Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Apr 2011 11:24:59 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r220565 - head/sys/dev/ahci
Message-ID:  <201104121124.p3CBOxw7022782@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104121124.p3CBOxw7022782>