Author: mav
Date: Tue Apr 12 11:24:59 2011
New Revision: 220565
URL: http://svn.freebsd.org/changeset/base/220565

Log:
  Implement automatic SCSI sense fetching for ahci(4).

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    Tue Apr 12 11:17:46 2011        (r220564)
+++ head/sys/dev/ahci/ahci.c    Tue Apr 12 11:24:59 2011        (r220565)
@@ -91,8 +91,9 @@ static int ahci_sata_connect(struct ahci
 static int ahci_sata_phy_reset(device_t dev);
 static int ahci_wait_ready(device_t dev, int t);
 
-static void ahci_issue_read_log(device_t dev);
+static void ahci_issue_recovery(device_t dev);
 static void ahci_process_read_log(device_t dev, union ccb *ccb);
+static void ahci_process_request_sense(device_t dev, union ccb *ccb);
 
 static void ahciaction(struct cam_sim *sim, union ccb *ccb);
 static void ahcipoll(struct cam_sim *sim);
@@ -267,6 +268,12 @@ static struct {
        {0x00000000, 0x00, NULL,                0}
 };
 
+#define recovery_type          spriv_field0
+#define RECOVERY_NONE          0
+#define RECOVERY_READ_LOG      1
+#define RECOVERY_REQUEST_SENSE 2
+#define recovery_slot          spriv_field1
+
 static int
 ahci_probe(device_t dev)
 {
@@ -1465,7 +1472,7 @@ ahci_ch_intr(void *data)
                 * We can't reinit port if there are some other
                 * commands active, use resume to complete them.
                 */
-               if (ch->rslots != 0) 
+               if (ch->rslots != 0 && !ch->recoverycmd)
                        ATA_OUTL(ch->r_mem, AHCI_P_FBS, AHCI_P_FBS_EN | 
AHCI_P_FBS_DEC);
        }
        /* Process NOTIFY events */
@@ -1937,7 +1944,7 @@ ahci_end_transaction(struct ahci_slot *s
        if (et != AHCI_ERR_NONE)
                ch->eslots |= (1 << slot->slot);
        /* In case of error, freeze device for proper recovery. */
-       if ((et != AHCI_ERR_NONE) && (!ch->readlog) &&
+       if ((et != AHCI_ERR_NONE) && (!ch->recoverycmd) &&
            !(ccb->ccb_h.status & CAM_DEV_QFRZN)) {
                xpt_freeze_devq(ccb->ccb_h.path, 1);
                ccb->ccb_h.status |= CAM_DEV_QFRZN;
@@ -1968,7 +1975,7 @@ ahci_end_transaction(struct ahci_slot *s
                break;
        case AHCI_ERR_SATA:
                ch->fatalerr = 1;
-               if (!ch->readlog) {
+               if (!ch->recoverycmd) {
                        xpt_freeze_simq(ch->sim, 1);
                        ccb->ccb_h.status &= ~CAM_STATUS_MASK;
                        ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
@@ -1976,7 +1983,7 @@ ahci_end_transaction(struct ahci_slot *s
                ccb->ccb_h.status |= CAM_UNCOR_PARITY;
                break;
        case AHCI_ERR_TIMEOUT:
-               if (!ch->readlog) {
+               if (!ch->recoverycmd) {
                        xpt_freeze_simq(ch->sim, 1);
                        ccb->ccb_h.status &= ~CAM_STATUS_MASK;
                        ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
@@ -2019,10 +2026,15 @@ ahci_end_transaction(struct ahci_slot *s
                return;
        }
        /* If it was our READ LOG command - process it. */
-       if (ch->readlog) {
+       if (ccb->ccb_h.recovery_type == RECOVERY_READ_LOG) {
                ahci_process_read_log(dev, ccb);
-       /* If it was NCQ command error, put result on hold. */
-       } else if (et == AHCI_ERR_NCQ) {
+       /* If it was our REQUEST SENSE command - process it. */
+       } else if (ccb->ccb_h.recovery_type == RECOVERY_REQUEST_SENSE) {
+               ahci_process_request_sense(dev, ccb);
+       /* If it was NCQ or ATAPI command error, put result on hold. */
+       } else if (et == AHCI_ERR_NCQ ||
+           ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
+            (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)) {
                ch->hold[slot->slot] = ccb;
                ch->numhslots++;
        } else
@@ -2046,8 +2058,8 @@ ahci_end_transaction(struct ahci_slot *s
                                ahci_start(dev, 1);
                        }
                        /* if there commands on hold, we can do READ LOG. */
-                       if (!ch->readlog && ch->numhslots)
-                               ahci_issue_read_log(dev);
+                       if (!ch->recoverycmd && ch->numhslots)
+                               ahci_issue_recovery(dev);
                }
        /* If all the rest of commands are in timeout - give them chance. */
        } else if ((ch->rslots & ~ch->toslots) == 0 &&
@@ -2062,14 +2074,15 @@ ahci_end_transaction(struct ahci_slot *s
 }
 
 static void
-ahci_issue_read_log(device_t dev)
+ahci_issue_recovery(device_t dev)
 {
        struct ahci_channel *ch = device_get_softc(dev);
        union ccb *ccb;
        struct ccb_ataio *ataio;
+       struct ccb_scsiio *csio;
        int i;
 
-       ch->readlog = 1;
+       ch->recoverycmd = 1;
        /* Find some holden command. */
        for (i = 0; i < ch->numslots; i++) {
                if (ch->hold[i])
@@ -2081,26 +2094,45 @@ ahci_issue_read_log(device_t dev)
                return; /* XXX */
        }
        ccb->ccb_h = ch->hold[i]->ccb_h;        /* Reuse old header. */
-       ccb->ccb_h.func_code = XPT_ATA_IO;
-       ccb->ccb_h.flags = CAM_DIR_IN;
-       ccb->ccb_h.timeout = 1000;      /* 1s should be enough. */
-       ataio = &ccb->ataio;
-       ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
-       if (ataio->data_ptr == NULL) {
-               xpt_free_ccb(ccb);
-               device_printf(dev, "Unable allocate memory for READ LOG 
command");
-               return; /* XXX */
+       if (ccb->ccb_h.func_code == XPT_ATA_IO) {
+               /* READ LOG */
+               ccb->ccb_h.recovery_type = RECOVERY_READ_LOG;
+               ccb->ccb_h.func_code = XPT_ATA_IO;
+               ccb->ccb_h.flags = CAM_DIR_IN;
+               ccb->ccb_h.timeout = 1000;      /* 1s should be enough. */
+               ataio = &ccb->ataio;
+               ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
+               if (ataio->data_ptr == NULL) {
+                       xpt_free_ccb(ccb);
+                       device_printf(dev, "Unable allocate memory for READ LOG 
command");
+                       return; /* XXX */
+               }
+               ataio->dxfer_len = 512;
+               bzero(&ataio->cmd, sizeof(ataio->cmd));
+               ataio->cmd.flags = CAM_ATAIO_48BIT;
+               ataio->cmd.command = 0x2F;      /* READ LOG EXT */
+               ataio->cmd.sector_count = 1;
+               ataio->cmd.sector_count_exp = 0;
+               ataio->cmd.lba_low = 0x10;
+               ataio->cmd.lba_mid = 0;
+               ataio->cmd.lba_mid_exp = 0;
+       } else {
+               /* REQUEST SENSE */
+               ccb->ccb_h.recovery_type = RECOVERY_REQUEST_SENSE;
+               ccb->ccb_h.recovery_slot = i;
+               ccb->ccb_h.func_code = XPT_SCSI_IO;
+               ccb->ccb_h.flags = CAM_DIR_IN;
+               ccb->ccb_h.status = 0;
+               ccb->ccb_h.timeout = 1000;      /* 1s should be enough. */
+               csio = &ccb->csio;
+               csio->data_ptr = (void *)&ch->hold[i]->csio.sense_data;
+               csio->dxfer_len = ch->hold[i]->csio.sense_len;
+               csio->cdb_len = 6;
+               bzero(&csio->cdb_io, sizeof(csio->cdb_io));
+               csio->cdb_io.cdb_bytes[0] = 0x03;
+               csio->cdb_io.cdb_bytes[4] = csio->dxfer_len;
        }
-       ataio->dxfer_len = 512;
-       bzero(&ataio->cmd, sizeof(ataio->cmd));
-       ataio->cmd.flags = CAM_ATAIO_48BIT;
-       ataio->cmd.command = 0x2F;      /* READ LOG EXT */
-       ataio->cmd.sector_count = 1;
-       ataio->cmd.sector_count_exp = 0;
-       ataio->cmd.lba_low = 0x10;
-       ataio->cmd.lba_mid = 0;
-       ataio->cmd.lba_mid_exp = 0;
-       /* Freeze SIM while doing READ LOG EXT. */
+       /* Freeze SIM while doing recovery. */
        xpt_freeze_simq(ch->sim, 1);
        ahci_begin_transaction(dev, ccb);
 }
@@ -2113,7 +2145,7 @@ ahci_process_read_log(device_t dev, unio
        struct ata_res *res;
        int i;
 
-       ch->readlog = 0;
+       ch->recoverycmd = 0;
 
        data = ccb->ataio.data_ptr;
        if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
@@ -2121,6 +2153,8 @@ ahci_process_read_log(device_t dev, unio
                for (i = 0; i < ch->numslots; i++) {
                        if (!ch->hold[i])
                                continue;
+                       if (ch->hold[i]->ccb_h.func_code != XPT_ATA_IO)
+                               continue;
                        if ((data[0] & 0x1F) == i) {
                                res = &ch->hold[i]->ataio.res;
                                res->status = data[2];
@@ -2151,6 +2185,8 @@ ahci_process_read_log(device_t dev, unio
                for (i = 0; i < ch->numslots; i++) {
                        if (!ch->hold[i])
                                continue;
+                       if (ch->hold[i]->ccb_h.func_code != XPT_ATA_IO)
+                               continue;
                        xpt_done(ch->hold[i]);
                        ch->hold[i] = NULL;
                        ch->numhslots--;
@@ -2162,6 +2198,28 @@ ahci_process_read_log(device_t dev, unio
 }
 
 static void
+ahci_process_request_sense(device_t dev, union ccb *ccb)
+{
+       struct ahci_channel *ch = device_get_softc(dev);
+       int i;
+
+       ch->recoverycmd = 0;
+
+       i = ccb->ccb_h.recovery_slot;
+       if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+               ch->hold[i]->ccb_h.status |= CAM_AUTOSNS_VALID;
+       } else {
+               ch->hold[i]->ccb_h.status &= ~CAM_STATUS_MASK;
+               ch->hold[i]->ccb_h.status |= CAM_AUTOSENSE_FAIL;
+       }
+       xpt_done(ch->hold[i]);
+       ch->hold[i] = NULL;
+       ch->numhslots--;
+       xpt_free_ccb(ccb);
+       xpt_release_simq(ch->sim, TRUE);
+}
+
+static void
 ahci_start(device_t dev, int fbs)
 {
        struct ahci_channel *ch = device_get_softc(dev);
@@ -2519,6 +2577,7 @@ ahciaction(struct cam_sim *sim, union cc
                        ccb->ccb_h.status = CAM_SEL_TIMEOUT;
                        break;
                }
+               ccb->ccb_h.recovery_type = RECOVERY_NONE;
                /* Check for command collision. */
                if (ahci_check_collision(dev, ccb)) {
                        /* Freeze command. */

Modified: head/sys/dev/ahci/ahci.h
==============================================================================
--- head/sys/dev/ahci/ahci.h    Tue Apr 12 11:17:46 2011        (r220564)
+++ head/sys/dev/ahci/ahci.h    Tue Apr 12 11:24:59 2011        (r220565)
@@ -408,7 +408,7 @@ struct ahci_channel {
        int                     numtslots;      /* Number of tagged slots */
        int                     numtslotspd[16];/* Number of tagged slots per 
dev */
        int                     numhslots;      /* Number of holden slots */
-       int                     readlog;        /* Our READ LOG active */
+       int                     recoverycmd;    /* Our READ LOG active */
        int                     fatalerr;       /* Fatal error happend */
        int                     lastslot;       /* Last used slot */
        int                     taggedtarget;   /* Last tagged target */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to