changeset 1612:f22bd5bc2aff

6369698 sata framework needs to support SCSI LOG SENSE command 6394707 inquiry responses from sata devices using the sata framework are partially incorrect 6397614 sata framework only uses one of the two bytes of allocation length during SCSI INQUIRY 6397617 si3124 fails to return ATA register contents to sata framework 6397618 marvell88sx fails to fill in the LBA information on errors
author ls24207
date Mon, 13 Mar 2006 18:33:17 -0800
parents 2ffa29275ba7
children aca102a242d3
files usr/src/uts/common/io/sata/adapters/si3124/si3124.c usr/src/uts/common/io/sata/impl/sata.c usr/src/uts/common/sys/sata/adapters/si3124/si3124reg.h usr/src/uts/common/sys/sata/sata_defs.h usr/src/uts/common/sys/sata/sata_hba.h
diffstat 5 files changed, 1741 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/adapters/si3124/si3124.c	Mon Mar 13 18:04:01 2006 -0800
+++ b/usr/src/uts/common/io/sata/adapters/si3124/si3124.c	Mon Mar 13 18:33:17 2006 -0800
@@ -308,6 +308,7 @@
 
 static	void si_log(si_ctl_state_t *, uint_t, char *, ...);
 
+static	void si_copy_out_regs(sata_cmd_t *, fis_reg_h2d_t *);
 
 /*
  * DMA attributes for the data buffer
@@ -1192,7 +1193,7 @@
 		return (SATA_TRAN_PORT_ERROR);
 	}
 
-	if (spkt->satapkt_cmd.satacmd_flags & SATA_CLEAR_DEV_RESET_STATE) {
+	if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
 		si_portp->siport_reset_in_progress = 0;
 		SIDBG1(SIDBG_ENTRY, si_ctlp,
 			"si_tran_start clearing the "
@@ -1200,8 +1201,7 @@
 	}
 
 	if (si_portp->siport_reset_in_progress &&
-		!(spkt->satapkt_cmd.satacmd_flags &
-					SATA_IGNORE_DEV_RESET_STATE)) {
+		! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset) {
 
 		spkt->satapkt_reason = SATA_PKT_BUSY;
 		SIDBG1(SIDBG_ERRS, si_ctlp,
@@ -1341,6 +1341,13 @@
 
 		satapkt = si_portp->siport_slot_pkts[tmpslot];
 		ASSERT(satapkt != NULL);
+		prb =  &si_portp->siport_prbpool[tmpslot];
+		ASSERT(prb != NULL);
+		satapkt->satapkt_cmd.satacmd_status_reg =
+						GET_FIS_COMMAND(prb->prb_fis);
+		if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs)
+			si_copy_out_regs(&satapkt->satapkt_cmd, &prb->prb_fis);
+
 		SIDBG1(SIDBG_ERRS, si_ctlp,
 			"si_mop_commands sending up completed satapkt: %x",
 			satapkt);
@@ -1385,6 +1392,30 @@
 						GET_FIS_COMMAND(prb->prb_fis);
 		satapkt->satapkt_cmd.satacmd_error_reg =
 						GET_FIS_FEATURES(prb->prb_fis);
+		satapkt->satapkt_cmd.satacmd_sec_count_lsb =
+					GET_FIS_SECTOR_COUNT(prb->prb_fis);
+		satapkt->satapkt_cmd.satacmd_lba_low_lsb =
+					GET_FIS_SECTOR(prb->prb_fis);
+		satapkt->satapkt_cmd.satacmd_lba_mid_lsb =
+					GET_FIS_CYL_LOW(prb->prb_fis);
+		satapkt->satapkt_cmd.satacmd_lba_high_lsb =
+					GET_FIS_CYL_HI(prb->prb_fis);
+		satapkt->satapkt_cmd.satacmd_device_reg =
+					GET_FIS_DEV_HEAD(prb->prb_fis);
+
+		if (satapkt->satapkt_cmd.satacmd_addr_type == ATA_ADDR_LBA48) {
+			satapkt->satapkt_cmd.satacmd_sec_count_msb =
+					GET_FIS_SECTOR_COUNT_EXP(prb->prb_fis);
+			satapkt->satapkt_cmd.satacmd_lba_low_msb =
+					GET_FIS_SECTOR_EXP(prb->prb_fis);
+			satapkt->satapkt_cmd.satacmd_lba_mid_msb =
+					GET_FIS_CYL_LOW_EXP(prb->prb_fis);
+			satapkt->satapkt_cmd.satacmd_lba_high_msb =
+					GET_FIS_CYL_HI_EXP(prb->prb_fis);
+		}
+
+		if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs)
+			si_copy_out_regs(&satapkt->satapkt_cmd, &prb->prb_fis);
 
 		/*
 		 * In the case of NCQ command failures, the error is
@@ -2441,9 +2472,11 @@
 
 	/* Now fill the prb. */
 	if (is_atapi) {
-		if (spkt->satapkt_cmd.satacmd_flags == SATA_DIR_READ) {
+		if (spkt->satapkt_cmd.satacmd_flags.sata_data_direction ==
+		    SATA_DIR_READ) {
 			SET_PRB_CONTROL_PKT_READ(prb);
-		} else if (spkt->satapkt_cmd.satacmd_flags == SATA_DIR_WRITE) {
+		} else if (spkt->satapkt_cmd.satacmd_flags.sata_data_direction
+		    == SATA_DIR_WRITE) {
 			SET_PRB_CONTROL_PKT_WRITE(prb);
 		}
 	}
@@ -2511,7 +2544,7 @@
 
 	}
 
