PERFORCE change 164397 for review

Alexander Motin mav at FreeBSD.org
Mon Jun 15 06:26:27 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=164397

Change 164397 by mav at mav_mavbook on 2009/06/15 06:25:36

	Use READ LOG EXT command to reveal NCQ commands errors.

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#31 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#15 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#31 (text+ko) ====

@@ -52,6 +52,7 @@
 #include <cam/cam_ccb.h>
 #include <cam/cam_sim.h>
 #include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
 #include <cam/cam_debug.h>
 
 /* local prototypes */
@@ -85,9 +86,14 @@
 static int ahci_sata_connect(struct ahci_channel *ch);
 static int ahci_sata_phy_reset(device_t dev, int quick);
 
+static void ahci_issue_read_log(device_t dev);
+static void ahci_process_read_log(device_t dev, union ccb *ccb);
+
 static void ahciaction(struct cam_sim *sim, union ccb *ccb);
 static void ahcipoll(struct cam_sim *sim);
 
+MALLOC_DEFINE(M_AHCI, "AHCI driver", "AHCI driver data buffers");
+
 /*
  * AHCI v1.x compliant SATA chipset support functions
  */
@@ -836,7 +842,7 @@
 	struct ahci_channel *ch = device_get_softc(dev);
 	uint32_t istatus, cstatus, sstatus, ok, err;
 	enum ahci_err_type et;
-	int i, ccs;
+	int i, ccs, ncq_err = 0;
 
 	mtx_lock(&ch->mtx);
 	/* Read and clear interrupt statuses. */
@@ -873,7 +879,8 @@
 	}
 	/* On error, complete the rest of commands with error statuses. */
 	if (err) {
-		xpt_freeze_simq(ch->sim, ch->numrslots);
+		if (!ch->readlog)
+			xpt_freeze_simq(ch->sim, ch->numrslots);
 		if (ch->frozen) {
 			union ccb *fccb = ch->frozen;
 			ch->frozen = NULL;
@@ -884,10 +891,7 @@
 			/* XXX: reqests in loading state. */
 			if (((err >> i) & 1) == 0)
 				continue;
-			if (istatus & AHCI_P_IX_IF) {
-				/* SATA error */
-				et = AHCI_ERR_SATA;
-			} else if (istatus & AHCI_P_IX_TFE) {
+			if (istatus & AHCI_P_IX_TFE) {
 				/* Task File Error */
 				if (ch->numtslots == 0) {
 					/* Untagged operation. */
@@ -897,12 +901,18 @@
 						et = AHCI_ERR_INNOCENT;
 				} else {
 					/* Tagged operation. */
-					et = AHCI_ERR_TFE;
+					et = AHCI_ERR_NCQ;
+					ncq_err = 1;
 				}
+			} else if (istatus & AHCI_P_IX_IF) {
+				/* SATA error */
+				et = AHCI_ERR_SATA;
 			} else
 				et = AHCI_ERR_INVALID;
 			ahci_end_transaction(&ch->slot[i], et);
 		}
+		if (ncq_err)
+			ahci_issue_read_log(dev);
 	}
 	mtx_unlock(&ch->mtx);
 }
@@ -1006,7 +1016,8 @@
 //device_printf(slot->dev, "%s slot %d\n", __func__, slot->slot);
 	if (error) {
 		device_printf(slot->dev, "DMA load error\n");
-		xpt_freeze_simq(ch->sim, 1);
+		if (!ch->readlog)
+			xpt_freeze_simq(ch->sim, 1);
 		ahci_end_transaction(slot, AHCI_ERR_INVALID);
 		return;
 	}
@@ -1046,7 +1057,8 @@
 	/* Setup the FIS for this request */
 	if (!(fis_size = ahci_setup_fis(ctp, ccb, slot->slot))) {
 		device_printf(ch->dev, "Setting up SATA FIS failed\n");
-		xpt_freeze_simq(ch->sim, 1);
+		if (!ch->readlog)
+			xpt_freeze_simq(ch->sim, 1);
 		ahci_end_transaction(slot, AHCI_ERR_INVALID);
 		return;
 	}
@@ -1155,7 +1167,8 @@
 	ahci_clo(ch->dev);
 	ahci_start(ch->dev);
 
-	xpt_freeze_simq(ch->sim, ch->numrslots);
+	if (!ch->readlog)
+		xpt_freeze_simq(ch->sim, ch->numrslots);
 	/* Handle command with timeout. */
 	ahci_end_transaction(&ch->slot[slot->slot], AHCI_ERR_TIMEOUT);
 	/* Handle the rest of commands. */
@@ -1240,8 +1253,9 @@
 		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
 			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
 			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
-		} else
-			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
+		} else {
+			ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR;
+		}
 		break;
 	case AHCI_ERR_SATA:
 			ccb->ccb_h.status |= CAM_UNCOR_PARITY;
