PERFORCE change 164261 for review

Alexander Motin mav at FreeBSD.org
Sat Jun 13 11:50:26 UTC 2009


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

Change 164261 by mav at mav_mavbook on 2009/06/13 11:49:27

	Make Soft Reset sequence to be an atomic operation for XPT.
	SiI HBAs to it completely in silicon.

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_xpt.c#14 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#23 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_xpt.c#14 (text+ko) ====

@@ -92,7 +92,6 @@
 
 typedef enum {
 	PROBE_RESET,
-	PROBE_UNRESET,
 	PROBE_IDENTIFY,
 	PROBE_INQUIRY,
 	PROBE_FULL_INQUIRY,
@@ -101,7 +100,6 @@
 
 static char *probe_action_text[] = {
 	"PROBE_RESET",
-	"PROBE_UNRESET",
 	"PROBE_IDENTIFY",
 	"PROBE_INQUIRY",
 	"PROBE_FULL_INQUIRY",
@@ -281,8 +279,8 @@
 	 * delay before attempting to probe the device.
 	 * For HBAs that don't do bus resets, this won't make a difference.
 	 */
-//	cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
-//				      scsi_delay);
+	cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
+				      scsi_delay);
 	probeschedule(periph);
 	return(CAM_REQ_CMP);
 }
@@ -330,7 +328,6 @@
 
 	switch (softc->action) {
 	case PROBE_RESET:
-	case PROBE_UNRESET:
 		cam_fill_ataio(ataio,
 		      4,
 		      probedone,
@@ -339,7 +336,7 @@
 		      /*data_ptr*/NULL,
 		      /*dxfer_len*/0,
 		      30 * 1000);
-		ata_reset_cmd(ataio, softc->action == PROBE_RESET ? 1 : 0);
+		ata_reset_cmd(ataio, 1);
 		break;
 	case PROBE_IDENTIFY:
 	{
@@ -559,25 +556,6 @@
 	switch (softc->action) {
 	case PROBE_RESET:
 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
-			PROBE_SET_ACTION(softc, PROBE_UNRESET);
-			xpt_release_ccb(done_ccb);
-			xpt_schedule(periph, priority);
-			return;
-		} else if (cam_periph_error(done_ccb, 0,
-					    done_ccb->ccb_h.target_lun > 0
-					    ? SF_RETRY_UA|SF_QUIET_IR
-					    : SF_RETRY_UA,
-					    &softc->saved_ccb) == ERESTART) {
-			return;
-		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
-			/* Don't wedge the queue */
-			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
-					 /*run_queue*/TRUE);
-		}
-		xpt_release_ccb(done_ccb);
-		break;
-	case PROBE_UNRESET:
-		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
 			printf("SIGNATURE: %02x%02x%02x%02x\n",
 			    done_ccb->ataio.res.lba_high, done_ccb->ataio.res.lba_mid,
 			    done_ccb->ataio.res.lba_low, done_ccb->ataio.res.sector_count);

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

@@ -69,7 +69,7 @@
 static void ahci_execute_transaction(struct ahci_slot *slot);
 static void ahci_timeout(struct ahci_slot *slot);
 static void ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et);
-static int ahci_hardreset(device_t dev, int port, uint32_t *signature);
+static int ahci_hardreset(device_t dev);
 static int ahci_setup_fis(struct ahci_cmd_tab *ctp, union ccb *ccb, int tag);
 static void ahci_dmainit(device_t dev);
 static void ahci_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
@@ -79,7 +79,7 @@
 static void ahci_reset(device_t dev);
 static void ahci_start(device_t dev);
 static void ahci_stop(device_t dev);
-//static void ahci_clo(device_t dev);
+static void ahci_clo(device_t dev);
 static void ahci_start_fr(device_t dev);
 static void ahci_stop_fr(device_t dev);
 
@@ -848,6 +848,7 @@
 		    >> AHCI_P_CMD_CCS_SHIFT;
 		/* Kick controller into sane state */
 		ahci_stop(dev);
+		ahci_clo(dev);
 		ahci_start(dev);
 		res = ch->rslots;
 		err = ch->rslots & (cstatus | sstatus);