-	if (cmd->satacmd_flags & SATA_QUEUED_CMD) {
+	if (cmd->satacmd_flags.sata_queued) {
 		/*
 		 * For queued commands, the TAG for the sector count lsb is
 		 * generated from current slot number.
@@ -3590,12 +3623,20 @@
 	finished_tags =  si_portp->siport_pending_tags &
 					~slot_status & SI_SLOT_MASK;
 	while (finished_tags) {
+		si_prb_t *prb;
+
 		finished_slot = ddi_ffs(finished_tags) - 1;
 		if (finished_slot == -1) {
 			break;
 		}
+		prb =  &si_portp->siport_prbpool[finished_slot];
 
 		satapkt = si_portp->siport_slot_pkts[finished_slot];
+		satapkt->satapkt_cmd.satacmd_status_reg =
+						GET_FIS_COMMAND(prb->prb_fis);
+
+		if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs)
+			si_copy_out_regs(&satapkt->satapkt_cmd, &prb->prb_fis);
 
 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_COMPLETED);
 
@@ -5326,3 +5367,30 @@
 	mutex_exit(&si_log_mutex);
 
 }
+
+static void
+si_copy_out_regs(sata_cmd_t *scmd, fis_reg_h2d_t *fisp)
+{
+	fis_reg_h2d_t	fis = *fisp;
+
+	if (scmd->satacmd_flags.sata_copy_out_sec_count_msb)
+		scmd->satacmd_sec_count_msb = GET_FIS_SECTOR_COUNT_EXP(fis);
+	if (scmd->satacmd_flags.sata_copy_out_lba_low_msb)
+		scmd->satacmd_lba_low_msb = GET_FIS_SECTOR_EXP(fis);
+	if (scmd->satacmd_flags.sata_copy_out_lba_mid_msb)
+		scmd->satacmd_lba_mid_msb = GET_FIS_CYL_LOW_EXP(fis);
+	if (scmd->satacmd_flags.sata_copy_out_lba_high_msb)
+		scmd->satacmd_lba_high_msb = GET_FIS_CYL_HI_EXP(fis);
+	if (scmd->satacmd_flags.sata_copy_out_sec_count_lsb)
+		scmd->satacmd_sec_count_lsb = GET_FIS_SECTOR_COUNT(fis);
+	if (scmd->satacmd_flags.sata_copy_out_lba_low_lsb)
+		scmd->satacmd_lba_low_lsb = GET_FIS_SECTOR(fis);
+	if (scmd->satacmd_flags.sata_copy_out_lba_mid_lsb)
+		scmd->satacmd_lba_mid_lsb = GET_FIS_CYL_LOW(fis);
+	if (scmd->satacmd_flags.sata_copy_out_lba_high_lsb)
+		scmd->satacmd_lba_high_lsb = GET_FIS_CYL_HI(fis);
+	if (scmd->satacmd_flags.sata_copy_out_device_reg)
+		scmd->satacmd_device_reg = GET_FIS_DEV_HEAD(fis);
+	if (scmd->satacmd_flags.sata_copy_out_error_reg)
+		scmd->satacmd_error_reg = GET_FIS_FEATURES(fis);
+}
--- a/usr/src/uts/common/io/sata/impl/sata.c	Mon Mar 13 18:04:01 2006 -0800
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Mon Mar 13 18:33:17 2006 -0800
@@ -54,7 +54,6 @@
 #include <sys/sata/sata_cfgadm.h>
 
 
-
 /* Debug flags - defined in sata.h */
 int	sata_debug_flags = 0;
 /*
@@ -193,9 +192,29 @@
 static	int sata_build_msense_page_1c(sata_drive_info_t *, int, uint8_t *);
 static	int sata_mode_select_page_8(sata_pkt_txlate_t *,
     struct mode_cache_scsi3 *, int, int *, int *, int *);
+static	int sata_build_lsense_page_0(sata_drive_info_t *, uint8_t *);
+static	int sata_build_lsense_page_10(sata_drive_info_t *, uint8_t *,
+    sata_hba_inst_t *);
+static	int sata_build_lsense_page_2f(sata_drive_info_t *, uint8_t *,
+    sata_hba_inst_t *);
+static	int sata_build_lsense_page_30(sata_drive_info_t *, uint8_t *,
+    sata_hba_inst_t *);
 static	void sata_save_drive_settings(sata_drive_info_t *);
 static	void sata_show_drive_info(sata_hba_inst_t *, sata_drive_info_t *);
 static	void sata_log(sata_hba_inst_t *, uint_t, char *fmt, ...);
+static int sata_fetch_smart_return_status(sata_hba_inst_t *,
+    sata_drive_info_t *);
+static int sata_fetch_smart_data(sata_hba_inst_t *, sata_drive_info_t *,
+    struct smart_data *);
+static int sata_smart_selftest_log(sata_hba_inst_t *,
+    sata_drive_info_t *,
+    struct smart_selftest_log *);
+static int sata_ext_smart_selftest_read_log(sata_hba_inst_t *,
+    sata_drive_info_t *, struct smart_ext_selftest_log *, uint16_t);
+static	int sata_smart_read_log(sata_hba_inst_t *, sata_drive_info_t *,
+    uint8_t *, uint8_t, uint8_t);
+static	int sata_read_log_ext_directory(sata_hba_inst_t *, sata_drive_info_t *,
+    struct read_log_ext_directory *);
 static	void sata_gen_sysevent(sata_hba_inst_t *, sata_address_t *, int);
 
 /*
@@ -3196,10 +3215,11 @@
 
 	if (spx->txlt_buf_dma_handle != NULL) {
 		if (spx->txlt_sata_pkt != NULL &&
-		    spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags !=
-		    SATA_DIR_NODATA_XFER) {
+		    spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags.
+		    sata_data_direction != SATA_DIR_NODATA_XFER) {
 			rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
-			    (spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags &
+			    (spx->txlt_sata_pkt->satapkt_cmd.
+			    satacmd_flags.sata_data_direction &
 			    SATA_DIR_WRITE) ?
 			    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
 			if (rval == DDI_SUCCESS) {
@@ -3232,6 +3252,10 @@
 {
 	sata_drive_info_t *sdinfo;
 	sata_device_t sata_device;
+	const struct sata_cmd_flags sata_initial_cmd_flags = {
+		SATA_DIR_NODATA_XFER,
+		/* all other values to 0/FALSE */
+	};
 
 	/* Validate address */
 	switch (sata_validate_scsi_address(spx->txlt_sata_hba_inst,
@@ -3273,7 +3297,7 @@
 	 */
 	spx->txlt_sata_pkt->satapkt_device.satadev_type = sdinfo->satadrv_type;
 
-	spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags = SATA_DIR_NODATA_XFER;
+	spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags = sata_initial_cmd_flags;
 
 	spx->txlt_scsi_pkt->pkt_reason = CMD_CMPLT;
 
@@ -3288,12 +3312,12 @@
 	}
 	/* Convert queuing information */
 	if (spx->txlt_scsi_pkt->pkt_flags & FLAG_STAG)
-		spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags |=
-		    SATA_QUEUE_STAG_CMD;
+		spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags.sata_queue_stag =
+		    B_TRUE;
 	else if (spx->txlt_scsi_pkt->pkt_flags &
 	    (FLAG_OTAG | FLAG_HTAG | FLAG_HEAD))
-		spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags |=
-		    SATA_QUEUE_OTAG_CMD;
+		spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags.sata_queue_otag =
+		    B_TRUE;
 
 	/* Always limit pkt time */
 	if (spx->txlt_scsi_pkt->pkt_time == 0)
@@ -3322,6 +3346,9 @@
 	struct scsi_inquiry *inq = (struct scsi_inquiry *)buf;
 	struct sata_id *sid = &sdinfo->satadrv_id;
 
+	/* Start with a nice clean slate */
+	bzero((void *)inq, sizeof (struct scsi_inquiry));
+
 	/* Rely on the dev_type for setting paripheral qualifier */
 	/* Does DTYPE_RODIRECT apply to CD/DVD R/W devices ? */
 	inq->inq_dtype = sdinfo->satadrv_type == SATA_DTYPE_ATADISK ?
@@ -3355,13 +3382,19 @@
 
 #ifdef _LITTLE_ENDIAN
 	/* Swap text fields to match SCSI format */
-	swab(sid->ai_model, inq->inq_vid, 8);		/* Vendor ID */
-	swab(&sid->ai_model[8], inq->inq_pid, 16);	/* Product ID */
-	swab(sid->ai_fw, inq->inq_revision, 8);		/* Revision level */
+	bcopy("ATA     ", inq->inq_vid, 8);		/* Vendor ID */
+	swab(sid->ai_model, inq->inq_pid, 16);		/* Product ID */
+	if (strncmp(&sid->ai_fw[4], "    ", 4) == 0)
+		swab(sid->ai_fw, inq->inq_revision, 4);	/* Revision level */
+	else
+		swab(&sid->ai_fw[4], inq->inq_revision, 4);	/* Rev. level */
 #else
 	bcopy(sid->ai_model, inq->inq_vid, 8);		/* Vendor ID */
 	bcopy(&sid->ai_model[8], inq->inq_pid, 16);	/* Product ID */
-	bcopy(sid->ai_fw, inq->inq_revision, 8);	/* Revision level */
+	if (strncmp(&sid->ai_fw[4], "    ", 4) == 0)
+		bcopy(sid->ai_fw, inq->inq_revision, 4); /* Revision level */
+	else
+		bcopy(&sid->ai_fw[4], inq->inq_revision, 4); /* Rev. level */
 #endif
 }
 
@@ -3498,19 +3531,21 @@
 		if (!(scsipkt->pkt_cdbp[1] & EVPD)) {
 		/* Standard Inquiry Data request */
 			struct scsi_inquiry inq;
-
-			bzero(&inq, sizeof (struct scsi_inquiry));
+			unsigned int bufsize;
+
 			sata_identdev_to_inquiry(spx->txlt_sata_hba_inst,
 			    sdinfo, (uint8_t *)&inq);
 			/* Copy no more than requested */
 			count = MIN(bp->b_bcount,
 			    sizeof (struct scsi_inquiry));
-			count = MIN(count, scsipkt->pkt_cdbp[4]);
+			bufsize = scsipkt->pkt_cdbp[4];
+			bufsize |= scsipkt->pkt_cdbp[3] << 8;
+			count = MIN(count, bufsize);
 			bcopy(&inq, bp->b_un.b_addr, count);
 
 			scsipkt->pkt_state |= STATE_XFERRED_DATA;
 			scsipkt->pkt_resid = scsipkt->pkt_cdbp[4] > count ?
-			    scsipkt->pkt_cdbp[4] - count : 0;
+			    bufsize - count : 0;
 		} else {
 			/*
 			 * peripheral_qualifier = 0;
@@ -4364,17 +4399,209 @@
 
 /*
  * Translate command: Log Sense
- * Not implemented at this time - returns invalid command response.
  */
 static 	int
 sata_txlt_log_sense(sata_pkt_txlate_t *spx)
 {
+	struct scsi_pkt	*scsipkt = spx->txlt_scsi_pkt;
+	struct buf	*bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp;
+	sata_drive_info_t *sdinfo;
+	struct scsi_extended_sense *sense;
+	int 		len, count, alc_len;
+	int		pc;	/* Page Control code */
+	int		page_code;	/* Page code */
+	uint8_t		*buf;	/* log sense buffer */
+	int		rval;
+#define	MAX_LOG_SENSE_PAGE_SIZE	512
+
 	SATADBG2(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
-	    "sata_txlt_log_sense, pc %x, page code %x\n",
+	    "sata_txlt_log_sense, pc 0x%x, page code 0x%x\n",
 	    spx->txlt_scsi_pkt->pkt_cdbp[2] >> 6,
 	    spx->txlt_scsi_pkt->pkt_cdbp[2] & 0x3f);
 
-	return (sata_txlt_invalid_command(spx));
+	buf = kmem_zalloc(MAX_LOG_SENSE_PAGE_SIZE, KM_SLEEP);
+
+	mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
+	if ((rval = sata_txlt_generic_pkt_info(spx)) != TRAN_ACCEPT) {
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		kmem_free(buf, MAX_LOG_SENSE_PAGE_SIZE);
+		return (rval);
+	}
+
+	scsipkt->pkt_reason = CMD_CMPLT;
+	scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+	    STATE_SENT_CMD | STATE_GOT_STATUS;
+
+	pc = scsipkt->pkt_cdbp[2] >> 6;
+	page_code = scsipkt->pkt_cdbp[2] & 0x3f;
+
+	/* Reject not supported request for all but cummulative values */
+	switch (pc) {
+	case PC_CUMMULATIVE_VALUES:
+		break;
+	default:
+		*scsipkt->pkt_scbp = STATUS_CHECK;
+		sense = sata_arq_sense(spx);
+		sense->es_key = KEY_ILLEGAL_REQUEST;
+		sense->es_add_code = SD_SCSI_INVALID_FIELD_IN_CDB;
+		goto done;
+	}
+
+	switch (page_code) {
+	case PAGE_CODE_GET_SUPPORTED_LOG_PAGES:
+	case PAGE_CODE_SELF_TEST_RESULTS:
+	case PAGE_CODE_INFORMATION_EXCEPTIONS:
+	case PAGE_CODE_SMART_READ_DATA:
+		break;
+	default:
+		*scsipkt->pkt_scbp = STATUS_CHECK;
+		sense = sata_arq_sense(spx);
+		sense->es_key = KEY_ILLEGAL_REQUEST;
+		sense->es_add_code = SD_SCSI_INVALID_FIELD_IN_CDB;
+		goto done;
+	}
+
+	if (bp != NULL && bp->b_un.b_addr && bp->b_bcount) {
+		sata_id_t *sata_id;
+		len = 0;
+
+		/* Build log parameter header */
+		buf[len++] = page_code;	/* page code as in the CDB */
+		buf[len++] = 0;		/* reserved */
+		buf[len++] = 0;		/* Zero out page length for now (MSB) */
+		buf[len++] = 0;		/* (LSB) */
+
+		sdinfo = sata_get_device_info(
+		    spx->txlt_sata_hba_inst,
+		    &spx->txlt_sata_pkt->satapkt_device);
+
+
+		/*
+		 * Add requested pages.
+		 */
+		switch (page_code) {
+		case PAGE_CODE_GET_SUPPORTED_LOG_PAGES:
+			len = sata_build_lsense_page_0(sdinfo, buf + len);
+			break;
+		case PAGE_CODE_SELF_TEST_RESULTS:
+			sata_id = &sdinfo->satadrv_id;
+			if ((! (sata_id->ai_cmdset84 &
+			    SATA_SMART_SELF_TEST_SUPPORTED)) ||
+			    (! (sata_id->ai_features87 &
+			    SATA_SMART_SELF_TEST_SUPPORTED))) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ILLEGAL_REQUEST;
+				sense->es_add_code =
+				    SD_SCSI_INVALID_FIELD_IN_CDB;
+
+				goto done;
+			}
+			len = sata_build_lsense_page_10(sdinfo, buf + len,
+			    spx->txlt_sata_hba_inst);
+			break;
+		case PAGE_CODE_INFORMATION_EXCEPTIONS:
+			sata_id = &sdinfo->satadrv_id;
+			if (! (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED)) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ILLEGAL_REQUEST;
+				sense->es_add_code =
+				    SD_SCSI_INVALID_FIELD_IN_CDB;
+
+				goto done;
+			}
+			if (! (sata_id->ai_features85 & SATA_SMART_ENABLED)) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ABORTED_COMMAND;
+				sense->es_add_code =
+				    SCSI_ASC_ATA_DEV_FEAT_NOT_ENABLED;
+				sense->es_qual_code =
+				    SCSI_ASCQ_ATA_DEV_FEAT_NOT_ENABLED;
+
+				goto done;
+			}
+
+			len = sata_build_lsense_page_2f(sdinfo, buf + len,
+			    spx->txlt_sata_hba_inst);
+			break;
+		case PAGE_CODE_SMART_READ_DATA:
+			sata_id = &sdinfo->satadrv_id;
+			if (! (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED)) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ILLEGAL_REQUEST;
+				sense->es_add_code =
+				    SD_SCSI_INVALID_FIELD_IN_CDB;
+
+				goto done;
+			}
+			if (! (sata_id->ai_features85 & SATA_SMART_ENABLED)) {
+				*scsipkt->pkt_scbp = STATUS_CHECK;
+				sense = sata_arq_sense(spx);
+				sense->es_key = KEY_ABORTED_COMMAND;
+				sense->es_add_code =
+				    SCSI_ASC_ATA_DEV_FEAT_NOT_ENABLED;
+				sense->es_qual_code =
+				    SCSI_ASCQ_ATA_DEV_FEAT_NOT_ENABLED;
+
+				goto done;
+			}
+
+			/* This page doesn't include a page header */
+			len = sata_build_lsense_page_30(sdinfo, buf,
+			    spx->txlt_sata_hba_inst);
+			goto no_header;
+		default:
+			/* Invalid request */
+			*scsipkt->pkt_scbp = STATUS_CHECK;
+			sense = sata_arq_sense(spx);
+			sense->es_key = KEY_ILLEGAL_REQUEST;
+			sense->es_add_code = SD_SCSI_INVALID_FIELD_IN_CDB;
+			goto done;
+		}
+
+		/* set parameter log sense data length */
+		buf[2] = len >> 8;	/* log sense length (MSB) */
+		buf[3] = len & 0xff;	/* log sense length (LSB) */
+
+		len += SCSI_LOG_PAGE_HDR_LEN;
+		ASSERT(len <= MAX_LOG_SENSE_PAGE_SIZE);
+
+no_header:
+		/* Check allocation length */
+		alc_len = scsipkt->pkt_cdbp[7];
+		alc_len = (len << 8) | scsipkt->pkt_cdbp[8];
+
+		/*
+		 * We do not check for possible parameters truncation
+		 * (alc_len < len) assuming that the target driver works
+		 * correctly. Just avoiding overrun.
+		 * Copy no more than requested and possible, buffer-wise.
+		 */
+		count = MIN(alc_len, len);
+		count = MIN(bp->b_bcount, count);
+		bcopy(buf, bp->b_un.b_addr, count);
+
+		scsipkt->pkt_state |= STATE_XFERRED_DATA;
+		scsipkt->pkt_resid = alc_len > count ? alc_len - count : 0;
+	}
+	*scsipkt->pkt_scbp = STATUS_GOOD;
+done:
+	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+	(void) kmem_free(buf, MAX_LOG_SENSE_PAGE_SIZE);
+
+	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
+
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+	    scsipkt->pkt_comp != NULL)
+		/* scsi callback required */
+		(*scsipkt->pkt_comp)(scsipkt);
+
+	return (TRAN_ACCEPT);
 }
 
 /*
@@ -4436,8 +4663,7 @@
 	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
 	    &spx->txlt_sata_pkt->satapkt_device);
 
-	scmd->satacmd_flags &= ~SATA_XFER_DIR_MASK;
-	scmd->satacmd_flags |= SATA_DIR_READ;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
 	/*
 	 * Build cmd block depending on the device capability and
 	 * requested operation mode.
@@ -4563,7 +4789,7 @@
 			scmd->satacmd_features_reg =
 			    scmd->satacmd_sec_count_lsb;
 			scmd->satacmd_sec_count_lsb = 0;
-			scmd->satacmd_flags |= SATA_QUEUED_CMD;
+			scmd->satacmd_flags.sata_queued = B_TRUE;
 		}
 	}
 
@@ -4638,8 +4864,7 @@
 	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
 	    &spx->txlt_sata_pkt->satapkt_device);
 
-	scmd->satacmd_flags &= ~SATA_XFER_DIR_MASK;
-	scmd->satacmd_flags |= SATA_DIR_WRITE;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_WRITE;
 	/*
 	 * Build cmd block depending on the device capability and
 	 * requested operation mode.
@@ -4766,7 +4991,7 @@
 			scmd->satacmd_features_reg =
 			    scmd->satacmd_sec_count_lsb;
 			scmd->satacmd_sec_count_lsb = 0;
-			scmd->satacmd_flags |= SATA_QUEUED_CMD;
+			scmd->satacmd_flags.sata_queued = B_TRUE;
 		}
 	}
 
@@ -4834,16 +5059,16 @@
 	}
 
 	/*
-	 * scmd->satacmd_flags default - SATA_DIR_NODATA_XFER - is set by
+	 * scmd->satacmd_flags.sata_data_direction default -
+	 * SATA_DIR_NODATA_XFER - is set by
 	 * sata_txlt_generic_pkt_info().
 	 */
 	if (scmd->satacmd_bp) {
 		if (scmd->satacmd_bp->b_flags & B_READ) {
-			scmd->satacmd_flags &= ~SATA_XFER_DIR_MASK;
-			scmd->satacmd_flags |= SATA_DIR_READ;
+			scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
 		} else {
-			scmd->satacmd_flags &= ~SATA_XFER_DIR_MASK;
-			scmd->satacmd_flags |= SATA_DIR_WRITE;
+			scmd->satacmd_flags.sata_data_direction =
+			    SATA_DIR_WRITE;
 		}
 	}
 
