diff usr/src/uts/common/io/sata/impl/sata.c @ 10391:12b08c516444

6838603 Under heavy I/O load, all Seagate Dragonfly drives in an x4x40 go offline at the same time 6857563 nv_sata poorly handles port reset, signature detection and hot-plugging events for Dragonfly drives 6869467 nv_sata: race between reset/abort/timeout and command completion interrupt causing panic 6679403 nv_sata: mcp55 interrupt handling can loop and delay other devices interrupt servicing 6854127 sata: device under reset may appear as gone
author Pawel Wojcik <Pawel.Wojcik@Sun.COM>
date Thu, 27 Aug 2009 11:15:07 -0700
parents 811db323512d
children 7d60ed90f743
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c	Thu Aug 27 12:59:34 2009 -0400
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Thu Aug 27 11:15:07 2009 -0700
@@ -131,7 +131,7 @@
 
 #define	LEGACY_HWID_LEN	64	/* Model (40) + Serial (20) + pad */
 
-static char sata_rev_tag[] = {"1.44"};
+static char sata_rev_tag[] = {"1.45"};
 
 /*
  * SATA cb_ops functions
@@ -2069,8 +2069,17 @@
 	sata_hba_inst = (sata_hba_inst_t *)(hba_tran->tran_hba_private);
 
 	/* Validate scsi device address */
+	/*
+	 * Note: tgt_free relates to the SCSA view of a device. If called, there
+	 * was a device at this address, so even if the sata framework internal
+	 * resources were alredy released because a device was detached,
+	 * this function should be executed as long as its actions do
+	 * not require the internal sata view of a device and the address
+	 * refers to a valid sata address.
+	 * Validating the address here means that we do not trust SCSA...
+	 */
 	if (sata_validate_scsi_address(sata_hba_inst, &sd->sd_address,
-	    &sata_device) != 0)
+	    &sata_device) == -1)
 		return;
 
 	mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst,
@@ -3053,16 +3062,30 @@
 
 	case -1:
 		/* Invalid address or invalid device type */
-		SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
-		    "sata_scsi_start: reject command because "
-		    "dev type or address is invalid\n", NULL);
 		return (TRAN_BADPKT);
+	case 2:
+		/*
+		 * Valid address but device type is unknown - Chack if it is
+		 * in the reset state and therefore in an indeterminate state.
+		 */
+		sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+		    &spx->txlt_sata_pkt->satapkt_device);
+		if (sdinfo != NULL && (sdinfo->satadrv_event_flags &
+		    (SATA_EVNT_DEVICE_RESET |
+		    SATA_EVNT_INPROC_DEVICE_RESET)) != 0) {
+			if (!ddi_in_panic()) {
+				spx->txlt_scsi_pkt->pkt_reason = CMD_INCOMPLETE;
+				*reason = CMD_INCOMPLETE;
+				SATADBG1(SATA_DBG_SCSI_IF,
+				    spx->txlt_sata_hba_inst,
+				    "sata_scsi_start: rejecting command "
+				    "because of device reset state\n", NULL);
+				return (TRAN_BUSY);
+			}
+		}
+		/* FALLTHROUGH */
 	case 1:
-		/* valid address but no device - it has disappeared ? */
-		SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
-		    "sata_scsi_start: reject command because "
-		    "device is gone\n", NULL);
-
+		/* valid address but no valid device - it has disappeared */
 		spx->txlt_scsi_pkt->pkt_reason = CMD_DEV_GONE;
 		*reason = CMD_DEV_GONE;
 		/*
@@ -3743,8 +3766,8 @@
 
 /*
  * SATA translate command: Test Unit Ready
- * At the moment this is an emulated command (ATA version for SATA hard disks).
- * May be translated into Check Power Mode command in the future
+ * (ATA version for SATA hard disks).
+ * It is translated into the Check Power Mode command.
  *
  * Returns TRAN_ACCEPT and appropriate values in scsi_pkt fields.
  */