@@ -1030,6 +1031,10 @@
 	if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
 	    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
 	    ccb->ataio.cmd.control & ATA_A_RESET) {
+		/* Kick controller into sane state */
+		ahci_stop(dev);
+		ahci_clo(dev);
+		ahci_start(dev);
 		clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY;
 	}
 	clp->bytecount = 0;
@@ -1080,6 +1085,7 @@
 			et = CAM_CMD_TIMEOUT;
 			/* Kick controller into sane state */
 			ahci_stop(ch->dev);
+			ahci_clo(ch->dev);
 			ahci_start(ch->dev);
 		}
 		ahci_end_transaction(slot, et);
@@ -1172,33 +1178,34 @@
 		bus_dmamap_unload(ch->dma.data_tag, slot->dma.data_map);
 	}
 	/* Set proper result status. */
+	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
 	switch (et) {
 	case AHCI_ERR_NONE:
-		ccb->ccb_h.status = CAM_REQ_CMP;
+		ccb->ccb_h.status |= CAM_REQ_CMP;
 		if (ccb->ccb_h.func_code == XPT_SCSI_IO)
 			ccb->csio.scsi_status = SCSI_STATUS_OK;
 		break;
 	case AHCI_ERR_INVALID:
-		ccb->ccb_h.status = CAM_REQ_INVALID;
+		ccb->ccb_h.status |= CAM_REQ_INVALID;
 		break;
 	case AHCI_ERR_REAL:
 		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
-			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+			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;
+			ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
 		break;
 	case AHCI_ERR_BTW:
-		ccb->ccb_h.status = CAM_REQUEUE_REQ;
+		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
 		break;
 	case AHCI_ERR_RESET:
-		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
+		ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
 		break;
 	case AHCI_ERR_TIMEOUT:
-		ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
 		break;
 	default:
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
 	}
 	/* Free slot. */
 	ch->rslots &= ~(1 << slot->slot);
@@ -1210,13 +1217,27 @@
 	    (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) {
 		ch->numtslots--;
 	}
+	/* If it was first request of reset sequence nod no error,
+	 * proceed to second. */
+	if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
+	    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) &&
+	    (ccb->ataio.cmd.control & ATA_A_RESET) &&
+	    et == AHCI_ERR_NONE) {
+		ccb->ataio.cmd.control &= ~ATA_A_RESET;
+		ahci_begin_transaction(dev, ccb);
+		return;
+	}
 	xpt_done(ccb);
 	if (ch->frozen && ch->numrslots == 0) {
 		union ccb *fccb = ch->frozen;
 //device_printf(dev, "Unfreeze\n");
 		ch->frozen = NULL;
 		ahci_begin_transaction(dev, fccb);
-		xpt_release_simq(ch->sim, TRUE);
+		/* If frozen command is not reset - release queue.
+		 * Reset will be released after it is finished. */
+		if ((fccb->ccb_h.func_code == XPT_ATA_IO) &&
+		    (fccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) == 0)
+			xpt_release_simq(ch->sim, TRUE);
 	}
 }
 
@@ -1227,12 +1248,12 @@
 	u_int32_t cmd;
 
 	/* Clear SATA error register */
-	ATA_OUTL(ch->r_mem, AHCI_P_SERR, ATA_INL(ch->r_mem, AHCI_P_SERR));
+	ATA_OUTL(ch->r_mem, AHCI_P_SERR, 0xFFFFFFFF);
 	/* Clear any interrupts pending on this channel */
-	ATA_OUTL(ch->r_mem, AHCI_P_IS, ATA_INL(ch->r_mem, AHCI_P_IS));
+	ATA_OUTL(ch->r_mem, AHCI_P_IS, 0xFFFFFFFF);
 	/* Start operations on this channel */
 	cmd = ATA_INL(ch->r_mem, AHCI_P_CMD);
-	ATA_OUTL(ch->r_mem, AHCI_P_CMD, cmd | AHCI_P_CMD_ST);
+	ATA_OUTL(ch->r_mem, AHCI_P_CMD, cmd | AHCI_P_CMD_ST | AHCI_P_CMD_PMA);
 //	     (ch->devices & ATA_PORTMULTIPLIER ? AHCI_P_CMD_PMA : 0));
 }
 
@@ -1257,7 +1278,6 @@
 	} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CR);
 }
 