@@ -5003,7 +5228,7 @@
 	sata_drive_info_t *sdinfo;
 	sata_device_t sata_device;
 	uint8_t cmd;
-	uint32_t cmd_flags;
+	struct sata_cmd_flags cmd_flags;
 
 	ASSERT(spx->txlt_sata_pkt != NULL);
 	ASSERT(mutex_owned(&SATA_CPORT_MUTEX(spx->txlt_sata_hba_inst,
@@ -5015,8 +5240,8 @@
 
 	/* Clear device reset state? */
 	if (sdinfo->satadrv_event_flags & SATA_EVNT_CLEAR_DEVICE_RESET) {
-		spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags |=
-		    SATA_CLEAR_DEV_RESET_STATE;
+		spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags.
+		    sata_clear_dev_reset = B_TRUE;
 		sdinfo->satadrv_event_flags &= ~SATA_EVNT_CLEAR_DEVICE_RESET;
 		SATADBG1(SATA_DBG_EVENTS, sata_hba_inst,
 		    "sata_hba_start: clearing device reset state\n", NULL);
@@ -5156,7 +5381,7 @@
 	 * If we got here, the packet was rejected.
 	 * Check if we need to remember reset state clearing request
 	 */
-	if (cmd_flags & SATA_CLEAR_DEV_RESET_STATE) {
+	if (cmd_flags.sata_clear_dev_reset) {
 		/*
 		 * Check if device is still configured - it may have
 		 * disapeared from the configuration
@@ -5359,7 +5584,7 @@
 
 		/*
 		 * SATA_PKT_DEV_ERROR is the only case where we may be able to
-		 * extract form device registers the failing LBA.
+		 * extract from device registers the failing LBA.
 		 */
 		if (sata_pkt->satapkt_reason == SATA_PKT_DEV_ERROR) {
 			if ((scmd->satacmd_addr_type == ATA_ADDR_LBA48) &&
@@ -5802,8 +6027,7 @@
 	 * Need to flip some setting
 	 * Set-up Internal SET FEATURES command(s)
 	 */
-	scmd->satacmd_flags &= ~SATA_XFER_DIR_MASK;
-	scmd->satacmd_flags |= SATA_DIR_NODATA_XFER;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_NODATA_XFER;
 	scmd->satacmd_addr_type = 0;
 	scmd->satacmd_device_reg = 0;
 	scmd->satacmd_status_reg = 0;
@@ -5918,6 +6142,493 @@
 	return (SATA_FAILURE);
 }
 
+/*
+ * sata_build_lsense_page0() is used to create the
+ * SCSI LOG SENSE page 0 (supported log pages)
+ *
+ * Currently supported pages are 0, 0x10, 0x2f and 0x30
+ * (supported log pages, self-test results, informational exceptions
+ *  and Sun vendor specific ATA SMART data).
+ *
+ * Takes a sata_drive_info t * and the address of a buffer
+ * in which to create the page information.
+ *
+ * Returns the number of bytes valid in the buffer.
+ */
+static	int
+sata_build_lsense_page_0(sata_drive_info_t *sdinfo, uint8_t *buf)
+{
+	struct log_parameter *lpp = (struct log_parameter *)buf;
+	uint8_t *page_ptr = (uint8_t *)lpp->param_values;
+	int num_pages_supported = 1; /* Always have GET_SUPPORTED_LOG_PAGES */
+	sata_id_t *sata_id = &sdinfo->satadrv_id;
+
+	lpp->param_code[0] = 0;
+	lpp->param_code[1] = 0;
+	lpp->param_ctrl_flags = LOG_CTRL_LP | LOG_CTRL_LBIN;
+	*page_ptr++ = PAGE_CODE_GET_SUPPORTED_LOG_PAGES;
+
+	if (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED) {
+		if (sata_id->ai_cmdset84 & SATA_SMART_SELF_TEST_SUPPORTED) {
+			*page_ptr++ = PAGE_CODE_SELF_TEST_RESULTS;
+			++num_pages_supported;
+		}
+		*page_ptr++ = PAGE_CODE_INFORMATION_EXCEPTIONS;
+		++num_pages_supported;
+		*page_ptr++ = PAGE_CODE_SMART_READ_DATA;
+		++num_pages_supported;
+	}
+
+	lpp->param_len = num_pages_supported;
+
+	return ((&lpp->param_values[0] - (uint8_t *)lpp) +
+	    num_pages_supported);
+}
+
+/*
+ * sata_build_lsense_page_10() is used to create the
+ * SCSI LOG SENSE page 0x10 (self-test results)
+ *
+ * Takes a sata_drive_info t * and the address of a buffer
+ * in which to create the page information as well as a sata_hba_inst_t *.
+ *
+ * Returns the number of bytes valid in the buffer.
+ */
+static	int
+sata_build_lsense_page_10(
+	sata_drive_info_t *sdinfo,
+	uint8_t *buf,
+	sata_hba_inst_t *sata_hba_inst)
+{
+	struct log_parameter *lpp = (struct log_parameter *)buf;
+	int rval;
+
+	if (sdinfo->satadrv_features_support & SATA_DEV_F_LBA48) {
+		struct smart_ext_selftest_log *ext_selftest_log;
+
+		ext_selftest_log = kmem_zalloc(
+		    sizeof (struct smart_ext_selftest_log), KM_SLEEP);
+
+		rval = sata_ext_smart_selftest_read_log(sata_hba_inst, sdinfo,
+		    ext_selftest_log, 0);
+		if (rval == 0) {
+			int index;
+			struct smart_ext_selftest_log_entry *entry;
+			uint16_t block_num;
+			int count;
+
+			index = ext_selftest_log->
+			    smart_ext_selftest_log_index[0];
+			index |= ext_selftest_log->
+			    smart_ext_selftest_log_index[1] << 8;
+			if (index == 0)
+				goto out;
+
+			--index;	/* Correct for 0 origin */
+			block_num = index / ENTRIES_PER_EXT_SELFTEST_LOG_BLK;
+			if (block_num != 0) {
+				rval = sata_ext_smart_selftest_read_log(
+				    sata_hba_inst, sdinfo, ext_selftest_log,
+				    block_num);
+				if (rval != 0)
+					goto out;
+			}
+			index %= ENTRIES_PER_EXT_SELFTEST_LOG_BLK;
+			entry =
+			    &ext_selftest_log->
+			    smart_ext_selftest_log_entries[index];
+
+			for (count = 1;
+			    count <= SCSI_ENTRIES_IN_LOG_SENSE_SELFTEST_RESULTS;
+			    ++count) {
+				uint8_t status;
+				uint8_t code;
+				uint8_t sense_key;
+				uint8_t add_sense_code;
+				uint8_t add_sense_code_qual;
+
+				lpp->param_code[0] = 0;
+				lpp->param_code[1] = count;
+				lpp->param_ctrl_flags = 0;
+				lpp->param_len =
+				    SCSI_LOG_SENSE_SELFTEST_PARAM_LEN;
+
+				status = entry->smart_ext_selftest_log_status;
+				status >>= 4;
+				switch (status) {
+				case 0:
+				default:
+					sense_key = KEY_NO_SENSE;
+					add_sense_code = SD_SCSI_NO_ADD_SENSE;
+					add_sense_code_qual = 0;
+					break;
+				case 1:
+					sense_key = KEY_ABORTED_COMMAND;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_81;
+					break;
+				case 2:
+					sense_key = KEY_ABORTED_COMMAND;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_82;
+					break;
+				case 3:
+					sense_key = KEY_ABORTED_COMMAND;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_83;
+					break;
+				case 4:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_84;
+					break;
+				case 5:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_85;
+					break;
+				case 6:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_86;
+					break;
+				case 7:
+					sense_key = KEY_MEDIUM_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_87;
+					break;
+				case 8:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_88;
+					break;
+				}
+				code = 0;	/* unspecified */
+				status |= (code << 4);
+				lpp->param_values[0] = status;
+				lpp->param_values[1] = 0; /* unspecified */
+				lpp->param_values[2] = entry->
+				    smart_ext_selftest_log_timestamp[1];
+				lpp->param_values[3] = entry->
+				    smart_ext_selftest_log_timestamp[0];
+				lpp->param_values[4] = 0;
+				lpp->param_values[5] = 0;
+				lpp->param_values[6] = entry->
+				    smart_ext_selftest_log_failing_lba[5];
+				lpp->param_values[7] = entry->
+				    smart_ext_selftest_log_failing_lba[4];
+				lpp->param_values[8] = entry->
+				    smart_ext_selftest_log_failing_lba[3];
+				lpp->param_values[9] = entry->
+				    smart_ext_selftest_log_failing_lba[2];
+				lpp->param_values[10] = entry->
+				    smart_ext_selftest_log_failing_lba[1];
+				lpp->param_values[11] = entry->
+				    smart_ext_selftest_log_failing_lba[0];
+				lpp->param_values[12] = sense_key;
+				lpp->param_values[13] = add_sense_code;
+				lpp->param_values[14] = add_sense_code_qual;
+				lpp->param_values[15] = 0; /* undefined */
+
+				lpp = (struct log_parameter *)
+				    (((uint8_t *)lpp) +
+				    SCSI_LOG_PARAM_HDR_LEN +
+				    SCSI_LOG_SENSE_SELFTEST_PARAM_LEN);
+
+				--index;	/* Back up to previous entry */
+				if (index < 0) {
+					if (block_num > 0) {
+						--block_num;
+					} else {
+						struct read_log_ext_directory
+						    logdir;
+
+						rval =
+						    sata_read_log_ext_directory(
+						    sata_hba_inst, sdinfo,
+						    &logdir);
+						if (rval == -1)
+							goto out;
+						if ((logdir.read_log_ext_vers
+						    [0] == 0) &&
+						    (logdir.read_log_ext_vers
+						    [1] == 0))
+							goto out;
+						block_num =
+						    logdir.read_log_ext_nblks[0]
+						    [EXT_SMART_SELFTEST_LOG_PAGE
+						    - 1];
+						block_num |= logdir.
+						    read_log_ext_nblks[1]
+						    [EXT_SMART_SELFTEST_LOG_PAGE
+						    - 1] << 8;
+						--block_num;
+					}
+					rval = sata_ext_smart_selftest_read_log(
+					    sata_hba_inst, sdinfo,
+					    ext_selftest_log, block_num);
+					if (rval != 0)
+						goto out;
+
+					index =
+					    ENTRIES_PER_EXT_SELFTEST_LOG_BLK -
+					    1;
+				}
+				index %= ENTRIES_PER_EXT_SELFTEST_LOG_BLK;
+				entry = &ext_selftest_log->
+				    smart_ext_selftest_log_entries[index];
+			}
+		}
+out:
+		kmem_free(ext_selftest_log,
+		    sizeof (struct smart_ext_selftest_log));
+	} else {
+		struct smart_selftest_log *selftest_log;
+
+		selftest_log = kmem_zalloc(sizeof (struct smart_selftest_log),
+		    KM_SLEEP);
+
+		rval = sata_smart_selftest_log(sata_hba_inst, sdinfo,
+		    selftest_log);
+
+		if (rval == 0) {
+			int index;
+			int count;
+			struct smart_selftest_log_entry *entry;
+
+			index = selftest_log->smart_selftest_log_index;
+			if (index == 0)
+				goto done;
+			--index;	/* Correct for 0 origin */
+			entry = &selftest_log->
+			    smart_selftest_log_entries[index];
+			for (count = 1;
+			    count <= SCSI_ENTRIES_IN_LOG_SENSE_SELFTEST_RESULTS;
+			    ++count) {
+				uint8_t status;
+				uint8_t code;
+				uint8_t sense_key;
+				uint8_t add_sense_code;
+				uint8_t add_sense_code_qual;
+
+				lpp->param_code[0] = 0;
+				lpp->param_code[1] = count;
+				lpp->param_ctrl_flags = 0;
+				lpp->param_len =
+				    SCSI_LOG_SENSE_SELFTEST_PARAM_LEN;
+
+				status = entry->smart_selftest_log_status;
+				status >>= 4;
+				switch (status) {
+				case 0:
+				default:
+					sense_key = KEY_NO_SENSE;
+					add_sense_code = SD_SCSI_NO_ADD_SENSE;
+					break;
+				case 1:
+					sense_key = KEY_ABORTED_COMMAND;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_81;
+					break;
+				case 2:
+					sense_key = KEY_ABORTED_COMMAND;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_82;
+					break;
+				case 3:
+					sense_key = KEY_ABORTED_COMMAND;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_83;
+					break;
+				case 4:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_84;
+					break;
+				case 5:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_85;
+					break;
+				case 6:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_86;
+					break;
+				case 7:
+					sense_key = KEY_MEDIUM_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_87;
+					break;
+				case 8:
+					sense_key = KEY_HARDWARE_ERROR;
+					add_sense_code =
+					    DIAGNOSTIC_FAILURE_ON_COMPONENT;
+					add_sense_code_qual = SCSI_COMPONENT_88;
+					break;
+				}
+				code = 0;	/* unspecified */
+				status |= (code << 4);
+				lpp->param_values[0] = status;
+				lpp->param_values[1] = 0; /* unspecified */
+				lpp->param_values[2] = entry->
+				    smart_selftest_log_timestamp[1];
+				lpp->param_values[3] = entry->
+				    smart_selftest_log_timestamp[0];
+				lpp->param_values[4] = 0;
+				lpp->param_values[5] = 0;
+				lpp->param_values[6] = 0;
+				lpp->param_values[7] = 0;
+				lpp->param_values[8] = entry->
+				    smart_selftest_log_failing_lba[3];
+				lpp->param_values[9] = entry->
+				    smart_selftest_log_failing_lba[2];
+				lpp->param_values[10] = entry->
+				    smart_selftest_log_failing_lba[1];
+				lpp->param_values[11] = entry->
+				    smart_selftest_log_failing_lba[0];
+				lpp->param_values[12] = sense_key;
+				lpp->param_values[13] = add_sense_code;
+				lpp->param_values[14] = add_sense_code_qual;
+				lpp->param_values[15] = 0; /* undefined */
+
+				lpp = (struct log_parameter *)
+				    (((uint8_t *)lpp) +
+				    SCSI_LOG_PARAM_HDR_LEN +
+				    SCSI_LOG_SENSE_SELFTEST_PARAM_LEN);
+				--index;	/* back up to previous entry */
+				if (index < 0) {
+					index =
+					    NUM_SMART_SELFTEST_LOG_ENTRIES - 1;
+				}
+				entry = &selftest_log->
+					smart_selftest_log_entries[index];
+			}
+		}
+done:
+		kmem_free(selftest_log, sizeof (struct smart_selftest_log));
+	}
+
+	return ((SCSI_LOG_PARAM_HDR_LEN + SCSI_LOG_SENSE_SELFTEST_PARAM_LEN) *
+	    SCSI_ENTRIES_IN_LOG_SENSE_SELFTEST_RESULTS);
+}
+
+/*
+ * sata_build_lsense_page_2f() is used to create the
+ * SCSI LOG SENSE page 0x10 (informational exceptions)
+ *
+ * Takes a sata_drive_info t * and the address of a buffer
+ * in which to create the page information as well as a sata_hba_inst_t *.
+ *
+ * Returns the number of bytes valid in the buffer.
+ */
+static	int
+sata_build_lsense_page_2f(
+	sata_drive_info_t *sdinfo,
+	uint8_t *buf,
+	sata_hba_inst_t *sata_hba_inst)
+{
+	struct log_parameter *lpp = (struct log_parameter *)buf;
+	int rval;
+	uint8_t *smart_data;
+	uint8_t temp;
+	sata_id_t *sata_id;
+#define	SMART_NO_TEMP	0xff
+
+	lpp->param_code[0] = 0;
+	lpp->param_code[1] = 0;
+	lpp->param_ctrl_flags = LOG_CTRL_LP | LOG_CTRL_LBIN;
+
+	/* Now get the SMART status w.r.t. threshold exceeded */
+	rval = sata_fetch_smart_return_status(sata_hba_inst, sdinfo);
+	switch (rval) {
+	case 1:
+		lpp->param_values[0] = SCSI_PREDICTED_FAILURE;
+		lpp->param_values[1] = SCSI_GENERAL_HD_FAILURE;
+		break;
+	case 0:
+	case -1:	/* failed to get data */
+		lpp->param_values[0] = 0;
+		lpp->param_values[1] = 0;
+		break;
+#if defined(SATA_DEBUG)
+	default:
+		cmn_err(CE_PANIC, "sata_build_lsense_page_2f bad return value");
+		/* NOTREACHED */
+#endif
+	}
+
+	sata_id = &sdinfo->satadrv_id;
+	if (! (sata_id->ai_sctsupport & SATA_SCT_CMD_TRANS_SUP))
+		temp = SMART_NO_TEMP;
+	else {
+		/* Now get the temperature */
+		smart_data = kmem_zalloc(512, KM_SLEEP);
+		rval = sata_smart_read_log(sata_hba_inst, sdinfo, smart_data,
+		    SCT_STATUS_LOG_PAGE, 1);
+		if (rval == -1)
+			temp = SMART_NO_TEMP;
+		else {
+			temp = smart_data[200];
+			if (temp & 0x80) {
+				if (temp & 0x7f)
+					temp = 0;
+				else
+					temp = SMART_NO_TEMP;
+			}
+		}
+		kmem_free(smart_data, 512);
+	}
+
+	lpp->param_values[2] = temp;
+
+	lpp->param_len = SCSI_INFO_EXCEPTIONS_PARAM_LEN;
+
+
+	return (SCSI_INFO_EXCEPTIONS_PARAM_LEN + SCSI_LOG_PARAM_HDR_LEN);
+}
+
+/*
+ * sata_build_lsense_page_30() is used to create the
+ * SCSI LOG SENSE page 0x30 (Sun's vendor specific page for ATA SMART data).
+ *
+ * Takes a sata_drive_info t * and the address of a buffer
+ * in which to create the page information as well as a sata_hba_inst_t *.
+ *
+ * Returns the number of bytes valid in the buffer.
+ */
+static int
+sata_build_lsense_page_30(
+	sata_drive_info_t *sdinfo,
+	uint8_t *buf,
+	sata_hba_inst_t *sata_hba_inst)
+{
+	struct smart_data *smart_data = (struct smart_data *)buf;
+	int rval;
+
+	/* Now do the SMART READ DATA */
+	rval = sata_fetch_smart_data(sata_hba_inst, sdinfo, smart_data);
+	if (rval == -1)
+		return (0);
+
+	return (sizeof (struct smart_data));
+}
+
 
 
 
@@ -7197,7 +7908,7 @@
 	    sizeof (sdinfo->satadrv_id.ai_drvser));
 	swab(msg_buf, msg_buf, sizeof (sdinfo->satadrv_id.ai_drvser));
 	msg_buf[sizeof (sdinfo->satadrv_id.ai_drvser)] = '\0';
-	cmn_err(CE_CONT, "?\tserial number %sn", msg_buf);
+	cmn_err(CE_CONT, "?\tserial number %s\n", msg_buf);
 
 #ifdef SATA_DEBUG
 	if (sdinfo->satadrv_id.ai_majorversion != 0 &&
@@ -7230,6 +7941,12 @@
 		    MAXPATHLEN);
 	else if (sdinfo->satadrv_id.ai_cmdset83 & SATA_RW_DMA_QUEUED_CMD)
 		(void) strlcat(msg_buf, ", Queuing", MAXPATHLEN);
+	if ((sdinfo->satadrv_id.ai_cmdset82 & SATA_SMART_SUPPORTED) &&
+	    (sdinfo->satadrv_id.ai_features85 & SATA_SMART_ENABLED))
+		(void) strlcat(msg_buf, ", SMART", MAXPATHLEN);
+	if ((sdinfo->satadrv_id.ai_cmdset84 & SATA_SMART_SELF_TEST_SUPPORTED) &&
+	    (sdinfo->satadrv_id.ai_features87 & SATA_SMART_SELF_TEST_SUPPORTED))
+		(void) strlcat(msg_buf, ", SMART self-test", MAXPATHLEN);
 	cmn_err(CE_CONT, "?\t %s\n", msg_buf);
 	if (sdinfo->satadrv_features_support & SATA_DEV_F_SATA2)
 		cmn_err(CE_CONT, "?\tSATA1 & SATA2 compatible\n");
@@ -7836,7 +8553,8 @@
 
 	scmd = &spkt->satapkt_cmd;
 	scmd->satacmd_bp = bp;
-	scmd->satacmd_flags = SATA_DIR_READ | SATA_IGNORE_DEV_RESET_STATE;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
+	scmd->satacmd_flags.sata_ignore_dev_reset = B_TRUE;
 
 	/* Build Identify Device cmd in the sata_pkt */
 	scmd->satacmd_addr_type = 0;		/* N/A */
@@ -7990,8 +8708,8 @@
 		    SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
 		spkt->satapkt_comp = NULL;
 		scmd = &spkt->satapkt_cmd;
-		scmd->satacmd_flags = SATA_DIR_NODATA_XFER |
-		    SATA_IGNORE_DEV_RESET_STATE;
+		scmd->satacmd_flags.sata_data_direction = SATA_DIR_NODATA_XFER;
+		scmd->satacmd_flags.sata_ignore_dev_reset = B_TRUE;
 		scmd->satacmd_addr_type = 0;
 		scmd->satacmd_device_reg = 0;
 		scmd->satacmd_status_reg = 0;
@@ -9769,8 +10487,8 @@
 	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
 	spkt->satapkt_comp = NULL;
 	scmd = &spkt->satapkt_cmd;
-	scmd->satacmd_flags =
-	    SATA_DIR_NODATA_XFER | SATA_IGNORE_DEV_RESET_STATE;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_NODATA_XFER;
+	scmd->satacmd_flags.sata_ignore_dev_reset = B_TRUE;
 	scmd->satacmd_addr_type = 0;
 	scmd->satacmd_device_reg = 0;
 	scmd->satacmd_status_reg = 0;
@@ -9847,6 +10565,604 @@
 }
 
 
+/*
+ *
+ * Returns 1 if threshold exceeded, 0 if threshold no exceeded, -1 if
+ * unable to determine.
+ *
+ * Cannot be called in an interrupt context.
+ *
+ * Called by sata_build_lsense_page_2f()
+ */
+
+static int
+sata_fetch_smart_return_status(sata_hba_inst_t *sata_hba_inst,
+    sata_drive_info_t *sdinfo)
+{
+	sata_pkt_t *spkt;
+	sata_cmd_t *scmd;
+	sata_pkt_txlate_t *spx;
+	int rval;
+
+	spx = kmem_zalloc(sizeof (sata_pkt_txlate_t), KM_SLEEP);
+	spx->txlt_sata_hba_inst = sata_hba_inst;
+	spx->txlt_scsi_pkt = NULL;		/* No scsi pkt involved */
+	spkt = sata_pkt_alloc(spx, SLEEP_FUNC);
+	if (spkt == NULL) {
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		return (-1);
+	}
+	/* address is needed now */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+
+
+	/* Fill sata_pkt */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
+	/* Synchronous mode, no callback */
+	spkt->satapkt_comp = NULL;
+	/* Timeout 30s */
+	spkt->satapkt_time = sata_default_pkt_time;
+
+	scmd = &spkt->satapkt_cmd;
+	scmd->satacmd_flags.sata_special_regs = B_TRUE;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_NODATA_XFER;
+
+	/* Set up which registers need to be returned */
+	scmd->satacmd_flags.sata_copy_out_lba_mid_lsb = B_TRUE;
+	scmd->satacmd_flags.sata_copy_out_lba_high_lsb = B_TRUE;
+
+	/* Build SMART_RETURN_STATUS cmd in the sata_pkt */
+	scmd->satacmd_addr_type = 0;		/* N/A */
+	scmd->satacmd_sec_count_lsb = 0;	/* N/A */
+	scmd->satacmd_lba_low_lsb = 0;		/* N/A */
+	scmd->satacmd_lba_mid_lsb = SMART_MAGIC_VAL_1;
+	scmd->satacmd_lba_high_lsb = SMART_MAGIC_VAL_2;
+	scmd->satacmd_features_reg = SATA_SMART_RETURN_STATUS;
+	scmd->satacmd_device_reg = 0;		/* Always device 0 */
+	scmd->satacmd_cmd_reg = SATAC_SMART;
+
+	/* Send pkt to SATA HBA driver */
+	if ((*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt) !=
+	    SATA_TRAN_ACCEPTED ||
+	    spkt->satapkt_reason != SATA_PKT_COMPLETED) {
+		/*
+		 * Whoops, no SMART RETURN STATUS
+		 */
+		rval = -1;
+	} else {
+		if (scmd->satacmd_error_reg & SATA_ERROR_ABORT) {
+			rval = -1;
+			goto fail;
+		}
+		if (scmd->satacmd_status_reg & SATA_STATUS_ERR) {
+			rval = -1;
+			goto fail;
+		}
+		if ((scmd->satacmd_lba_mid_lsb == SMART_MAGIC_VAL_1) &&
+		    (scmd->satacmd_lba_high_lsb == SMART_MAGIC_VAL_2))
+			rval = 0;
+		else if ((scmd->satacmd_lba_mid_lsb == SMART_MAGIC_VAL_3) &&
+		    (scmd->satacmd_lba_high_lsb == SMART_MAGIC_VAL_4))
+			rval = 1;
+		else {
+			rval = -1;
+			goto fail;
+		}
+	}
+fail:
+	/* Free allocated resources */
+	sata_pkt_free(spx);
+	kmem_free(spx, sizeof (sata_pkt_txlate_t));
+
+	return (rval);
+}
+
+/*
+ *
+ * Returns 0 if succeeded, -1 otherwise
+ *
+ * Cannot be called in an interrupt context.
+ *
+ */
+static int
+sata_fetch_smart_data(
+	sata_hba_inst_t *sata_hba_inst,
+	sata_drive_info_t *sdinfo,
+	struct smart_data *smart_data)
+{
+	sata_pkt_t *spkt;
+	sata_cmd_t *scmd;
+	sata_pkt_txlate_t *spx;
+	int rval;
+
+#if ! defined(lint)
+	ASSERT(sizeof (struct smart_data) == 512);
+#endif
+
+	spx = kmem_zalloc(sizeof (sata_pkt_txlate_t), KM_SLEEP);
+	spx->txlt_sata_hba_inst = sata_hba_inst;
+	spx->txlt_scsi_pkt = NULL;		/* No scsi pkt involved */
+	spkt = sata_pkt_alloc(spx, SLEEP_FUNC);
+	if (spkt == NULL) {
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		return (-1);
+	}
+	/* address is needed now */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+
+
+	/* Fill sata_pkt */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
+	/* Synchronous mode, no callback */
+	spkt->satapkt_comp = NULL;
+	/* Timeout 30s */
+	spkt->satapkt_time = sata_default_pkt_time;
+
+	scmd = &spkt->satapkt_cmd;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
+
+	/*
+	 * Allocate buffer for SMART data
+	 */
+	scmd->satacmd_bp = sata_alloc_local_buffer(spx,
+	    sizeof (struct smart_data));
+	if (scmd->satacmd_bp == NULL) {
+		sata_pkt_free(spx);
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_fetch_smart_data: "
+		    "cannot allocate buffer"));
+		return (-1);
+	}
+
+
+	/* Build SMART_READ_DATA cmd in the sata_pkt */
+	scmd->satacmd_addr_type = 0;		/* N/A */
+	scmd->satacmd_sec_count_lsb = 0;	/* N/A */
+	scmd->satacmd_lba_low_lsb = 0;		/* N/A */
+	scmd->satacmd_lba_mid_lsb = SMART_MAGIC_VAL_1;
+	scmd->satacmd_lba_high_lsb = SMART_MAGIC_VAL_2;
+	scmd->satacmd_features_reg = SATA_SMART_READ_DATA;
+	scmd->satacmd_device_reg = 0;		/* Always device 0 */
+	scmd->satacmd_cmd_reg = SATAC_SMART;
+
+	/* Send pkt to SATA HBA driver */
+	if ((*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt) !=
+	    SATA_TRAN_ACCEPTED ||
+	    spkt->satapkt_reason != SATA_PKT_COMPLETED) {
+		/*
+		 * Whoops, no SMART DATA available
+		 */
+		rval = -1;
+		goto fail;
+	} else {
+		rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+		if (rval != DDI_SUCCESS) {
+			SATA_LOG_D((spx->txlt_sata_hba_inst, CE_WARN,
+			    "sata_fetch_smart_data: "
+			    "sync pkt failed"));
+			rval = -1;
+			goto fail;
+		}
+		bcopy(scmd->satacmd_bp->b_un.b_addr, (uint8_t *)smart_data,
+		    sizeof (struct smart_data));
+	}
+
+fail:
+	/* Free allocated resources */
+	sata_free_local_buffer(spx);
+	spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp = NULL;
+	sata_pkt_free(spx);
+	kmem_free(spx, sizeof (sata_pkt_txlate_t));
+
+	return (rval);
+}
+
+/*
+ * Used by LOG SENSE page 0x10
+ *
+ * return 0 for success, -1 otherwise
+ *
+ */
+static int
+sata_ext_smart_selftest_read_log(
+	sata_hba_inst_t *sata_hba_inst,
+	sata_drive_info_t *sdinfo,
+	struct smart_ext_selftest_log *ext_selftest_log,
+	uint16_t block_num)
+{
+	sata_pkt_txlate_t *spx;
+	sata_pkt_t *spkt;
+	sata_cmd_t *scmd;
+	int rval;
+
+#if ! defined(lint)
+	ASSERT(sizeof (struct smart_ext_selftest_log) == 512);
+#endif
+
+	spx = kmem_zalloc(sizeof (sata_pkt_txlate_t), KM_SLEEP);
+	spx->txlt_sata_hba_inst = sata_hba_inst;
+	spx->txlt_scsi_pkt = NULL;		/* No scsi pkt involved */
+	spkt = sata_pkt_alloc(spx, SLEEP_FUNC);
+	if (spkt == NULL) {
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		return (-1);
+	}
+	/* address is needed now */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+
+
+	/* Fill sata_pkt */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
+	/* Synchronous mode, no callback */
+	spkt->satapkt_comp = NULL;
+	/* Timeout 30s */
+	spkt->satapkt_time = sata_default_pkt_time;
+
+	scmd = &spkt->satapkt_cmd;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
+
+	/*
+	 * Allocate buffer for SMART extended self-test log
+	 */
+	scmd->satacmd_bp = sata_alloc_local_buffer(spx,
+	    sizeof (struct smart_ext_selftest_log));
+	if (scmd->satacmd_bp == NULL) {
+		sata_pkt_free(spx);
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_ext_smart_selftest_log: "
+		    "cannot allocate buffer"));
+		return (-1);
+	}
+
+	/* Build READ LOG EXT w/ extended self-test log cmd in the sata_pkt */
+	scmd->satacmd_addr_type = ATA_ADDR_LBA48;
+	scmd->satacmd_sec_count_lsb = 1;	/* One sector of selftest log */
+	scmd->satacmd_sec_count_msb = 0;	/* One sector of selftest log */
+	scmd->satacmd_lba_low_lsb = EXT_SMART_SELFTEST_LOG_PAGE;
+	scmd->satacmd_lba_low_msb = 0;
+	scmd->satacmd_lba_mid_lsb = block_num & 0xff;
+	scmd->satacmd_lba_mid_msb = block_num >> 8;
+	scmd->satacmd_device_reg = 0;		/* Always device 0 */
+	scmd->satacmd_cmd_reg = SATAC_READ_LOG_EXT;
+
+	/* Send pkt to SATA HBA driver */
+	if ((*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt) !=
+	    SATA_TRAN_ACCEPTED ||
+	    spkt->satapkt_reason != SATA_PKT_COMPLETED) {
+		/*
+		 * Whoops, no SMART selftest log info available
+		 */
+		rval = -1;
+		goto fail;
+	} else {
+		rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+		if (rval != DDI_SUCCESS) {
+			SATA_LOG_D((spx->txlt_sata_hba_inst, CE_WARN,
+			    "sata_ext_smart_selftest_log: "
+			    "sync pkt failed"));
+			rval = -1;
+			goto fail;
+		}
+		bcopy(scmd->satacmd_bp->b_un.b_addr,
+		    (uint8_t *)ext_selftest_log,
+		    sizeof (struct smart_ext_selftest_log));
+		rval = 0;
+	}
+
+fail:
+	/* Free allocated resources */
+	sata_free_local_buffer(spx);
+	spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp = NULL;
+	sata_pkt_free(spx);
+	kmem_free(spx, sizeof (sata_pkt_txlate_t));
+
+	return (rval);
+}
+
+/*
+ * Returns 0 for success, -1 otherwise
+ *
+ * SMART self-test log data is returned in buffer pointed to by selftest_log
+ */
+static int
+sata_smart_selftest_log(
+	sata_hba_inst_t *sata_hba_inst,
+	sata_drive_info_t *sdinfo,
+	struct smart_selftest_log *selftest_log)
+{
+	sata_pkt_t *spkt;
+	sata_cmd_t *scmd;
+	sata_pkt_txlate_t *spx;
+	int rval;
+
+#if ! defined(lint)
+	ASSERT(sizeof (struct smart_selftest_log) == 512);
+#endif
+
+	spx = kmem_zalloc(sizeof (sata_pkt_txlate_t), KM_SLEEP);
+	spx->txlt_sata_hba_inst = sata_hba_inst;
+	spx->txlt_scsi_pkt = NULL;		/* No scsi pkt involved */
+	spkt = sata_pkt_alloc(spx, SLEEP_FUNC);
+	if (spkt == NULL) {
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		return (-1);
+	}
+	/* address is needed now */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+
+
+	/* Fill sata_pkt */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
+	/* Synchronous mode, no callback */
+	spkt->satapkt_comp = NULL;
+	/* Timeout 30s */
+	spkt->satapkt_time = sata_default_pkt_time;
+
+	scmd = &spkt->satapkt_cmd;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
+
+	/*
+	 * Allocate buffer for Identify Data return data
+	 */
+	scmd->satacmd_bp = sata_alloc_local_buffer(spx,
+	    sizeof (struct smart_selftest_log));
+	if (scmd->satacmd_bp == NULL) {
+		sata_pkt_free(spx);
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_smart_selftest_log: "
+		    "cannot allocate buffer"));
+		return (-1);
+	}
+
+	/* Build SMART_READ_DATA cmd in the sata_pkt */
+	scmd->satacmd_addr_type = 0;		/* N/A */
+	scmd->satacmd_sec_count_lsb = 1;	/* One sector of SMART log */
+	scmd->satacmd_lba_low_lsb = SMART_SELFTEST_LOG_PAGE;
+	scmd->satacmd_lba_mid_lsb = SMART_MAGIC_VAL_1;
+	scmd->satacmd_lba_high_lsb = SMART_MAGIC_VAL_2;
+	scmd->satacmd_features_reg = SATA_SMART_READ_LOG;
+	scmd->satacmd_device_reg = 0;		/* Always device 0 */
+	scmd->satacmd_cmd_reg = SATAC_SMART;
+
+	/* Send pkt to SATA HBA driver */
+	if ((*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt) !=
+	    SATA_TRAN_ACCEPTED ||
+	    spkt->satapkt_reason != SATA_PKT_COMPLETED) {
+		/*
+		 * Whoops, no SMART DATA available
+		 */
+		rval = -1;
+		goto fail;
+	} else {
+		rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+		if (rval != DDI_SUCCESS) {
+			SATA_LOG_D((spx->txlt_sata_hba_inst, CE_WARN,
+			    "sata_smart_selftest_log: "
+			    "sync pkt failed"));
+			rval = -1;
+			goto fail;
+		}
+		bcopy(scmd->satacmd_bp->b_un.b_addr, (uint8_t *)selftest_log,
+		    sizeof (struct smart_selftest_log));
+		rval = 0;
+	}
+
+fail:
+	/* Free allocated resources */
+	sata_free_local_buffer(spx);
+	spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp = NULL;
+	sata_pkt_free(spx);
+	kmem_free(spx, sizeof (sata_pkt_txlate_t));
+
+	return (rval);
+}
+
+
+/*
+ * Returns 0 for success, -1 otherwise
+ *
+ * SMART READ LOG data is returned in buffer pointed to by smart_log
+ */
+static int
+sata_smart_read_log(
+	sata_hba_inst_t *sata_hba_inst,
+	sata_drive_info_t *sdinfo,
+	uint8_t *smart_log,		/* where the data should be returned */
+	uint8_t which_log,		/* which log should be returned */
+	uint8_t log_size)		/* # of 512 bytes in log */
+{
+	sata_pkt_t *spkt;
+	sata_cmd_t *scmd;
+	sata_pkt_txlate_t *spx;
+	int rval;
+
+	spx = kmem_zalloc(sizeof (sata_pkt_txlate_t), KM_SLEEP);
+	spx->txlt_sata_hba_inst = sata_hba_inst;
+	spx->txlt_scsi_pkt = NULL;		/* No scsi pkt involved */
+	spkt = sata_pkt_alloc(spx, SLEEP_FUNC);
+	if (spkt == NULL) {
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		return (-1);
+	}
+	/* address is needed now */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+
+
+	/* Fill sata_pkt */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
+	/* Synchronous mode, no callback */
+	spkt->satapkt_comp = NULL;
+	/* Timeout 30s */
+	spkt->satapkt_time = sata_default_pkt_time;
+
+	scmd = &spkt->satapkt_cmd;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
+
+	/*
+	 * Allocate buffer for SMART READ LOG
+	 */
+	scmd->satacmd_bp = sata_alloc_local_buffer(spx, log_size * 512);
+	if (scmd->satacmd_bp == NULL) {
+		sata_pkt_free(spx);
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_smart_read_log: " "cannot allocate buffer"));
+		return (-1);
+	}
+
+	/* Build SMART_READ_DATA cmd in the sata_pkt */
+	scmd->satacmd_addr_type = 0;		/* N/A */
+	scmd->satacmd_sec_count_lsb = log_size;	/* what the caller asked for */
+	scmd->satacmd_lba_low_lsb = which_log;	/* which log page */
+	scmd->satacmd_lba_mid_lsb = SMART_MAGIC_VAL_1;
+	scmd->satacmd_lba_high_lsb = SMART_MAGIC_VAL_2;
+	scmd->satacmd_features_reg = SATA_SMART_READ_LOG;
+	scmd->satacmd_device_reg = 0;		/* Always device 0 */
+	scmd->satacmd_cmd_reg = SATAC_SMART;
+
+	/* Send pkt to SATA HBA driver */
+	if ((*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt) !=
+	    SATA_TRAN_ACCEPTED ||
+	    spkt->satapkt_reason != SATA_PKT_COMPLETED) {
+		/*
+		 * Whoops, no SMART DATA available
+		 */
+		rval = -1;
+		goto fail;
+	} else {
+		rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+		if (rval != DDI_SUCCESS) {
+			SATA_LOG_D((spx->txlt_sata_hba_inst, CE_WARN,
+			    "sata_smart_read_log: " "sync pkt failed"));
+			rval = -1;
+			goto fail;
+		}
+		bcopy(scmd->satacmd_bp->b_un.b_addr, smart_log, log_size * 512);
+		rval = 0;
+	}
+
+fail:
+	/* Free allocated resources */
+	sata_free_local_buffer(spx);
+	spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp = NULL;
+	sata_pkt_free(spx);
+	kmem_free(spx, sizeof (sata_pkt_txlate_t));
+
+	return (rval);
+}
+
+/*
+ * Used by LOG SENSE page 0x10
+ *
+ * return 0 for success, -1 otherwise
+ *
+ */
+static int
+sata_read_log_ext_directory(
+	sata_hba_inst_t *sata_hba_inst,
+	sata_drive_info_t *sdinfo,
+	struct read_log_ext_directory *logdir)
+{
+	sata_pkt_txlate_t *spx;
+	sata_pkt_t *spkt;
+	sata_cmd_t *scmd;
+	int rval;
+
+#if ! defined(lint)
+	ASSERT(sizeof (struct read_log_ext_directory) == 512);
+#endif
+
+	spx = kmem_zalloc(sizeof (sata_pkt_txlate_t), KM_SLEEP);
+	spx->txlt_sata_hba_inst = sata_hba_inst;
+	spx->txlt_scsi_pkt = NULL;		/* No scsi pkt involved */
+	spkt = sata_pkt_alloc(spx, SLEEP_FUNC);
+	if (spkt == NULL) {
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		return (-1);
+	}
+
+	/* Fill sata_pkt */
+	spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr;
+	spkt->satapkt_op_mode = SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS;
+	/* Synchronous mode, no callback */
+	spkt->satapkt_comp = NULL;
+	/* Timeout 30s */
+	spkt->satapkt_time = sata_default_pkt_time;
+
+	scmd = &spkt->satapkt_cmd;
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ;
+
+	/*
+	 * Allocate buffer for SMART extended self-test log
+	 */
+	scmd->satacmd_bp = sata_alloc_local_buffer(spx,
+	    sizeof (struct read_log_ext_directory));
+	if (scmd->satacmd_bp == NULL) {
+		sata_pkt_free(spx);
+		kmem_free(spx, sizeof (sata_pkt_txlate_t));
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_read_log_ext_directory: "
+		    "cannot allocate buffer"));
+		return (-1);
+	}
+
+	/* Build READ LOG EXT w/ extended self-test log cmd in the sata_pkt */
+	scmd->satacmd_addr_type = ATA_ADDR_LBA48;
+	scmd->satacmd_sec_count_lsb = 1;	/* One sector of directory */
+	scmd->satacmd_sec_count_msb = 0;	/* One sector of directory */
+	scmd->satacmd_lba_low_lsb = READ_LOG_EXT_LOG_DIRECTORY;
+	scmd->satacmd_lba_low_msb = 0;
+	scmd->satacmd_lba_mid_lsb = 0;
+	scmd->satacmd_lba_mid_msb = 0;
+	scmd->satacmd_device_reg = 0;		/* Always device 0 */
+	scmd->satacmd_cmd_reg = SATAC_READ_LOG_EXT;
+
+	/* Send pkt to SATA HBA driver */
+	if ((*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt) !=
+	    SATA_TRAN_ACCEPTED ||
+	    spkt->satapkt_reason != SATA_PKT_COMPLETED) {
+		/*
+		 * Whoops, no SMART selftest log info available
+		 */
+		rval = -1;
+		goto fail;
+	} else {
+		rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
+			DDI_DMA_SYNC_FORKERNEL);
+		if (rval != DDI_SUCCESS) {
+			SATA_LOG_D((spx->txlt_sata_hba_inst, CE_WARN,
+			    "sata_read_log_ext_directory: "
+			    "sync pkt failed"));
+			rval = -1;
+			goto fail;
+		}
+		bcopy(scmd->satacmd_bp->b_un.b_addr, (uint8_t *)logdir,
+		    sizeof (struct read_log_ext_directory));
+		rval = 0;
+	}
+
+fail:
+	/* Free allocated resources */
+	sata_free_local_buffer(spx);
+	spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp = NULL;
+	sata_pkt_free(spx);
+	kmem_free(spx, sizeof (sata_pkt_txlate_t));
+
+	return (rval);
+}
+
 static void
 sata_gen_sysevent(sata_hba_inst_t *sata_hba_inst, sata_address_t *saddr,
     int hint)
