Author: mav
Date: Sun Feb 14 12:30:35 2010
New Revision: 203873
URL: http://svn.freebsd.org/changeset/base/203873

Log:
  MFp4:
  With FBS enabled, we have no idea what command caused timeout.
  Implement same logic as in siis(4) - wait for other commands
  complete or timeout and then give some more time.

Modified:
  head/sys/dev/ahci/ahci.c
  head/sys/dev/ahci/ahci.h

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c    Sun Feb 14 12:30:30 2010        (r203872)
+++ head/sys/dev/ahci/ahci.c    Sun Feb 14 12:30:35 2010        (r203873)
@@ -1663,6 +1663,45 @@ ahci_execute_transaction(struct ahci_slo
        return;
 }
 
+/* Must be called with channel locked. */
+static void
+ahci_process_timeout(device_t dev)
+{
+       struct ahci_channel *ch = device_get_softc(dev);
+       int i;
+
+       mtx_assert(&ch->mtx, MA_OWNED);
+       /* Handle the rest of commands. */
+       for (i = 0; i < ch->numslots; i++) {
+               /* Do we have a running request on slot? */
+               if (ch->slot[i].state < AHCI_SLOT_RUNNING)
+                       continue;
+               ahci_end_transaction(&ch->slot[i], AHCI_ERR_TIMEOUT);
+       }
+}
+
+/* Must be called with channel locked. */
+static void
+ahci_rearm_timeout(device_t dev)
+{
+       struct ahci_channel *ch = device_get_softc(dev);
+       int i;
+
+       mtx_assert(&ch->mtx, MA_OWNED);
+       for (i = 0; i < ch->numslots; i++) {
+               struct ahci_slot *slot = &ch->slot[i];
+
+               /* Do we have a running request on slot? */
+               if (slot->state < AHCI_SLOT_RUNNING)
+                       continue;
+               if ((ch->toslots & (1 << i)) == 0)
+                       continue;
+               callout_reset(&slot->timeout,
+                   (int)slot->ccb->ccb_h.timeout * hz / 2000,
+                   (timeout_t*)ahci_timeout, slot);
+       }
+}
+
 /* Locked by callout mechanism. */
 static void
 ahci_timeout(struct ahci_slot *slot)
@@ -1699,7 +1738,6 @@ ahci_timeout(struct ahci_slot *slot)
            ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots,
            ATA_INL(ch->r_mem, AHCI_P_TFD), ATA_INL(ch->r_mem, AHCI_P_SERR));
 
-       ch->fatalerr = 1;
        /* Handle frozen command. */
        if (ch->frozen) {
                union ccb *fccb = ch->frozen;
@@ -1711,14 +1749,28 @@ ahci_timeout(struct ahci_slot *slot)
                }
                xpt_done(fccb);
        }
-       /* Handle command with timeout. */
-       ahci_end_transaction(&ch->slot[slot->slot], AHCI_ERR_TIMEOUT);
-       /* Handle the rest of commands. */
-       for (i = 0; i < ch->numslots; i++) {
-               /* Do we have a running request on slot? */
-               if (ch->slot[i].state < AHCI_SLOT_RUNNING)
-                       continue;
-               ahci_end_transaction(&ch->slot[i], AHCI_ERR_INNOCENT);
+       if (!ch->fbs_enabled) {
+               /* Without FBS we know real timeout source. */
+               ch->fatalerr = 1;
+               /* Handle command with timeout. */
+               ahci_end_transaction(&ch->slot[slot->slot], AHCI_ERR_TIMEOUT);
+               /* Handle the rest of commands. */
+               for (i = 0; i < ch->numslots; i++) {
+                       /* Do we have a running request on slot? */
+                       if (ch->slot[i].state < AHCI_SLOT_RUNNING)
+                               continue;
+                       ahci_end_transaction(&ch->slot[i], AHCI_ERR_INNOCENT);
+               }
+       } else {
+               /* With FBS we wait for other commands timeout and pray. */
+               if (ch->toslots == 0)
+                       xpt_freeze_simq(ch->sim, 1);
+               ch->toslots |= (1 << slot->slot);
+               if ((ch->rslots & ~ch->toslots) == 0)
+                       ahci_process_timeout(dev);
+               else
+                       device_printf(dev, " ... waiting for slots %08x\n",
+                           ch->rslots & ~ch->toslots);
        }
 }
 