-#if 0
 static void
 ahci_clo(device_t dev)
 {
@@ -1280,7 +1300,6 @@
 		} while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CLO);
 	}
 }
-#endif
 
 static void
 ahci_stop_fr(device_t dev)
@@ -1336,23 +1355,19 @@
 }
 
 static int
-ahci_hardreset(device_t dev, int port, uint32_t *signature)
+ahci_hardreset(device_t dev)
 {
-	struct ahci_channel *ch = device_get_softc(dev);
 
-	*signature = 0xffffffff;
 	ahci_stop(dev);
 	/* Reset port */
 	if (!ahci_sata_phy_reset(dev, 0))
 		return (ENOENT);
 	/* Wait for clearing busy status. */
 	if (ahci_wait_ready(dev, 10000)) {
-		device_printf(dev, "hardware reset timeout\n");
-		return (EBUSY);
+		device_printf(dev, "device ready timeout\n");
+		ahci_clo(dev);
 	}
-	*signature = ATA_INL(ch->r_mem, AHCI_P_SIG);
 	ahci_start(dev);
-
 	return (0);
 }
 
@@ -1360,7 +1375,6 @@
 ahci_reset(device_t dev)
 {
 	struct ahci_channel *ch = device_get_softc(dev);
-	u_int32_t signature;
 
 	if (bootverbose)
 		device_printf(dev, "AHCI reset...\n");
@@ -1368,7 +1382,7 @@
 	/* Disable port interrupts */
 	ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
 	/* Reset and reconnect PHY, */
-	if (ahci_hardreset(dev, -1, &signature)) {
+	if (ahci_hardreset(dev)) {
 		if (bootverbose)
 			device_printf(dev,
 			    "AHCI reset done: phy reset found no device\n");
@@ -1448,8 +1462,8 @@
 	u_int32_t status;
 	int timeout;
 
-	/* Wait up to 1 second for "connect well" */
-	for (timeout = 0; timeout < 1000 ; timeout++) {
+	/* Wait up to 100ms for "connect well" */
+	for (timeout = 0; timeout < 100 ; timeout++) {
 		status = ATA_INL(ch->r_mem, AHCI_P_SSTS);
 		if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
 		    ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
@@ -1457,7 +1471,7 @@
 			break;
 		DELAY(1000);
 	}
-	if (timeout >= 1000) {
+	if (timeout >= 100) {
 		if (bootverbose) {
 			device_printf(ch->dev, "SATA connect timeout status=%08x\n",
 			    status);
@@ -1487,11 +1501,13 @@
 
 	if (bootverbose)
 		device_printf(dev, "hardware reset ...\n");
-	ATA_OUTL(ch->r_mem, AHCI_P_SCTL, ATA_SC_DET_RESET);
+	ATA_OUTL(ch->r_mem, AHCI_P_SCTL, ATA_SC_IPM_DIS_PARTIAL |
+	    ATA_SC_IPM_DIS_SLUMBER | ATA_SC_DET_RESET);
 	DELAY(50000);
 	ATA_OUTL(ch->r_mem, AHCI_P_SCTL,
-	    ATA_SC_DET_IDLE /*| ATA_SC_SPD_SPEED_GEN1*/ | ((ch->pm_level > 0) ? 0 :
+	    ATA_SC_DET_IDLE | ATA_SC_SPD_SPEED_GEN1 | ((ch->pm_level > 0) ? 0 :
 	    (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)));
+	DELAY(50000);
 	return (ahci_sata_connect(ch));
 }
 
@@ -1519,12 +1535,18 @@
 		/* Check for command collision. */
 		if (ahci_check_collision(dev, ccb)) {
 			/* Freeze command. */
-device_printf(dev, "Freeze\n");
+//device_printf(dev, "Freeze\n");
 			/* We have only one frozen slot, so freeze simq also. */
 			xpt_freeze_simq(ch->sim, 1);
 			ch->frozen = ccb;
 			return;
 		}
+		/* If it is a reset sequence - freeze the queue. */
+		if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
+		    (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL)) {
+			xpt_freeze_simq(ch->sim, 1);
+			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
+		}
 		ahci_begin_transaction(dev, ccb);
 		break;
 	case XPT_EN_LUN:		/* Enable LUN as a target */


More information about the p4-projects mailing list