--- a/usr/src/uts/common/sys/sata/adapters/si3124/si3124reg.h	Mon Mar 13 18:04:01 2006 -0800
+++ b/usr/src/uts/common/sys/sata/adapters/si3124/si3124reg.h	Mon Mar 13 18:33:17 2006 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -117,6 +117,9 @@
 #define	SET_FIS_DEV_HEAD(fis, dev_head)	\
 	(fis.fish_sector_cyllow_cylhi_devhead |= ((dev_head & 0xff) << 24))
 
+#define	GET_FIS_DEV_HEAD(fis)	\
+	((fis.fish_sector_cyllow_cylhi_devhead >> 24) & 0xff)
+
 
 	/* offset 0x08 */
 	uint32_t fish_sectexp_cyllowexp_cylhiexp_featuresexp;
@@ -125,14 +128,23 @@
 	(fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp |=	\
 		((sectorexp & 0xff)))
 
+#define	GET_FIS_SECTOR_EXP(fis)	\
+	(fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp  & 0xff)
+
 #define	SET_FIS_CYL_LOW_EXP(fis, cyllowexp)			\
 	(fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp |= 	\
 		((cyllowexp & 0xff) << 8))
 
+#define	GET_FIS_CYL_LOW_EXP(fis)			\
+	((fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp >> 8) & 0xff)
+
 #define	SET_FIS_CYL_HI_EXP(fis, cylhiexp)			\
 	(fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp |= 	\
 		((cylhiexp & 0xff) << 16))
 
