Author: mav
Date: Sat May 11 13:21:31 2013
New Revision: 250508
URL: http://svnweb.freebsd.org/changeset/base/250508

Log:
  Disable sending Early R_OK on SiI3726/SiI3826 port multipliers.
  With "cached read" HDD testing and multiple ports busy on a SATA
  host controller, 3726/3826 PMP will very rarely drop a deferred
  R_OK that was intended for the host. Symptom will be all 5 drives
  under test will timeout, get reset, and recover.
  
  Submitted by: Rich Futyma <rich.fut...@sanmina.com>
  MFC after:    2 weeks

Modified:
  head/sys/cam/ata/ata_pmp.c

Modified: head/sys/cam/ata/ata_pmp.c
==============================================================================
--- head/sys/cam/ata/ata_pmp.c  Sat May 11 12:43:26 2013        (r250507)
+++ head/sys/cam/ata/ata_pmp.c  Sat May 11 13:21:31 2013        (r250508)
@@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$");
 typedef enum {
        PMP_STATE_NORMAL,
        PMP_STATE_PORTS,
+       PMP_STATE_PM_QUIRKS_1,
+       PMP_STATE_PM_QUIRKS_2,
+       PMP_STATE_PM_QUIRKS_3,
        PMP_STATE_PRECONFIG,
        PMP_STATE_RESET,
        PMP_STATE_CONNECT,
@@ -317,7 +320,11 @@ pmpasync(void *callback_arg, u_int32_t c
                if (code == AC_SENT_BDR || code == AC_BUS_RESET)
                        softc->found = 0; /* We have to reset everything. */
                if (softc->state == PMP_STATE_NORMAL) {
-                       softc->state = PMP_STATE_PRECONFIG;
+                       if (softc->pm_pid == 0x37261095 ||
+                           softc->pm_pid == 0x38261095)
+                               softc->state = PMP_STATE_PM_QUIRKS_1;
+                       else
+                               softc->state = PMP_STATE_PRECONFIG;
                        cam_periph_acquire(periph);
                        xpt_schedule(periph, CAM_PRIORITY_DEV);
                } else
@@ -427,7 +434,10 @@ pmpstart(struct cam_periph *periph, unio
 
        if (softc->restart) {
                softc->restart = 0;
-               softc->state = min(softc->state, PMP_STATE_PRECONFIG);
+               if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
+                       softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1);
+               else
+                       softc->state = min(softc->state, PMP_STATE_PRECONFIG);
        }
        /* Fetch user wanted device speed. */
        if (softc->state == PMP_STATE_RESET ||
@@ -457,6 +467,32 @@ pmpstart(struct cam_periph *periph, unio
                      pmp_default_timeout * 1000);
                ata_pm_read_cmd(ataio, 2, 15);
                break;
+
+       case PMP_STATE_PM_QUIRKS_1:
+       case PMP_STATE_PM_QUIRKS_3:
+               cam_fill_ataio(ataio,
+                     pmp_retry_count,
+                     pmpdone,
+                     /*flags*/CAM_DIR_NONE,
+                     0,
+                     /*data_ptr*/NULL,
+                     /*dxfer_len*/0,
+                     pmp_default_timeout * 1000);
+               ata_pm_read_cmd(ataio, 129, 15);
+               break;
+
+       case PMP_STATE_PM_QUIRKS_2:
+               cam_fill_ataio(ataio,
+                     pmp_retry_count,
+                     pmpdone,
+                     /*flags*/CAM_DIR_NONE,
+                     0,
+                     /*data_ptr*/NULL,
+                     /*dxfer_len*/0,
+                     pmp_default_timeout * 1000);
+               ata_pm_write_cmd(ataio, 129, 15, softc->caps & ~0x1);
+               break;
+
        case PMP_STATE_PRECONFIG:
                /* Get/update host SATA capabilities. */
                bzero(&cts, sizeof(cts));
@@ -466,6 +502,8 @@ pmpstart(struct cam_periph *periph, unio
                xpt_action((union ccb *)&cts);
                if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
                        softc->caps = cts.xport_specific.sata.caps;
+               else
+                       softc->caps = 0;
                cam_fill_ataio(ataio,
                      pmp_retry_count,
                      pmpdone,
@@ -575,7 +613,10 @@ pmpdone(struct cam_periph *periph, union
        if (softc->restart) {
                softc->restart = 0;
                xpt_release_ccb(done_ccb);
-               softc->state = min(softc->state, PMP_STATE_PRECONFIG);
+               if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
+                       softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1);
+               else
+                       softc->state = min(softc->state, PMP_STATE_PRECONFIG);
                xpt_schedule(periph, priority);
                return;
        }
@@ -618,10 +659,48 @@ pmpdone(struct cam_periph *periph, union
                printf("%s%d: %d fan-out ports\n",
                    periph->periph_name, periph->unit_number,
                    softc->pm_ports);
+               if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
+                       softc->state = PMP_STATE_PM_QUIRKS_1;
+               else
+                       softc->state = PMP_STATE_PRECONFIG;
+               xpt_release_ccb(done_ccb);
+               xpt_schedule(periph, priority);
+               return;
+
+       case PMP_STATE_PM_QUIRKS_1:
+               softc->caps = (ataio->res.lba_high << 24) +
+                   (ataio->res.lba_mid << 16) +
+                   (ataio->res.lba_low << 8) +
+                   ataio->res.sector_count;
+               if (softc->caps & 0x1)
+                       softc->state = PMP_STATE_PM_QUIRKS_2;
+               else
+                       softc->state = PMP_STATE_PRECONFIG;
+               xpt_release_ccb(done_ccb);
+               xpt_schedule(periph, priority);
+               return;
+
+       case PMP_STATE_PM_QUIRKS_2:
+               if (bootverbose)
+                       softc->state = PMP_STATE_PM_QUIRKS_3;
+               else
+                       softc->state = PMP_STATE_PRECONFIG;
+               xpt_release_ccb(done_ccb);
+               xpt_schedule(periph, priority);
+               return;
+
+       case PMP_STATE_PM_QUIRKS_3:
+               res = (ataio->res.lba_high << 24) +
+                   (ataio->res.lba_mid << 16) +
+                   (ataio->res.lba_low << 8) +
+                   ataio->res.sector_count;
+               printf("%s%d: Disabling SiI3x26 R_OK in GSCR_POLL: %x->%x\n",
+                   periph->periph_name, periph->unit_number, softc->caps, res);
                softc->state = PMP_STATE_PRECONFIG;
                xpt_release_ccb(done_ccb);
                xpt_schedule(periph, priority);
                return;
+
        case PMP_STATE_PRECONFIG:
                softc->pm_step = 0;
                softc->state = PMP_STATE_RESET;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to