@@ -1249,6 +1263,8 @@
 	case AHCI_ERR_TIMEOUT:
 		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
 		break;
+	case AHCI_ERR_NCQ:
+		ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR;
 	default:
 		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
 	}
@@ -1273,7 +1289,14 @@
 		ahci_begin_transaction(dev, ccb);
 		return;
 	}
-	xpt_done(ccb);
+	/* If it was NCQ command error, put result on hold. */
+	if (et == AHCI_ERR_NCQ) {
+		ch->hold[slot->slot] = ccb;
+	} else if (ch->readlog)	/* If it was our READ LOG command - process it. */
+		ahci_process_read_log(dev, ccb);
+	else
+		xpt_done(ccb);
+	/* Unfreeze frozen command. */
 	if (ch->frozen && ch->numrslots == 0) {
 		union ccb *fccb = ch->frozen;
 //device_printf(dev, "Unfreeze\n");
@@ -1284,6 +1307,104 @@
 }
 
 static void
+ahci_issue_read_log(device_t dev)
+{
+	struct ahci_channel *ch = device_get_softc(dev);
+	union ccb *ccb;
+	struct ccb_ataio *ataio;
+	int i;
+
+//device_printf(dev, "%s\n", __func__);
+	ch->readlog = 1;
+	/* Find some holden command. */
+	for (i = 0; i < ch->numslots; i++) {
+		if (ch->hold[i])
+			break;
+	}
+	ccb = xpt_alloc_ccb_nowait();
+	if (ccb == NULL) {
+		device_printf(dev, "Unable allocate READ LOG command");
+		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) {
+		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;
+	
+	ahci_begin_transaction(dev, ccb);
+}
+
+static void
+ahci_process_read_log(device_t dev, union ccb *ccb)
+{
+	struct ahci_channel *ch = device_get_softc(dev);
+	uint8_t *data;
+	struct ata_res *res;
+	int i;
+
+//device_printf(dev, "%s\n", __func__);
+	ch->readlog = 0;
+
+	data = ccb->ataio.data_ptr;
+	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
+	    (data[0] & 0x80) == 0) {
+		for (i = 0; i < ch->numslots; i++) {
+			if (!ch->hold[i])
+				continue;
+			if ((data[0] & 0x1F) == i) {
+device_printf(dev, "READ LOG EXT: TAG %d MATCH\n", i);
+				res = &ch->hold[i]->ataio.res;
+				res->status = data[2];
+				res->error = data[3];
+				res->lba_low = data[4];
+				res->lba_mid = data[5];
+				res->lba_high = data[6];
+				res->device = data[7];
+				res->lba_low_exp = data[8];
+				res->lba_mid_exp = data[9];
+				res->lba_high_exp = data[10];
+				res->sector_count = data[12];
+				res->sector_count_exp = data[13];
+			} else {
+				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+				ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+			}
+			xpt_done(ch->hold[i]);
+			ch->hold[i] = NULL;
+		}
+	} else {
+		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+			device_printf(dev, "Error while READ LOG EXT\n");
+		else if ((data[0] & 0x80) == 0) {
+			device_printf(dev, "Non-queued command error in READ LOG EXT\n");
+		}
+		for (i = 0; i < ch->numslots; i++) {
+			if (!ch->hold[i])
+				continue;
+			xpt_done(ch->hold[i]);
+			ch->hold[i] = NULL;
+		}
+	}
+	free(ccb->ataio.data_ptr, M_AHCI);
+	xpt_free_ccb(ccb);
+}
+
+static void
 ahci_start(device_t dev)
 {
 	struct ahci_channel *ch = device_get_softc(dev);

==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#15 (text+ko) ====

@@ -341,6 +341,7 @@
 	int			sata_rev;	/* Maximum allowed SATA generation */
 
 	struct ahci_slot	slot[AHCI_MAX_SLOTS];
+	union ccb		*hold[AHCI_MAX_SLOTS];
 	struct mtx		mtx;		/* state lock */
 	int			devices;        /* What is present */
 	int			pm_present;	/* PM presence reported */
@@ -348,6 +349,7 @@
 	uint32_t		aslots;		/* Slots with atomic commands  */
 	int			numrslots;	/* Number of running slots */
 	int			numtslots;	/* Number of tagged slots */
+	int			readlog;	/* Our READ LOG active */
 	int			lastslot;	/* Last used slot */
 	int			taggedtarget;	/* Last tagged target */
 	union ccb		*frozen;	/* Frozen command */
@@ -385,6 +387,8 @@
 	AHCI_ERR_TFE,		/* Task File Error. */
 	AHCI_ERR_SATA,		/* SATA error. */
 	AHCI_ERR_TIMEOUT,	/* Command execution timeout. */
+	AHCI_ERR_NCQ,		/* NCQ command error. CCB should be put on hold
+				 * until READ LOG executed to reveal error. */
 };
 
 /* macros to hide busspace uglyness */


More information about the p4-projects mailing list