+#define	GET_FIS_CYL_HI_EXP(fis)			\
+	((fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp >> 16) & 0xff)
+
 #define	SET_FIS_FEATURES_EXP(fis, features_exp)		\
 	(fis.fish_sectexp_cyllowexp_cylhiexp_featuresexp |= 	\
 		((features_exp & 0xff) << 24))
@@ -150,6 +162,9 @@
 	(fis.fish_sectcount_sectcountexp_rsvd_devctl |= \
 		((sector_count_exp & 0xff) << 8))
 
+#define	GET_FIS_SECTOR_COUNT_EXP(fis)	\
+	((fis.fish_sectcount_sectcountexp_rsvd_devctl >> 8) & 0xff)
+
 #define	SET_FIS_SECTOR_DEVCTL(fis, devctl)	\
 	(fis.fish_sectcount_sectcountexp_rsvd_devctl |= ((devctl & 0xff) << 24))
 
--- a/usr/src/uts/common/sys/sata/sata_defs.h	Mon Mar 13 18:04:01 2006 -0800
+++ b/usr/src/uts/common/sys/sata/sata_defs.h	Mon Mar 13 18:33:17 2006 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -84,6 +84,9 @@
 #define	SATAC_WRITE_FPDMA_QUEUED 0x61	/* First-Party-DMA write queued */
 
 #define	SATAC_READ_LOG_EXT	0x2f	/* read log */
