diff options
author | Tejun Heo <htejun@gmail.com> | 2006-05-15 08:03:43 -0400 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-05-15 08:03:43 -0400 |
commit | dedaf2b0365ccec50714fbde0b3215e7e94fa47c (patch) | |
tree | d98e2a928793e6072d4ff65b0e2ceedaa600e25d | |
parent | 6cec4a3943bdfe46e2952bc246f17670f747be8d (diff) |
[PATCH] libata-ncq: implement ap->qc_active, ap->sactive and complete helper
Add ap->qc_active and ap->sactive, mask of all active qcs and libata's
view of the SActive register, respectively. Also, implement
ata_qc_complete_multiple() which takes new qc_active mask and complete
multiple qcs according to the mask.
These will be used to track NCQ commands and complete them. The
distinction between ap->qc_active and ap->sactive is also useful for
later PM implementation.
Signed-off-by: Tejun Heo <htejun@gmail.com>
-rw-r--r-- | drivers/scsi/libata-core.c | 81 | ||||
-rw-r--r-- | include/linux/libata.h | 5 |
2 files changed, 84 insertions, 2 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f8401800dc1a..eea1fe9c8b79 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -981,6 +981,7 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
981 | u8 command = tf->command; | 981 | u8 command = tf->command; |
982 | struct ata_queued_cmd *qc; | 982 | struct ata_queued_cmd *qc; |
983 | unsigned int tag, preempted_tag; | 983 | unsigned int tag, preempted_tag; |
984 | u32 preempted_sactive, preempted_qc_active; | ||
984 | DECLARE_COMPLETION(wait); | 985 | DECLARE_COMPLETION(wait); |
985 | unsigned long flags; | 986 | unsigned long flags; |
986 | unsigned int err_mask; | 987 | unsigned int err_mask; |
@@ -1017,7 +1018,11 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
1017 | ata_qc_reinit(qc); | 1018 | ata_qc_reinit(qc); |
1018 | 1019 | ||
1019 | preempted_tag = ap->active_tag; | 1020 | preempted_tag = ap->active_tag; |
1021 | preempted_sactive = ap->sactive; | ||
1022 | preempted_qc_active = ap->qc_active; | ||
1020 | ap->active_tag = ATA_TAG_POISON; | 1023 | ap->active_tag = ATA_TAG_POISON; |
1024 | ap->sactive = 0; | ||
1025 | ap->qc_active = 0; | ||
1021 | 1026 | ||
1022 | /* prepare & issue qc */ | 1027 | /* prepare & issue qc */ |
1023 | qc->tf = *tf; | 1028 | qc->tf = *tf; |
@@ -1082,6 +1087,8 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
1082 | 1087 | ||
1083 | ata_qc_free(qc); | 1088 | ata_qc_free(qc); |
1084 | ap->active_tag = preempted_tag; | 1089 | ap->active_tag = preempted_tag; |
1090 | ap->sactive = preempted_sactive; | ||
1091 | ap->qc_active = preempted_qc_active; | ||
1085 | 1092 | ||
1086 | /* XXX - Some LLDDs (sata_mv) disable port on command failure. | 1093 | /* XXX - Some LLDDs (sata_mv) disable port on command failure. |
1087 | * Until those drivers are fixed, we detect the condition | 1094 | * Until those drivers are fixed, we detect the condition |
@@ -4270,6 +4277,8 @@ void ata_qc_free(struct ata_queued_cmd *qc) | |||
4270 | 4277 | ||
4271 | void __ata_qc_complete(struct ata_queued_cmd *qc) | 4278 | void __ata_qc_complete(struct ata_queued_cmd *qc) |
4272 | { | 4279 | { |
4280 | struct ata_port *ap = qc->ap; | ||
4281 | |||
4273 | WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ | 4282 | WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ |
4274 | WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); | 4283 | WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); |
4275 | 4284 | ||
@@ -4277,13 +4286,17 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) | |||
4277 | ata_sg_clean(qc); | 4286 | ata_sg_clean(qc); |
4278 | 4287 | ||
4279 | /* command should be marked inactive atomically with qc completion */ | 4288 | /* command should be marked inactive atomically with qc completion */ |
4280 | qc->ap->active_tag = ATA_TAG_POISON; | 4289 | if (qc->tf.protocol == ATA_PROT_NCQ) |
4290 | ap->sactive &= ~(1 << qc->tag); | ||
4291 | else | ||
4292 | ap->active_tag = ATA_TAG_POISON; | ||
4281 | 4293 | ||
4282 | /* atapi: mark qc as inactive to prevent the interrupt handler | 4294 | /* atapi: mark qc as inactive to prevent the interrupt handler |
4283 | * from completing the command twice later, before the error handler | 4295 | * from completing the command twice later, before the error handler |
4284 | * is called. (when rc != 0 and atapi request sense is needed) | 4296 | * is called. (when rc != 0 and atapi request sense is needed) |
4285 | */ | 4297 | */ |
4286 | qc->flags &= ~ATA_QCFLAG_ACTIVE; | 4298 | qc->flags &= ~ATA_QCFLAG_ACTIVE; |
4299 | ap->qc_active &= ~(1 << qc->tag); | ||
4287 | 4300 | ||
4288 | /* call completion callback */ | 4301 | /* call completion callback */ |
4289 | qc->complete_fn(qc); | 4302 | qc->complete_fn(qc); |
@@ -4349,6 +4362,55 @@ void ata_qc_complete(struct ata_queued_cmd *qc) | |||
4349 | } | 4362 | } |
4350 | } | 4363 | } |
4351 | 4364 | ||
4365 | /** | ||
4366 | * ata_qc_complete_multiple - Complete multiple qcs successfully | ||
4367 | * @ap: port in question | ||
4368 | * @qc_active: new qc_active mask | ||
4369 | * @finish_qc: LLDD callback invoked before completing a qc | ||
4370 | * | ||
4371 | * Complete in-flight commands. This functions is meant to be | ||
4372 | * called from low-level driver's interrupt routine to complete | ||
4373 | * requests normally. ap->qc_active and @qc_active is compared | ||
4374 | * and commands are completed accordingly. | ||
4375 | * | ||
4376 | * LOCKING: | ||
4377 | * spin_lock_irqsave(host_set lock) | ||
4378 | * | ||
4379 | * RETURNS: | ||
4380 | * Number of completed commands on success, -errno otherwise. | ||
4381 | */ | ||
4382 | int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, | ||
4383 | void (*finish_qc)(struct ata_queued_cmd *)) | ||
4384 | { | ||
4385 | int nr_done = 0; | ||
4386 | u32 done_mask; | ||
4387 | int i; | ||
4388 | |||
4389 | done_mask = ap->qc_active ^ qc_active; | ||
4390 | |||
4391 | if (unlikely(done_mask & qc_active)) { | ||
4392 | ata_port_printk(ap, KERN_ERR, "illegal qc_active transition " | ||
4393 | "(%08x->%08x)\n", ap->qc_active, qc_active); | ||
4394 | return -EINVAL; | ||
4395 | } | ||
4396 | |||
4397 | for (i = 0; i < ATA_MAX_QUEUE; i++) { | ||
4398 | struct ata_queued_cmd *qc; | ||
4399 | |||
4400 | if (!(done_mask & (1 << i))) | ||
4401 | continue; | ||
4402 | |||
4403 | if ((qc = ata_qc_from_tag(ap, i))) { | ||
4404 | if (finish_qc) | ||
4405 | finish_qc(qc); | ||
4406 | ata_qc_complete(qc); | ||
4407 | nr_done++; | ||
4408 | } | ||
4409 | } | ||
4410 | |||
4411 | return nr_done; | ||
4412 | } | ||
4413 | |||
4352 | static inline int ata_should_dma_map(struct ata_queued_cmd *qc) | 4414 | static inline int ata_should_dma_map(struct ata_queued_cmd *qc) |
4353 | { | 4415 | { |
4354 | struct ata_port *ap = qc->ap; | 4416 | struct ata_port *ap = qc->ap; |
@@ -4388,8 +4450,22 @@ void ata_qc_issue(struct ata_queued_cmd *qc) | |||
4388 | { | 4450 | { |
4389 | struct ata_port *ap = qc->ap; | 4451 | struct ata_port *ap = qc->ap; |
4390 | 4452 | ||
4391 | qc->ap->active_tag = qc->tag; | 4453 | /* Make sure only one non-NCQ command is outstanding. The |
4454 | * check is skipped for old EH because it reuses active qc to | ||
4455 | * request ATAPI sense. | ||
4456 | */ | ||
4457 | WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag)); | ||
4458 | |||
4459 | if (qc->tf.protocol == ATA_PROT_NCQ) { | ||
4460 | WARN_ON(ap->sactive & (1 << qc->tag)); | ||
4461 | ap->sactive |= 1 << qc->tag; | ||
4462 | } else { | ||
4463 | WARN_ON(ap->sactive); | ||
4464 | ap->active_tag = qc->tag; | ||
4465 | } | ||
4466 | |||
4392 | qc->flags |= ATA_QCFLAG_ACTIVE; | 4467 | qc->flags |= ATA_QCFLAG_ACTIVE; |
4468 | ap->qc_active |= 1 << qc->tag; | ||
4393 | 4469 | ||
4394 | if (ata_should_dma_map(qc)) { | 4470 | if (ata_should_dma_map(qc)) { |
4395 | if (qc->flags & ATA_QCFLAG_SG) { | 4471 | if (qc->flags & ATA_QCFLAG_SG) { |
@@ -5549,6 +5625,7 @@ EXPORT_SYMBOL_GPL(ata_host_set_remove); | |||
5549 | EXPORT_SYMBOL_GPL(ata_sg_init); | 5625 | EXPORT_SYMBOL_GPL(ata_sg_init); |
5550 | EXPORT_SYMBOL_GPL(ata_sg_init_one); | 5626 | EXPORT_SYMBOL_GPL(ata_sg_init_one); |
5551 | EXPORT_SYMBOL_GPL(ata_qc_complete); | 5627 | EXPORT_SYMBOL_GPL(ata_qc_complete); |
5628 | EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); | ||
5552 | EXPORT_SYMBOL_GPL(ata_qc_issue_prot); | 5629 | EXPORT_SYMBOL_GPL(ata_qc_issue_prot); |
5553 | EXPORT_SYMBOL_GPL(ata_tf_load); | 5630 | EXPORT_SYMBOL_GPL(ata_tf_load); |
5554 | EXPORT_SYMBOL_GPL(ata_tf_read); | 5631 | EXPORT_SYMBOL_GPL(ata_tf_read); |
diff --git a/include/linux/libata.h b/include/linux/libata.h index b3a4f8bea828..dd0db2d21bc5 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -475,7 +475,10 @@ struct ata_port { | |||
475 | 475 | ||
476 | struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; | 476 | struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; |
477 | unsigned long qc_allocated; | 477 | unsigned long qc_allocated; |
478 | unsigned int qc_active; | ||
479 | |||
478 | unsigned int active_tag; | 480 | unsigned int active_tag; |
481 | u32 sactive; | ||
479 | 482 | ||
480 | struct ata_host_stats stats; | 483 | struct ata_host_stats stats; |
481 | struct ata_host_set *host_set; | 484 | struct ata_host_set *host_set; |
@@ -668,6 +671,8 @@ extern void ata_bmdma_drive_eh(struct ata_port *ap, | |||
668 | extern void ata_bmdma_error_handler(struct ata_port *ap); | 671 | extern void ata_bmdma_error_handler(struct ata_port *ap); |
669 | extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); | 672 | extern void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc); |
670 | extern void ata_qc_complete(struct ata_queued_cmd *qc); | 673 | extern void ata_qc_complete(struct ata_queued_cmd *qc); |
674 | extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, | ||
675 | void (*finish_qc)(struct ata_queued_cmd *)); | ||
671 | extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, | 676 | extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, |
672 | void (*done)(struct scsi_cmnd *)); | 677 | void (*done)(struct scsi_cmnd *)); |
673 | extern int ata_std_bios_param(struct scsi_device *sdev, | 678 | extern int ata_std_bios_param(struct scsi_device *sdev, |