@@ -4145,8 +4168,8 @@
 	}
 
 	/*
-	 * since it was synchronous commands,
-	 * a callback function will be called directely.
+	 * Since it was a synchronous command,
+	 * a callback function will be called directly.
 	 */
 	mutex_exit(&SATA_CPORT_MUTEX(shi, cport));
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
@@ -7891,7 +7914,7 @@
 
 /*
  * sata_build_lsense_page_0e() is used to create the
- * SCSI LOG SENSE page 0e (supported log pages)
+ * SCSI LOG SENSE page 0e (start-stop cycle counter page)
  *
  * Date of Manufacture (0x0001)
  *	YEAR = "0000"
@@ -10883,7 +10906,8 @@
  * SCSI target address is translated into SATA cport/pmport and compared
  * with a controller port/device configuration. LUN has to be 0.
  * Returns 0 if a scsi target refers to an attached device,
- * returns 1 if address is valid but device is not attached,
+ * returns 1 if address is valid but no valid device is attached,
+ * returns 2 if address is valid but device type is unknown (not valid device),
  * returns -1 if bad address or device is of an unsupported type.
  * Upon return sata_device argument is set.
  *
@@ -10913,6 +10937,11 @@
 		sata_pmult_info_t *pmultinfo;
 		sata_drive_info_t *sdinfo = NULL;
 
+		sata_device->satadev_addr.qual = qual;
+		sata_device->satadev_addr.cport = cport;
+		sata_device->satadev_addr.pmport = pmport;
+		sata_device->satadev_rev = SATA_DEVICE_REV_1;
+
 		rval = 1;	/* Valid sata address */
 
 		cportinfo = SATA_CPORT_INFO(sata_hba_inst, cport);
@@ -10921,12 +10950,18 @@
 			    cportinfo->cport_dev_type == SATA_DTYPE_NONE)
 				goto out;
 
+			sdinfo = SATA_CPORTINFO_DRV_INFO(cportinfo);
+			if (cportinfo->cport_dev_type == SATA_DTYPE_UNKNOWN &&
+			    sdinfo != NULL) {
+				rval = 2;
+				goto out;
+			}
+
 			if ((cportinfo->cport_dev_type &
 			    SATA_VALID_DEV_TYPE) == 0) {
 				rval = -1;
 				goto out;
 			}
-			sdinfo = SATA_CPORTINFO_DRV_INFO(cportinfo);
 
 		} else if (qual == SATA_ADDR_DPMPORT) {
 			pmultinfo = SATA_CPORTINFO_PMULT_INFO(cportinfo);
@@ -10942,6 +10977,18 @@
 
 			sdinfo = SATA_PMPORT_DRV_INFO(sata_hba_inst, cport,
 			    pmport);
+			if (SATA_PMPORT_DEV_TYPE(sata_hba_inst, cport,
+			    pmport) == SATA_DTYPE_UNKNOWN && sdinfo != NULL) {
+				rval = 2;
+				goto out;
+			}
+
+			if ((SATA_PMPORT_DEV_TYPE(sata_hba_inst, cport,
+			    pmport) && SATA_VALID_DEV_TYPE) == 0) {
+				rval = -1;
+				goto out;
+			}
+
 		} else {
 			rval = -1;
 			goto out;
@@ -10951,14 +10998,11 @@
 			goto out;
 
 		sata_device->satadev_type = sdinfo->satadrv_type;
-		sata_device->satadev_addr.qual = qual;
-		sata_device->satadev_addr.cport = cport;
-		sata_device->satadev_addr.pmport = pmport;
-		sata_device->satadev_rev = SATA_DEVICE_REV_1;
+
 		return (0);
 	}
 out:
-	if (rval == 1) {
+	if (rval > 0) {
 		SATADBG2(SATA_DBG_SCSI_IF, sata_hba_inst,
 		    "sata_validate_scsi_address: no valid target %x lun %x",
 		    ap->a_target, ap->a_lun);
@@ -11159,6 +11203,7 @@
 	return (rval);
 }
 
+
 /*
  * Get pointer to sata_drive_info structure.
  *
@@ -12259,6 +12304,7 @@
 
 	sata_common_free_dma_rsrcs(spx);
 }
+
 /*
  * Fetch Device Identify data.
  * Send DEVICE IDENTIFY or IDENTIFY PACKET DEVICE (depending on a device type)
@@ -12993,7 +13039,7 @@
 	sata_cport_info_t *cportinfo = NULL;
 	sata_pmport_info_t *pmportinfo = NULL;
 	sata_pmult_info_t *pmultinfo = NULL;
-	sata_device_t 		subsdevice;
+	sata_device_t subsdevice;
 	int cport, pmport, qual;
 	int rval = SATA_SUCCESS;
 	int npmport = 0;