+
+#define	SATAC_SMART		0xb0	/* SMART */
+
 #define	SATA_LOG_PAGE_10	0x10	/* log page 0x10 - SATA error */
 /*
  * Power Managment Commands (subset)
@@ -96,6 +99,18 @@
 
 
 /*
+ * SMART FEATURES Subcommands
+ */
+#define	SATA_SMART_READ_DATA		0xd0
+#define	SATA_SMART_ATTR_AUTOSAVE	0xd2
+#define	SATA_SMART_EXECUTE_OFFLINE_IMM	0xd4
+#define	SATA_SMART_READ_LOG		0xd5
+#define	SATA_SMART_WRITE_LOG		0xd6
+#define	SATA_SMART_ENABLE_OPS		0xd8
+#define	SATA_SMART_DISABLE_OPS		0xd9
+#define	SATA_SMART_RETURN_STATUS	0xda
+
+/*
  * SET FEATURES Subcommands
  */
 #define	SATAC_SF_ENABLE_WRITE_CACHE	0x02
@@ -123,72 +138,92 @@
  * Following is the ATA Device Identify data layout
  */
 typedef struct sata_id {
-/*  					WORD				*/
-/* 					OFFSET COMMENT			*/
-	ushort_t  ai_config;	  /*   0  general configuration bits 	*/
-	ushort_t  ai_fixcyls;	  /*   1  # of cylinders (obsolete)	*/
-	ushort_t  ai_resv0;	  /*   2  # reserved			*/
-	ushort_t  ai_heads;	  /*   3  # of heads (obsolete)		*/
-	ushort_t  ai_trksiz;	  /*   4  # of bytes/track (retired)	*/
-	ushort_t  ai_secsiz;	  /*   5  # of bytes/sector (retired)	*/
-	ushort_t  ai_sectors;	  /*   6  # of sectors/track (obsolete)	*/
-	ushort_t  ai_resv1[3];	  /*   7  "Vendor Unique"		*/
-	char	ai_drvser[20];	  /*  10  Serial number			*/
-	ushort_t ai_buftype;	  /*  20  Buffer type			*/
-	ushort_t ai_bufsz;	  /*  21  Buffer size in 512 byte incr  */
-	ushort_t ai_ecc;	  /*  22  # of ecc bytes avail on rd/wr */
-	char	ai_fw[8];	  /*  23  Firmware revision		*/
-	char	ai_model[40];	  /*  27  Model #			*/
-	ushort_t ai_mult1;	  /*  47  Multiple command flags	*/
-	ushort_t ai_dwcap;	  /*  48  Doubleword capabilities	*/
-	ushort_t ai_cap;	  /*  49  Capabilities			*/
-	ushort_t ai_resv2;	  /*  50  Reserved			*/
-	ushort_t ai_piomode;	  /*  51  PIO timing mode		*/
-	ushort_t ai_dmamode;	  /*  52  DMA timing mode		*/
-	ushort_t ai_validinfo;	  /*  53  bit0: wds 54-58, bit1: 64-70	*/
-	ushort_t ai_curcyls;	  /*  54  # of current cylinders	*/
-	ushort_t ai_curheads;	  /*  55  # of current heads		*/
-	ushort_t ai_cursectrk;	  /*  56  # of current sectors/track	*/
-	ushort_t ai_cursccp[2];	  /*  57  current sectors capacity	*/
-	ushort_t ai_mult2;	  /*  59  multiple sectors info		*/
-	ushort_t ai_addrsec[2];	  /*  60  LBA only: no of addr secs	*/
-	ushort_t ai_sworddma;	  /*  62  single word dma modes		*/
-	ushort_t ai_dworddma;	  /*  63  double word dma modes		*/
-	ushort_t ai_advpiomode;	  /*  64  advanced PIO modes supported	*/
-	ushort_t ai_minmwdma;	  /*  65  min multi-word dma cycle info	*/
-	ushort_t ai_recmwdma;	  /*  66  rec multi-word dma cycle info	*/
-	ushort_t ai_minpio;	  /*  67  min PIO cycle info		*/
-	ushort_t ai_minpioflow;	  /*  68  min PIO cycle info w/flow ctl */
-	ushort_t ai_resv3[2];	  /* 69,70 reserved			*/
-	ushort_t ai_typtime[2];	  /* 71-72 timing			*/
-	ushort_t ai_resv4[2];	  /* 73-74 reserved			*/
-	ushort_t ai_qdepth;	  /*  75  queue depth			*/
-	ushort_t ai_satacap;	  /*  76  SATA capabilities		*/
-	ushort_t ai_resv5;	  /*  77 reserved			*/
-	ushort_t ai_satafsup;	  /*  78 SATA features supported	*/
-	ushort_t ai_satafenbl;	  /*  79 SATA features enabled		*/
-	ushort_t ai_majorversion; /*  80  major versions supported	*/
-	ushort_t ai_minorversion; /*  81  minor version number supported */
-	ushort_t ai_cmdset82;	  /*  82  command set supported		*/
-	ushort_t ai_cmdset83;	  /*  83  more command sets supported	*/
-	ushort_t ai_cmdset84;	  /*  84  more command sets supported	*/
-	ushort_t ai_features85;	  /*  85 enabled features		*/
-	ushort_t ai_features86;	  /*  86 enabled features		*/
-	ushort_t ai_features87;	  /*  87 enabled features		*/
-	ushort_t ai_ultradma;	  /*  88 Ultra DMA mode			*/
-	ushort_t ai_erasetime;	  /*  89 security erase time		*/
-	ushort_t ai_erasetimex;	  /*  90 enhanced security erase time	*/
-	ushort_t ai_padding1[9];  /* pad through 99			*/
-	ushort_t ai_addrsecxt[4]; /* 100 extended max LBA sector	*/
-	ushort_t ai_padding2[22]; /* pad to 126				*/
-	ushort_t ai_lastlun;	  /* 126 last LUN, as per SFF-8070i	*/
-	ushort_t ai_resv6;	  /* 127 reserved			*/
-	ushort_t ai_securestatus; /* 128 security status		*/
-	ushort_t ai_vendor[31];	  /* 129-159 vendor specific		*/
-	ushort_t ai_padding3[16]; /* 160 pad to 176			*/
-	ushort_t ai_curmedser[30]; /* 176-205 current media serial number */
-	ushort_t ai_padding4[49]; /* 206 pad to 255			*/
-	ushort_t ai_integrity;	  /* 255 integrity word			*/
+/*  					WORD				  */
+/* 					OFFSET COMMENT			  */
+	ushort_t  ai_config;	   /*   0  general configuration bits	  */
+	ushort_t  ai_fixcyls;	   /*   1  # of cylinders (obsolete)	  */
+	ushort_t  ai_resv0;	   /*   2  # reserved			  */
+	ushort_t  ai_heads;	   /*   3  # of heads (obsolete)	  */
+	ushort_t  ai_trksiz;	   /*   4  # of bytes/track (retired)	  */
+	ushort_t  ai_secsiz;	   /*   5  # of bytes/sector (retired)	  */
+	ushort_t  ai_sectors;	   /*   6  # of sectors/track (obsolete)  */
+	ushort_t  ai_resv1[3];	   /*   7  "Vendor Unique"		  */
+	char	ai_drvser[20];	   /*  10  Serial number		  */
+	ushort_t ai_buftype;	   /*  20  Buffer type			  */
+	ushort_t ai_bufsz;	   /*  21  Buffer size in 512 byte incr   */
+	ushort_t ai_ecc;	   /*  22  # of ecc bytes avail on rd/wr  */
+	char	ai_fw[8];	   /*  23  Firmware revision		  */
+	char	ai_model[40];	   /*  27  Model #			  */
+	ushort_t ai_mult1;	   /*  47  Multiple command flags	  */
+	ushort_t ai_dwcap;	   /*  48  Doubleword capabilities	  */
+	ushort_t ai_cap;	   /*  49  Capabilities			  */
+	ushort_t ai_resv2;	   /*  50  Reserved			  */
+	ushort_t ai_piomode;	   /*  51  PIO timing mode		  */
+	ushort_t ai_dmamode;	   /*  52  DMA timing mode		  */
+	ushort_t ai_validinfo;	   /*  53  bit0: wds 54-58, bit1: 64-70	  */
+	ushort_t ai_curcyls;	   /*  54  # of current cylinders	  */
+	ushort_t ai_curheads;	   /*  55  # of current heads		  */
+	ushort_t ai_cursectrk;	   /*  56  # of current sectors/track	  */
+	ushort_t ai_cursccp[2];	   /*  57  current sectors capacity	  */
+	ushort_t ai_mult2;	   /*  59  multiple sectors info	  */
+	ushort_t ai_addrsec[2];	   /*  60  LBA only: no of addr secs	  */
+	ushort_t ai_sworddma;	   /*  62  single word dma modes	  */
+	ushort_t ai_dworddma;	   /*  63  double word dma modes	  */
+	ushort_t ai_advpiomode;	   /*  64  advanced PIO modes supported	  */
+	ushort_t ai_minmwdma;	   /*  65  min multi-word dma cycle info  */
+	ushort_t ai_recmwdma;	   /*  66  rec multi-word dma cycle info  */
+	ushort_t ai_minpio;	   /*  67  min PIO cycle info		  */
+	ushort_t ai_minpioflow;	   /*  68  min PIO cycle info w/flow ctl  */
+	ushort_t ai_resv3[2];	   /* 69,70 reserved			  */
+	ushort_t ai_typtime[2];	   /* 71-72 timing			  */
+	ushort_t ai_resv4[2];	   /* 73-74 reserved			  */
+	ushort_t ai_qdepth;	   /*  75  queue depth			  */
+	ushort_t ai_satacap;	   /*  76  SATA capabilities		  */
+	ushort_t ai_resv5;	   /*  77 reserved			  */
+	ushort_t ai_satafsup;	   /*  78 SATA features supported	  */
+	ushort_t ai_satafenbl;	   /*  79 SATA features enabled		  */
+	ushort_t ai_majorversion;  /*  80  major versions supported	  */
+	ushort_t ai_minorversion;  /*  81  minor version number supported */
+	ushort_t ai_cmdset82;	   /*  82  command set supported	  */
+	ushort_t ai_cmdset83;	   /*  83  more command sets supported	  */
+	ushort_t ai_cmdset84;	   /*  84  more command sets supported	  */
+	ushort_t ai_features85;	   /*  85 enabled features		  */
+	ushort_t ai_features86;	   /*  86 enabled features		  */
+	ushort_t ai_features87;	   /*  87 enabled features		  */
+	ushort_t ai_ultradma;	   /*  88 Ultra DMA mode		  */
+	ushort_t ai_erasetime;	   /*  89 security erase time		  */
+	ushort_t ai_erasetimex;	   /*  90 enhanced security erase time	  */
+	ushort_t ai_adv_pwr_mgmt;  /*  91 advanced power management time  */
+	ushort_t ai_master_pwd;    /*  92 master password revision code   */
+	ushort_t ai_hrdwre_reset;  /*  93 hardware reset result		  */
+	ushort_t ai_acoustic;	   /*  94 accoustic management values	  */
+	ushort_t ai_stream_min_sz; /*  95 stream minimum request size	  */
+	ushort_t ai_stream_xfer_d; /*  96 streaming transfer time (DMA)   */
+	ushort_t ai_stream_lat;    /*  97 streaming access latency	  */
+	ushort_t ai_streamperf[2]; /* 98-99 streaming performance gran.   */
+	ushort_t ai_addrsecxt[4];  /* 100 extended max LBA sector	  */
+	ushort_t ai_stream_xfer_p; /* 104 streaming transfer time (PIO)   */
+	ushort_t ai_padding1;	   /* 105 pad				  */
+	ushort_t ai_phys_sect_sz;  /* 106 physical sector size		  */
+	ushort_t ai_seek_delay;	   /* 107 inter-seek delay time (usecs)	  */
+	ushort_t ai_naa_ieee_oui;  /* 108 NAA/IEEE OUI			  */
+	ushort_t ai_ieee_oui_uid;  /* 109 IEEE OUT/unique id		  */
+	ushort_t ai_uid_mid;	   /* 110 unique id (mid)		  */
+	ushort_t ai_uid_low;	   /* 111 unique id (low)		  */
+	ushort_t ai_resv_wwn[4];   /* 112-115 reserved for WWN ext.	  */
+	ushort_t ai_incits;	   /* 116 reserved for INCITS TR-37-2004  */
+	ushort_t ai_words_lsec[2]; /* 117-118 words per logical sector	  */
+	ushort_t ai_cmdset119;	   /* 119 more command sets supported	  */
+	ushort_t ai_features120;   /* 120 enabled features		  */
+	ushort_t ai_padding2[6];   /* pad to 126			  */
+	ushort_t ai_rmsn;	   /* 127 removable media notification	  */
+	ushort_t ai_securestatus;  /* 128 security status		  */
+	ushort_t ai_vendor[31];	   /* 129-159 vendor specific		  */
+	ushort_t ai_padding3[16];  /* 160 pad to 176			  */
+	ushort_t ai_curmedser[30]; /* 176-205 current media serial #	  */
+	ushort_t ai_sctsupport;	   /* 206 SCT command transport		  */
+	ushort_t ai_padding4[48];  /* 207 pad to 255			  */
+	ushort_t ai_integrity;	   /* 255 integrity word		  */
 } sata_id_t;
 
 
