diff options
author | Jeff Garzik <jeff@garzik.org> | 2007-08-03 11:10:07 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:30 -0400 |
commit | 640fdb504941fa2b9f6f274716fc9f97f2bf6bff (patch) | |
tree | 3e712ef4edacd3c1701aaad77ca2e2819b395053 /drivers/ata | |
parent | 782e3b3b3804c38d5130c7f21d7ec7bf6709023f (diff) |
[libata] pdc_adma: convert to new exception handling (EH) framework
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/pdc_adma.c | 82 |
1 files changed, 67 insertions, 15 deletions
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 5c79271401af..c95c1bf7df37 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c | |||
@@ -92,6 +92,8 @@ enum { | |||
92 | 92 | ||
93 | /* CPB bits */ | 93 | /* CPB bits */ |
94 | cDONE = (1 << 0), | 94 | cDONE = (1 << 0), |
95 | cATERR = (1 << 3), | ||
96 | |||
95 | cVLD = (1 << 0), | 97 | cVLD = (1 << 0), |
96 | cDAT = (1 << 2), | 98 | cDAT = (1 << 2), |
97 | cIEN = (1 << 3), | 99 | cIEN = (1 << 3), |
@@ -131,14 +133,15 @@ static int adma_ata_init_one (struct pci_dev *pdev, | |||
131 | static int adma_port_start(struct ata_port *ap); | 133 | static int adma_port_start(struct ata_port *ap); |
132 | static void adma_host_stop(struct ata_host *host); | 134 | static void adma_host_stop(struct ata_host *host); |
133 | static void adma_port_stop(struct ata_port *ap); | 135 | static void adma_port_stop(struct ata_port *ap); |
134 | static void adma_phy_reset(struct ata_port *ap); | ||
135 | static void adma_qc_prep(struct ata_queued_cmd *qc); | 136 | static void adma_qc_prep(struct ata_queued_cmd *qc); |
136 | static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); | 137 | static unsigned int adma_qc_issue(struct ata_queued_cmd *qc); |
137 | static int adma_check_atapi_dma(struct ata_queued_cmd *qc); | 138 | static int adma_check_atapi_dma(struct ata_queued_cmd *qc); |
138 | static void adma_bmdma_stop(struct ata_queued_cmd *qc); | 139 | static void adma_bmdma_stop(struct ata_queued_cmd *qc); |
139 | static u8 adma_bmdma_status(struct ata_port *ap); | 140 | static u8 adma_bmdma_status(struct ata_port *ap); |
140 | static void adma_irq_clear(struct ata_port *ap); | 141 | static void adma_irq_clear(struct ata_port *ap); |
141 | static void adma_eng_timeout(struct ata_port *ap); | 142 | static void adma_freeze(struct ata_port *ap); |
143 | static void adma_thaw(struct ata_port *ap); | ||
144 | static void adma_error_handler(struct ata_port *ap); | ||
142 | 145 | ||
143 | static struct scsi_host_template adma_ata_sht = { | 146 | static struct scsi_host_template adma_ata_sht = { |
144 | .module = THIS_MODULE, | 147 | .module = THIS_MODULE, |
@@ -165,12 +168,13 @@ static const struct ata_port_operations adma_ata_ops = { | |||
165 | .exec_command = ata_exec_command, | 168 | .exec_command = ata_exec_command, |
166 | .check_status = ata_check_status, | 169 | .check_status = ata_check_status, |
167 | .dev_select = ata_std_dev_select, | 170 | .dev_select = ata_std_dev_select, |
168 | .phy_reset = adma_phy_reset, | ||
169 | .check_atapi_dma = adma_check_atapi_dma, | 171 | .check_atapi_dma = adma_check_atapi_dma, |
170 | .data_xfer = ata_data_xfer, | 172 | .data_xfer = ata_data_xfer, |
171 | .qc_prep = adma_qc_prep, | 173 | .qc_prep = adma_qc_prep, |
172 | .qc_issue = adma_qc_issue, | 174 | .qc_issue = adma_qc_issue, |
173 | .eng_timeout = adma_eng_timeout, | 175 | .freeze = adma_freeze, |
176 | .thaw = adma_thaw, | ||
177 | .error_handler = adma_error_handler, | ||
174 | .irq_clear = adma_irq_clear, | 178 | .irq_clear = adma_irq_clear, |
175 | .irq_on = ata_irq_on, | 179 | .irq_on = ata_irq_on, |
176 | .irq_ack = ata_irq_ack, | 180 | .irq_ack = ata_irq_ack, |
@@ -184,7 +188,7 @@ static const struct ata_port_operations adma_ata_ops = { | |||
184 | static struct ata_port_info adma_port_info[] = { | 188 | static struct ata_port_info adma_port_info[] = { |
185 | /* board_1841_idx */ | 189 | /* board_1841_idx */ |
186 | { | 190 | { |
187 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | | 191 | .flags = ATA_FLAG_SLAVE_POSS | |
188 | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | | 192 | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | |
189 | ATA_FLAG_PIO_POLLING, | 193 | ATA_FLAG_PIO_POLLING, |
190 | .pio_mask = 0x10, /* pio4 */ | 194 | .pio_mask = 0x10, /* pio4 */ |
@@ -273,24 +277,41 @@ static inline void adma_enter_reg_mode(struct ata_port *ap) | |||
273 | readb(chan + ADMA_STATUS); /* flush */ | 277 | readb(chan + ADMA_STATUS); /* flush */ |
274 | } | 278 | } |
275 | 279 | ||
276 | static void adma_phy_reset(struct ata_port *ap) | 280 | static void adma_freeze(struct ata_port *ap) |
277 | { | 281 | { |
278 | struct adma_port_priv *pp = ap->private_data; | 282 | void __iomem *chan = ADMA_PORT_REGS(ap); |
283 | |||
284 | /* mask/clear ATA interrupts */ | ||
285 | writeb(ATA_NIEN, ap->ioaddr.ctl_addr); | ||
286 | ata_check_status(ap); | ||
287 | |||
288 | /* reset ADMA to idle state */ | ||
289 | writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL); | ||
290 | udelay(2); | ||
291 | writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL); | ||
292 | udelay(2); | ||
293 | } | ||
279 | 294 | ||
280 | pp->state = adma_state_idle; | 295 | static void adma_thaw(struct ata_port *ap) |
296 | { | ||
281 | adma_reinit_engine(ap); | 297 | adma_reinit_engine(ap); |
282 | ata_port_probe(ap); | ||
283 | ata_bus_reset(ap); | ||
284 | } | 298 | } |
285 | 299 | ||
286 | static void adma_eng_timeout(struct ata_port *ap) | 300 | static int adma_prereset(struct ata_port *ap, unsigned long deadline) |
287 | { | 301 | { |
288 | struct adma_port_priv *pp = ap->private_data; | 302 | struct adma_port_priv *pp = ap->private_data; |
289 | 303 | ||
290 | if (pp->state != adma_state_idle) /* healthy paranoia */ | 304 | if (pp->state != adma_state_idle) /* healthy paranoia */ |
291 | pp->state = adma_state_mmio; | 305 | pp->state = adma_state_mmio; |
292 | adma_reinit_engine(ap); | 306 | adma_reinit_engine(ap); |
293 | ata_eng_timeout(ap); | 307 | |
308 | return ata_std_prereset(ap, deadline); | ||
309 | } | ||
310 | |||
311 | static void adma_error_handler(struct ata_port *ap) | ||
312 | { | ||
313 | ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL, | ||
314 | ata_std_postreset); | ||
294 | } | 315 | } |
295 | 316 | ||
296 | static int adma_fill_sg(struct ata_queued_cmd *qc) | 317 | static int adma_fill_sg(struct ata_queued_cmd *qc) |
@@ -466,12 +487,31 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host) | |||
466 | continue; | 487 | continue; |
467 | qc = ata_qc_from_tag(ap, ap->active_tag); | 488 | qc = ata_qc_from_tag(ap, ap->active_tag); |
468 | if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { | 489 | if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { |
469 | if ((status & (aPERR | aPSD | aUIRQ))) | 490 | if (status & aPERR) |
491 | qc->err_mask |= AC_ERR_HOST_BUS; | ||
492 | else if ((status & (aPSD | aUIRQ))) | ||
470 | qc->err_mask |= AC_ERR_OTHER; | 493 | qc->err_mask |= AC_ERR_OTHER; |
494 | |||
495 | if (pp->pkt[0] & cATERR) | ||
496 | qc->err_mask |= AC_ERR_DEV; | ||
471 | else if (pp->pkt[0] != cDONE) | 497 | else if (pp->pkt[0] != cDONE) |
472 | qc->err_mask |= AC_ERR_OTHER; | 498 | qc->err_mask |= AC_ERR_OTHER; |
473 | 499 | ||
474 | ata_qc_complete(qc); | 500 | if (!qc->err_mask) |
501 | ata_qc_complete(qc); | ||
502 | else { | ||
503 | struct ata_eh_info *ehi = &ap->eh_info; | ||
504 | ata_ehi_clear_desc(ehi); | ||
505 | ata_ehi_push_desc(ehi, | ||
506 | "ADMA-status 0x%02X", status); | ||
507 | ata_ehi_push_desc(ehi, | ||
508 | "pkt[0] 0x%02X", pp->pkt[0]); | ||
509 | |||
510 | if (qc->err_mask == AC_ERR_DEV) | ||
511 | ata_port_abort(ap); | ||
512 | else | ||
513 | ata_port_freeze(ap); | ||
514 | } | ||
475 | } | 515 | } |
476 | } | 516 | } |
477 | return handled; | 517 | return handled; |
@@ -502,7 +542,19 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) | |||
502 | /* complete taskfile transaction */ | 542 | /* complete taskfile transaction */ |
503 | pp->state = adma_state_idle; | 543 | pp->state = adma_state_idle; |
504 | qc->err_mask |= ac_err_mask(status); | 544 | qc->err_mask |= ac_err_mask(status); |
505 | ata_qc_complete(qc); | 545 | if (!qc->err_mask) |
546 | ata_qc_complete(qc); | ||
547 | else { | ||
548 | struct ata_eh_info *ehi = &ap->eh_info; | ||
549 | ata_ehi_clear_desc(ehi); | ||
550 | ata_ehi_push_desc(ehi, | ||
551 | "status 0x%02X", status); | ||
552 | |||
553 | if (qc->err_mask == AC_ERR_DEV) | ||
554 | ata_port_abort(ap); | ||
555 | else | ||
556 | ata_port_freeze(ap); | ||
557 | } | ||
506 | handled = 1; | 558 | handled = 1; |
507 | } | 559 | } |
508 | } | 560 | } |