diff options
author | Tejun Heo <htejun@gmail.com> | 2007-09-23 00:14:12 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:41 -0400 |
commit | da917d69d0ea63f5390716cba6e77f490ce96df9 (patch) | |
tree | 214670f42be4c140bbd05226adc8f86db51ee725 | |
parent | 31cc23b34913bc173680bdc87af79e551bf8cc0d (diff) |
libata-pmp-prep: implement qc_defer helpers
Implement ap->nr_active_links (the number of links with active qcs),
ap->excl_link (pointer to link which can be used by ->qc_defer and is
cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and
ata_link_active().
These can be used by ->qc_defer() to implement proper command
exclusion. This set of helpers seem enough for both sil24 (ATAPI
exclusion needed) and cmd-switching PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/libata-core.c | 22 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 5 | ||||
-rw-r--r-- | include/linux/libata.h | 8 |
3 files changed, 33 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b666f51da7ed..376dbd80cc93 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -1390,6 +1390,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, | |||
1390 | struct ata_queued_cmd *qc; | 1390 | struct ata_queued_cmd *qc; |
1391 | unsigned int tag, preempted_tag; | 1391 | unsigned int tag, preempted_tag; |
1392 | u32 preempted_sactive, preempted_qc_active; | 1392 | u32 preempted_sactive, preempted_qc_active; |
1393 | int preempted_nr_active_links; | ||
1393 | DECLARE_COMPLETION_ONSTACK(wait); | 1394 | DECLARE_COMPLETION_ONSTACK(wait); |
1394 | unsigned long flags; | 1395 | unsigned long flags; |
1395 | unsigned int err_mask; | 1396 | unsigned int err_mask; |
@@ -1428,9 +1429,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, | |||
1428 | preempted_tag = link->active_tag; | 1429 | preempted_tag = link->active_tag; |
1429 | preempted_sactive = link->sactive; | 1430 | preempted_sactive = link->sactive; |
1430 | preempted_qc_active = ap->qc_active; | 1431 | preempted_qc_active = ap->qc_active; |
1432 | preempted_nr_active_links = ap->nr_active_links; | ||
1431 | link->active_tag = ATA_TAG_POISON; | 1433 | link->active_tag = ATA_TAG_POISON; |
1432 | link->sactive = 0; | 1434 | link->sactive = 0; |
1433 | ap->qc_active = 0; | 1435 | ap->qc_active = 0; |
1436 | ap->nr_active_links = 0; | ||
1434 | 1437 | ||
1435 | /* prepare & issue qc */ | 1438 | /* prepare & issue qc */ |
1436 | qc->tf = *tf; | 1439 | qc->tf = *tf; |
@@ -1509,6 +1512,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, | |||
1509 | link->active_tag = preempted_tag; | 1512 | link->active_tag = preempted_tag; |
1510 | link->sactive = preempted_sactive; | 1513 | link->sactive = preempted_sactive; |
1511 | ap->qc_active = preempted_qc_active; | 1514 | ap->qc_active = preempted_qc_active; |
1515 | ap->nr_active_links = preempted_nr_active_links; | ||
1512 | 1516 | ||
1513 | /* XXX - Some LLDDs (sata_mv) disable port on command failure. | 1517 | /* XXX - Some LLDDs (sata_mv) disable port on command failure. |
1514 | * Until those drivers are fixed, we detect the condition | 1518 | * Until those drivers are fixed, we detect the condition |
@@ -5408,10 +5412,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) | |||
5408 | ata_sg_clean(qc); | 5412 | ata_sg_clean(qc); |
5409 | 5413 | ||
5410 | /* command should be marked inactive atomically with qc completion */ | 5414 | /* command should be marked inactive atomically with qc completion */ |
5411 | if (qc->tf.protocol == ATA_PROT_NCQ) | 5415 | if (qc->tf.protocol == ATA_PROT_NCQ) { |
5412 | link->sactive &= ~(1 << qc->tag); | 5416 | link->sactive &= ~(1 << qc->tag); |
5413 | else | 5417 | if (!link->sactive) |
5418 | ap->nr_active_links--; | ||
5419 | } else { | ||
5414 | link->active_tag = ATA_TAG_POISON; | 5420 | link->active_tag = ATA_TAG_POISON; |
5421 | ap->nr_active_links--; | ||
5422 | } | ||
5423 | |||
5424 | /* clear exclusive status */ | ||
5425 | if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && | ||
5426 | ap->excl_link == link)) | ||
5427 | ap->excl_link = NULL; | ||
5415 | 5428 | ||
5416 | /* atapi: mark qc as inactive to prevent the interrupt handler | 5429 | /* atapi: mark qc as inactive to prevent the interrupt handler |
5417 | * from completing the command twice later, before the error handler | 5430 | * from completing the command twice later, before the error handler |
@@ -5590,9 +5603,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc) | |||
5590 | 5603 | ||
5591 | if (qc->tf.protocol == ATA_PROT_NCQ) { | 5604 | if (qc->tf.protocol == ATA_PROT_NCQ) { |
5592 | WARN_ON(link->sactive & (1 << qc->tag)); | 5605 | WARN_ON(link->sactive & (1 << qc->tag)); |
5606 | |||
5607 | if (!link->sactive) | ||
5608 | ap->nr_active_links++; | ||
5593 | link->sactive |= 1 << qc->tag; | 5609 | link->sactive |= 1 << qc->tag; |
5594 | } else { | 5610 | } else { |
5595 | WARN_ON(link->sactive); | 5611 | WARN_ON(link->sactive); |
5612 | |||
5613 | ap->nr_active_links++; | ||
5596 | link->active_tag = qc->tag; | 5614 | link->active_tag = qc->tag; |
5597 | } | 5615 | } |
5598 | 5616 | ||
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 1d3b0dccfb0a..5244723952c2 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -451,6 +451,7 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
451 | 451 | ||
452 | ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; | 452 | ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; |
453 | ap->pflags &= ~ATA_PFLAG_EH_PENDING; | 453 | ap->pflags &= ~ATA_PFLAG_EH_PENDING; |
454 | ap->excl_link = NULL; /* don't maintain exclusion over EH */ | ||
454 | 455 | ||
455 | spin_unlock_irqrestore(ap->lock, flags); | 456 | spin_unlock_irqrestore(ap->lock, flags); |
456 | 457 | ||
@@ -2474,6 +2475,10 @@ void ata_eh_finish(struct ata_port *ap) | |||
2474 | } | 2475 | } |
2475 | } | 2476 | } |
2476 | } | 2477 | } |
2478 | |||
2479 | /* make sure nr_active_links is zero after EH */ | ||
2480 | WARN_ON(ap->nr_active_links); | ||
2481 | ap->nr_active_links = 0; | ||
2477 | } | 2482 | } |
2478 | 2483 | ||
2479 | /** | 2484 | /** |
diff --git a/include/linux/libata.h b/include/linux/libata.h index b0d4ca0d27b4..f9f81fd93293 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -216,6 +216,7 @@ enum { | |||
216 | ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, | 216 | ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, |
217 | ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ | 217 | ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ |
218 | ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ | 218 | ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ |
219 | ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ | ||
219 | 220 | ||
220 | ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ | 221 | ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ |
221 | ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ | 222 | ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ |
@@ -579,11 +580,13 @@ struct ata_port { | |||
579 | struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; | 580 | struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; |
580 | unsigned long qc_allocated; | 581 | unsigned long qc_allocated; |
581 | unsigned int qc_active; | 582 | unsigned int qc_active; |
583 | int nr_active_links; /* #links with active qcs */ | ||
582 | 584 | ||
583 | struct ata_link link; /* host default link */ | 585 | struct ata_link link; /* host default link */ |
584 | 586 | ||
585 | int nr_pmp_links; /* nr of available PMP links */ | 587 | int nr_pmp_links; /* nr of available PMP links */ |
586 | struct ata_link *pmp_link; /* array of PMP links */ | 588 | struct ata_link *pmp_link; /* array of PMP links */ |
589 | struct ata_link *excl_link; /* for PMP qc exclusion */ | ||
587 | 590 | ||
588 | struct ata_port_stats stats; | 591 | struct ata_port_stats stats; |
589 | struct ata_host *host; | 592 | struct ata_host *host; |
@@ -1104,6 +1107,11 @@ static inline int ata_link_max_devices(const struct ata_link *link) | |||
1104 | return 1; | 1107 | return 1; |
1105 | } | 1108 | } |
1106 | 1109 | ||
1110 | static inline int ata_link_active(struct ata_link *link) | ||
1111 | { | ||
1112 | return ata_tag_valid(link->active_tag) || link->sactive; | ||
1113 | } | ||
1114 | |||
1107 | static inline struct ata_link *ata_port_first_link(struct ata_port *ap) | 1115 | static inline struct ata_link *ata_port_first_link(struct ata_port *ap) |
1108 | { | 1116 | { |
1109 | if (ap->nr_pmp_links) | 1117 | if (ap->nr_pmp_links) |