@@ -228,11 +263,16 @@
 
 /* Identify Device: command set supported/enabled bits - words 82 and 85 */
 
+#define	SATA_SMART_SUPPORTED	0x0001	/* SMART feature set is supported */
 #define	SATA_WRITE_CACHE	0x0020	/* Write Cache supported/enabled */
 #define	SATA_LOOK_AHEAD		0x0040	/* Look Ahead supported/enabled */
 #define	SATA_DEVICE_RESET_CMD	0x0200	/* Device Reset CMD supported/enbld */
 #define	SATA_READ_BUFFER_CMD	0x2000	/* Read Buffer CMD supported/enbld */
 #define	SATA_WRITE_BUFFER_CMD	0x1000	/* Write Buffer CMD supported/enbld */
+#define	SATA_SMART_ENABLED	0x0001	/* SMART feature set is enabled */
+
+/* Identify Device: command set supported/enabled bits - words 84 & 87 */
+#define	SATA_SMART_SELF_TEST_SUPPORTED	0x0002	/* SMART self-test supported */
 
 #define	SATA_MDMA_SEL_MASK	0x0700	/* Multiword DMA selected */
 #define	SATA_MDMA_2_SEL		0x0400	/* Multiword DMA mode 2 selected */
@@ -242,6 +282,16 @@
 #define	SATA_MDMA_1_SUP		0x0002	/* Multiword DMA mode 1 supported */
 #define	SATA_MDMA_0_SUP		0x0001	/* Multiword DMA mode 0 supported */
 
+/* Identify Device: command set supported/enabled bits - word 206 */
+
+/* All are SCT Command Transport support */
+#define	SATA_SCT_CMD_TRANS_SUP		0x0001	/* anything */
+#define	SATA_SCT_CMD_TRANS_LNG_SECT_SUP	0x0002	/* Long Sector Access */
+#define	SATA_SCT_CMD_TRANS_WR_SAME_SUP	0x0004	/* Write Same */
+#define	SATA_SCT_CMD_TRANS_ERR_RCOV_SUP	0x0008	/* Error Recovery Control */
+#define	SATA_SCT_CMD_TRANS_FEAT_CTL_SUP	0x0010	/* Features Control */
+#define	SATA_SCT_CMD_TRANS_DATA_TBL_SUP	0x0020	/* Data Tables supported */
+
 #define	SATA_DISK_SECTOR_SIZE	512	/* HD physical sector size */
 
 /* Identify Packet Device data definitions (ATAPI devices) */
