From c408a8b3d9268245f7f2af65399dd3f6d464d2a6 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 13 Jun 2009 23:07:00 -0700 Subject: [PATCH] AHCI - Bug fixes - primary port probe and TFD flushing. * The primary port probe was skipping the software reset step. * ahci_flush_tfd() was looping on the SERR.DIAG.X bit with a 10ms delay, but on some parts this bit gets re-set very quickly if the port is in a COMRESET state. Remove the loop, just use an if() instead. Reported-by: Sepherosa Ziehau --- sys/dev/disk/ahci/ahci.c | 17 +++++++---------- sys/dev/disk/ahci/ahci_cam.c | 5 ++++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sys/dev/disk/ahci/ahci.c b/sys/dev/disk/ahci/ahci.c index b565d4fa35..2e6a65a94c 100644 --- a/sys/dev/disk/ahci/ahci.c +++ b/sys/dev/disk/ahci/ahci.c @@ -584,7 +584,7 @@ ahci_port_state_machine(struct ahci_port *ap, int initial) * during the initial parallel probe and the port's probe state * will not get past ATA_PROBE_NEED_IDENT. */ - if (ap->ap_type == ATA_PORT_T_NONE) { + { if (initial == 0 && ap->ap_probe <= ATA_PROBE_NEED_HARD_RESET) { kprintf("%s: Waiting 10 seconds on insertion\n", PORTNAME(ap)); @@ -1314,6 +1314,8 @@ ahci_port_hardreset(struct ahci_port *ap, int hard) error = ENODEV; } + ahci_flush_tfd(ap); + /* * Wait for the device to become ready. * @@ -1713,11 +1715,9 @@ ahci_port_hardstop(struct ahci_port *ap) } /* - * Multiple events may have built up in the TFD. The spec is not very - * clear on this but it does seem to serialize events so clearing DIAG_X - * just once might not do the job during a reset sequence. - * - * XXX this probably isn't right. + * We can't loop on the X bit, a continuous COMINIT received will make + * it loop forever. Just assume one event has built up and clear X + * so the task file descriptor can update. */ void ahci_flush_tfd(struct ahci_port *ap) @@ -1725,11 +1725,8 @@ ahci_flush_tfd(struct ahci_port *ap) u_int32_t r; r = ahci_pread(ap, AHCI_PREG_SERR); - while (r & AHCI_PREG_SERR_DIAG_X) { + if (r & AHCI_PREG_SERR_DIAG_X) ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_X); - ahci_os_sleep(1); - r = ahci_pread(ap, AHCI_PREG_SERR); - } } /* diff --git a/sys/dev/disk/ahci/ahci_cam.c b/sys/dev/disk/ahci/ahci_cam.c index a61b57efaf..82301e4183 100644 --- a/sys/dev/disk/ahci/ahci_cam.c +++ b/sys/dev/disk/ahci/ahci_cam.c @@ -151,7 +151,10 @@ ahci_cam_attach(struct ahci_port *ap) } ap->ap_flags |= AP_F_BUS_REGISTERED; - error = ahci_cam_probe(ap, NULL); + if (ap->ap_probe == ATA_PROBE_NEED_IDENT) + error = ahci_cam_probe(ap, NULL); + else + error = 0; if (error) { ahci_cam_detach(ap); return (EIO); -- 2.41.0