@@ -1815,10 +1867,6 @@ ahci_end_transaction(struct ahci_slot *s
                ccb->ccb_h.status |= CAM_UNCOR_PARITY;
                break;
        case AHCI_ERR_TIMEOUT:
-               /* Do no treat soft-reset timeout as fatal here. */
-               if (ccb->ccb_h.func_code != XPT_ATA_IO ||
-                   !(ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL))
-                       ch->fatalerr = 1;
                if (!ch->readlog) {
                        xpt_freeze_simq(ch->sim, 1);
                        ccb->ccb_h.status &= ~CAM_STATUS_MASK;
@@ -1834,6 +1882,11 @@ ahci_end_transaction(struct ahci_slot *s
        ch->oslots &= ~(1 << slot->slot);
        ch->rslots &= ~(1 << slot->slot);
        ch->aslots &= ~(1 << slot->slot);
+       if (et != AHCI_ERR_TIMEOUT) {
+               if (ch->toslots == (1 << slot->slot))
+                       xpt_release_simq(ch->sim, TRUE);
+               ch->toslots &= ~(1 << slot->slot);
+       }
        slot->state = AHCI_SLOT_EMPTY;
        slot->ccb = NULL;
        /* Update channel stats. */
@@ -1873,7 +1926,7 @@ ahci_end_transaction(struct ahci_slot *s
        /* If we have no other active commands, ... */
        if (ch->rslots == 0) {
                /* if there was fatal error - reset port. */
-               if (ch->fatalerr) {
+               if (ch->toslots != 0 || ch->fatalerr) {
                        ahci_reset(dev);
                } else {
                        /* if we have slots in error, we can reinit port. */
@@ -1885,7 +1938,10 @@ ahci_end_transaction(struct ahci_slot *s
                        if (!ch->readlog && ch->numhslots)
                                ahci_issue_read_log(dev);
                }
-       }
+       /* If all the rest of commands are in timeout - give them chance. */
+       } else if ((ch->rslots & ~ch->toslots) == 0 &&
+           et != AHCI_ERR_TIMEOUT)
+               ahci_rearm_timeout(dev);
        /* Start PM timer. */
        if (ch->numrslots == 0 && ch->pm_level > 3) {
                callout_schedule(&ch->pm_timer,
@@ -2149,7 +2205,10 @@ ahci_reset(device_t dev)
                ch->hold[i] = NULL;
                ch->numhslots--;
        }
+       if (ch->toslots != 0)
+               xpt_release_simq(ch->sim, TRUE);
        ch->eslots = 0;
+       ch->toslots = 0;
        ch->fatalerr = 0;
        /* Tell the XPT about the event */
        xpt_async(AC_BUS_RESET, ch->path, NULL);

Modified: head/sys/dev/ahci/ahci.h
==============================================================================
--- head/sys/dev/ahci/ahci.h    Sun Feb 14 12:30:30 2010        (r203872)
+++ head/sys/dev/ahci/ahci.h    Sun Feb 14 12:30:35 2010        (r203873)
@@ -401,6 +401,7 @@ struct ahci_channel {
        uint32_t                rslots;         /* Running slots */
        uint32_t                aslots;         /* Slots with atomic commands  
*/
        uint32_t                eslots;         /* Slots in error */
+       uint32_t                toslots;        /* Slots in timeout */
        int                     numrslots;      /* Number of running slots */
        int                     numrslotspd[16];/* Number of running slots per 
dev */
        int                     numtslots;      /* Number of tagged slots */
_______________________________________________
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