@@ -254,13 +304,13 @@
 #define	SATA_ATAPI_ID_PKT_12B	0x0000  /* Packet size 12 bytes */
 #define	SATA_ATAPI_ID_PKT_16B	0x0001  /* Packet size 16 bytes */
 #define	SATA_ATAPI_ID_DRQ_TYPE	0x0060 	/* DRQ asserted in 3ms after pkt */
-#define	SATA_ATAPI_ID_DRQ_INTR	0x0020 	/* Obsolete in ATA/ATAPI 7 */
+#define	SATA_ATAPI_ID_DRQ_INTR	0x0020  /* Obsolete in ATA/ATAPI 7 */
 
 #define	SATA_ATAPI_ID_DEV_TYPE	0x0f00	/* device type/command set mask */
 #define	SATA_ATAPI_ID_DEV_SHFT	8
 #define	SATA_ATAPI_DIRACC_DEV	0x0000	/* Direct Access device */
-#define	SATA_ATAPI_SQACC_DEV	0x0100	/* Sequential access dev (tape ?) */
-#define	SATA_ATAPI_CDROM_DEV	0x0500	/* CD_ROM device */
+#define	SATA_ATAPI_SQACC_DEV	0x0100  /* Sequential access dev (tape ?) */
+#define	SATA_ATAPI_CDROM_DEV	0x0500  /* CD_ROM device */
 
 /*
  * Status bits from ATAPI Interrupt reason register (AT_COUNT) register
@@ -329,9 +379,152 @@
 #define	SATA_ERROR_EOM		0x02    /* end of media (Packet cmds) */
 #define	SATA_ERROR_ILI		0x01    /* cmd sepcific */
 
+
+/*
+ * Bits from the device control register
+ */
+#define	SATA_DEVCTL_NIEN	0x02	/* not interrupt enabled */
+#define	SATA_DEVCTL_SRST	0x04	/* software reset */
+#define	SATA_DEVCTL_HOB		0x80	/* high order bit */
+
 /* device_reg */
 #define	SATA_ADH_LBA		0x40	/* addressing in LBA mode not chs */
 
+
+#define	SCSI_LOG_PAGE_HDR_LEN	4	/* # bytes of a SCSI log page header */
+#define	SCSI_LOG_PARAM_HDR_LEN	4	/* # byttes of a SCSI log param hdr */
+
+/* Number of log entries per extended selftest log block */
+#define	ENTRIES_PER_EXT_SELFTEST_LOG_BLK	19
+
+/* Number of entries per SCSI LOG SENSE SELFTEST RESULTS page */
+#define	SCSI_ENTRIES_IN_LOG_SENSE_SELFTEST_RESULTS	20
+
+/* Length of a SCSI LOG SENSE SELFTEST RESULTS parameter */
+#define	SCSI_LOG_SENSE_SELFTEST_PARAM_LEN	0x10
+
+#define	DIAGNOSTIC_FAILURE_ON_COMPONENT	0x40
+
+#define	SCSI_COMPONENT_81	0x81
+#define	SCSI_COMPONENT_82	0x82
+#define	SCSI_COMPONENT_83	0x83
+#define	SCSI_COMPONENT_84	0x84
+#define	SCSI_COMPONENT_85	0x85
+#define	SCSI_COMPONENT_86	0x86
+#define	SCSI_COMPONENT_87	0x87
+#define	SCSI_COMPONENT_88	0x88
+
+#define	SCSI_ASC_ATA_DEV_FEAT_NOT_ENABLED	0x67
+#define	SCSI_ASCQ_ATA_DEV_FEAT_NOT_ENABLED	0x0b
+
+#define	SCSI_PREDICTED_FAILURE	0x5d
+#define	SCSI_GENERAL_HD_FAILURE	0x10
+
+#define	SCSI_INFO_EXCEPTIONS_PARAM_LEN	3
+
+#define	READ_LOG_EXT_LOG_DIRECTORY	0
+#define	SMART_SELFTEST_LOG_PAGE		6
+#define	EXT_SMART_SELFTEST_LOG_PAGE	7
+/*
+ * SMART data structures
+ */
+struct smart_data {
+	uint8_t smart_vendor_specific[362];
+	uint8_t smart_offline_data_collection_status;
+	uint8_t smart_selftest_exec_status;
+	uint8_t smart_secs_to_complete_offline_data[2];
+	uint8_t smart_vendor_specific2;
+	uint8_t smart_offline_data_collection_capability;
+	uint8_t smart_capability[2];
+	uint8_t	smart_error_logging_capability;
+	uint8_t smart_vendor_specific3;
+	uint8_t smart_short_selftest_polling_time;
+	uint8_t smart_extended_selftest_polling_time;
+	uint8_t smart_conveyance_selftest_polling_time;
+	uint8_t smart_reserved[11];
+	uint8_t smart_vendor_specific4[125];
+	uint8_t smart_checksum;
+};
+
+struct smart_selftest_log_entry {
+	uint8_t	smart_selftest_log_lba_low;
+	uint8_t	smart_selftest_log_status;
+	uint8_t	smart_selftest_log_timestamp[2];
+	uint8_t smart_selftest_log_checkpoint;
+	uint8_t smart_selftest_log_failing_lba[4];	/* from LSB to MSB */
+	uint8_t smart_selftest_log_vendor_specific[15];
+};
+
+#define	NUM_SMART_SELFTEST_LOG_ENTRIES	21
+struct smart_selftest_log {
+	uint8_t	smart_selftest_log_revision[2];
+	struct	smart_selftest_log_entry
+	    smart_selftest_log_entries[NUM_SMART_SELFTEST_LOG_ENTRIES];
+	uint8_t	smart_selftest_log_vendor_specific[2];
+	uint8_t smart_selftest_log_index;
+	uint8_t smart_selftest_log_reserved[2];
+	uint8_t smart_selftest_log_checksum;
+};
+
+struct smart_ext_selftest_log_entry {
+	uint8_t	smart_ext_selftest_log_lba_low;
+	uint8_t smart_ext_selftest_log_status;
+	uint8_t smart_ext_selftest_log_timestamp[2];
+	uint8_t smart_ext_selftest_log_checkpoint;
+	uint8_t smart_ext_selftest_log_failing_lba[6];
+	uint8_t smart_ext_selftest_log_vendor_specific[15];
+};
+
+struct smart_ext_selftest_log {
+	uint8_t	smart_ext_selftest_log_rev;
+	uint8_t	smart_ext_selftest_log_reserved;
+	uint8_t	smart_ext_selftest_log_index[2];
+	struct smart_ext_selftest_log_entry smart_ext_selftest_log_entries[19];
+	uint8_t	smart_ext_selftest_log_vendor_specific[2];
+	uint8_t	smart_ext_selftest_log_reserved2[11];
+	uint8_t	smart_ext_selftest_log_checksum;
+};
+
+struct read_log_ext_directory {
+	uint8_t	read_log_ext_vers[2];	/* general purpose log version */
+	uint8_t read_log_ext_nblks[2][255]; /* # of blks @ log addr index+1 */
+};
+
+/*
+ * SMART specific data
+ * These eventually need to go to a generic scsi hearder file
+ * for now they will reside here
+ */
+#define	PC_CUMMULATIVE_VALUES			0x01
+#define	PAGE_CODE_GET_SUPPORTED_LOG_PAGES	0x00
+#define	PAGE_CODE_SELF_TEST_RESULTS		0x10
+#define	PAGE_CODE_INFORMATION_EXCEPTIONS	0x2f
+#define	PAGE_CODE_SMART_READ_DATA		0x30
+
+
+struct log_parameter {
+	uint8_t param_code[2];		/* parameter dependant */
+	uint8_t param_ctrl_flags;	/* see defines below */
+	uint8_t param_len;		/* # of bytes following */
+	uint8_t param_values[1];	/* # of bytes defined by param_len */
+};
+
+/* param_ctrl_flag fields */
+#define	LOG_CTRL_LP	0x01	/* list parameter */
+#define	LOG_CTRL_LBIN	0x02	/* list is binary */
+#define	LOG_CTRL_TMC	0x0c	/* threshold met criteria */
+#define	LOG_CTRL_ETC	0x10	/* enable threshold comparison */
+#define	LOG_CTRL_TSD	0x20	/* target save disable */
+#define	LOG_CTRL_DS	0x40	/* disable save */
+#define	LOG_CTRL_DU	0x80	/* disable update */
+
+#define	SMART_MAGIC_VAL_1	0x4f
+#define	SMART_MAGIC_VAL_2	0xc2
+#define	SMART_MAGIC_VAL_3	0xf4
+#define	SMART_MAGIC_VAL_4	0x2c
+
+#define	SCT_STATUS_LOG_PAGE	0xe0
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/sys/sata/sata_hba.h	Mon Mar 13 18:04:01 2006 -0800
+++ b/usr/src/uts/common/sys/sata/sata_hba.h	Mon Mar 13 18:33:17 2006 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -195,7 +195,6 @@
 /* Mask for a port power states */
 #define	SATA_PSTATE_PWR			(SATA_PSTATE_PWRON | \
 					SATA_PSTATE_PWROFF)
-
 /*
  * Device type (in satadev_type field of sata_device structure).
  * More device types may be added in the future.
@@ -285,7 +284,8 @@
  * command block registers (task file registers).
  */
 #define	SATA_CMD_REV_1	1
-#define	SATA_CMD_REV	SATA_CMD_REV_1
+#define	SATA_CMD_REV_2	2
+#define	SATA_CMD_REV	SATA_CMD_REV_2
 
 #define	SATA_ATAPI_MAX_CDB_LEN	16	/* Covers both 12 and 16 byte cdbs */
 #define	SATA_ATAPI_RQSENSE_LEN	24	/* Fixed size Request Sense data */
@@ -293,7 +293,30 @@
 struct sata_cmd {
 	int		satacmd_rev;		/* version */
 	struct buf	*satacmd_bp;		/* ptr to buffer structure */
-	uint32_t	satacmd_flags;		/* transfer direction */
+	struct sata_cmd_flags {
+		uint32_t	sata_data_direction : 3;	 /* 0-2 */
+		uint32_t	: 1;		/* reserved */	 /* 3 */
+		uint32_t	sata_queue_stag : 1;		 /* 4 */
+		uint32_t	sata_queue_otag : 1;		 /* 5 */
+		uint32_t	: 2;		/* reserved */	 /* 6-7 */
+		uint32_t	sata_queued : 1;		 /* 8 */
+		uint32_t	: 3;		/* reserved */	 /* 9-11 */
+		uint32_t	sata_ignore_dev_reset : 1;	 /* 12 */
+		uint32_t	sata_clear_dev_reset : 1;	 /* 13 */
+		uint32_t	: 2;		/* reserved */	 /* 14-15 */
+		uint32_t	sata_special_regs : 1;		 /* 16 */
+		uint32_t	sata_copy_out_sec_count_msb : 1; /* 17 */
+		uint32_t	sata_copy_out_lba_low_msb : 1;	 /* 18 */
+		uint32_t	sata_copy_out_lba_mid_msb : 1;	 /* 19 */
+		uint32_t	sata_copy_out_lba_high_msb : 1;	 /* 20 */
+		uint32_t	sata_copy_out_sec_count_lsb : 1; /* 21 */
+		uint32_t	sata_copy_out_lba_low_lsb : 1;	 /* 22 */
+		uint32_t	sata_copy_out_lba_mid_lsb : 1;	 /* 23 */
+		uint32_t	sata_copy_out_lba_high_lsb : 1;	 /* 24 */
+		uint32_t	sata_copy_out_device_reg : 1;	 /* 25 */
+		uint32_t	sata_copy_out_error_reg : 1;	 /* 26 */
+		uint32_t	: 5;		/* reserved */	 /* 27-31 */
+	} satacmd_flags;
 	uint8_t 	satacmd_addr_type; 	/* addr type: LBA28, LBA48 */
 	uint8_t		satacmd_features_reg_ext; /* features reg extended */
 	uint8_t		satacmd_sec_count_msb;	/* sector count MSB (LBA48) */
@@ -348,15 +371,13 @@
  */
 
 /*
- * Data transfer direction flags (satacmd_flags)
+ * Data transfer direction flags (satacmd_flags.sata_data_direction)
  * Direction flags are mutually exclusive.
  */
 #define	SATA_DIR_NODATA_XFER	0x0001	/* No data transfer */
 #define	SATA_DIR_READ		0x0002	/* Reading data from a device */
 #define	SATA_DIR_WRITE		0x0004	/* Writing data to a device */
 
-#define	SATA_XFER_DIR_MASK	0x0007
-
 /*
  * Tagged Queuing type flags (satacmd_flags).
  * These flags indicate how the SATA command should be queued.