summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/uts/common/io/sata/impl/sata.c318
-rw-r--r--usr/src/uts/common/sys/scsi/generic/mode.h52
2 files changed, 302 insertions, 68 deletions
diff --git a/usr/src/uts/common/io/sata/impl/sata.c b/usr/src/uts/common/io/sata/impl/sata.c
index 6ead816949..4890c56c62 100644
--- a/usr/src/uts/common/io/sata/impl/sata.c
+++ b/usr/src/uts/common/io/sata/impl/sata.c
@@ -192,6 +192,8 @@ static int sata_build_msense_page_1a(sata_drive_info_t *, int, uint8_t *);
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_mode_select_page_1c(sata_pkt_txlate_t *,
+ struct mode_info_excpt_page *, 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 *);
@@ -216,6 +218,7 @@ static int sata_smart_read_log(sata_hba_inst_t *, sata_drive_info_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);
+static void sata_xlate_errors(sata_pkt_txlate_t *);
/*
* SATA Framework will ignore SATA HBA driver cb_ops structure and
@@ -3953,6 +3956,7 @@ sata_txlt_mode_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;
+ sata_id_t *sata_id;
struct scsi_extended_sense *sense;
int len, bdlen, count, alc_len;
int pc; /* Page Control code */
@@ -3980,15 +3984,6 @@ sata_txlt_mode_sense(sata_pkt_txlate_t *spx)
pc = scsipkt->pkt_cdbp[2] >> 6;
- /* Reject not supported request for saved parameters */
- if (pc == 3) {
- *scsipkt->pkt_scbp = STATUS_CHECK;
- sense = sata_arq_sense(spx);
- sense->es_key = KEY_ILLEGAL_REQUEST;
- sense->es_add_code = SD_SCSI_SAVING_PARAMS_NOT_SUP;
- goto done;
- }
-
if (bp != NULL && bp->b_un.b_addr && bp->b_bcount) {
len = 0;
bdlen = 0;
@@ -4079,6 +4074,9 @@ sata_txlt_mode_sense(sata_pkt_txlate_t *spx)
buf[len++] = 0;
}
}
+
+ sata_id = &sdinfo->satadrv_id;
+
/*
* Add requested pages.
* Page 3 and 4 are obsolete and we are not supporting them.
@@ -4099,12 +4097,27 @@ sata_txlt_mode_sense(sata_pkt_txlate_t *spx)
break;
case MODEPAGE_CACHING:
/* DAD_MODE_CACHE */
+ /* Reject not supported request for saved parameters */
+ if (pc == 3) {
+ *scsipkt->pkt_scbp = STATUS_CHECK;
+ sense = sata_arq_sense(spx);
+ sense->es_key = KEY_ILLEGAL_REQUEST;
+ sense->es_add_code =
+ SD_SCSI_SAVING_PARAMS_NOT_SUP;
+ goto done;
+ }
+
/* caching */
len += sata_build_msense_page_8(sdinfo, pc, buf+len);
break;
case MODEPAGE_INFO_EXCPT:
/* exception cntrl */
- len += sata_build_msense_page_1c(sdinfo, pc, buf+len);
+ if (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED) {
+ len += sata_build_msense_page_1c(sdinfo, pc,
+ buf+len);
+ }
+ else
+ goto err;
break;
case MODEPAGE_POWER_COND:
/* DAD_MODE_POWER_COND */
@@ -4116,9 +4129,13 @@ sata_txlt_mode_sense(sata_pkt_txlate_t *spx)
len += sata_build_msense_page_1(sdinfo, pc, buf+len);
len += sata_build_msense_page_8(sdinfo, pc, buf+len);
len += sata_build_msense_page_1a(sdinfo, pc, buf+len);
- len += sata_build_msense_page_1c(sdinfo, pc, buf+len);
+ if (sata_id->ai_cmdset82 & SATA_SMART_SUPPORTED) {
+ len += sata_build_msense_page_1c(sdinfo, pc,
+ buf+len);
+ }
break;
default:
+ err:
/* Invalid request */
*scsipkt->pkt_scbp = STATUS_CHECK;
sense = sata_arq_sense(spx);
@@ -4225,8 +4242,7 @@ sata_txlt_mode_select(sata_pkt_txlate_t *spx)
STATE_SENT_CMD | STATE_GOT_STATUS;
/* Reject not supported request */
- if (! (scsipkt->pkt_cdbp[1] & 0x10) || /* No support for PF bit = 0 */
- (scsipkt->pkt_cdbp[1] & 0x01)) { /* No support for SP (saving) */
+ if (! (scsipkt->pkt_cdbp[1] & 0x10)) { /* No support for PF bit = 0 */
*scsipkt->pkt_scbp = STATUS_CHECK;
sense = sata_arq_sense(spx);
sense->es_key = KEY_ILLEGAL_REQUEST;
@@ -4292,13 +4308,47 @@ sata_txlt_mode_select(sata_pkt_txlate_t *spx)
while (pllen > 0) {
switch ((int)buf[len]) {
case MODEPAGE_CACHING:
+ /* No support for SP (saving) */
+ if (scsipkt->pkt_cdbp[1] & 0x01) {
+ *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;
+ }
stat = sata_mode_select_page_8(spx,
(struct mode_cache_scsi3 *)&buf[len],
pllen, &pagelen, &rval, &dmod);
/*
- * The pagelen value indicates number of
+ * The pagelen value indicates the number of
+ * parameter bytes already processed.
+ * The rval is the return value from
+ * sata_tran_start().
+ * The stat indicates the overall status of
+ * the operation(s).
+ */
+ if (stat != SATA_SUCCESS)
+ /*
+ * Page processing did not succeed -
+ * all error info is already set-up,
+ * just return
+ */
+ pllen = 0; /* this breaks the loop */
+ else {
+ len += pagelen;
+ pllen -= pagelen;
+ }
+ break;
+
+ case MODEPAGE_INFO_EXCPT:
+ stat = sata_mode_select_page_1c(spx,
+ (struct mode_info_excpt_page *)&buf[len],
+ pllen, &pagelen, &rval, &dmod);
+ /*
+ * The pagelen value indicates the number of
* parameter bytes already processed.
- * The rval is return value from
+ * The rval is the return value from
* sata_tran_start().
* The stat indicates the overall status of
* the operation(s).
@@ -5868,6 +5918,9 @@ sata_build_msense_page_8(sata_drive_info_t *sdinfo, int pcntrl, uint8_t *buf)
*/
bzero(buf, PAGELENGTH_DAD_MODE_CACHE_SCSI3);
+ /* Saved paramters not supported */
+ if (pcntrl == 3)
+ return (0);
if (pcntrl == 0 || pcntrl == 2) {
/*
* For now treat current and default parameters as same
@@ -5901,17 +5954,37 @@ sata_build_msense_page_8(sata_drive_info_t *sdinfo, int pcntrl, uint8_t *buf)
/*
* Build Mode sense exception cntrl page
- * NOT IMPLEMENTED
*/
static int
sata_build_msense_page_1c(sata_drive_info_t *sdinfo, int pcntrl, uint8_t *buf)
{
-#ifndef __lock_lint
- _NOTE(ARGUNUSED(sdinfo))
- _NOTE(ARGUNUSED(pcntrl))
- _NOTE(ARGUNUSED(buf))
-#endif
- return (0);
+ struct mode_info_excpt_page *page = (struct mode_info_excpt_page *)buf;
+ sata_id_t *sata_id = &sdinfo->satadrv_id;
+
+ /*
+ * Most of the fields are set to 0, being not supported and/or disabled
+ */
+ bzero(buf, PAGELENGTH_INFO_EXCPT);
+
+ page->mode_page.code = MODEPAGE_INFO_EXCPT;
+ page->mode_page.length = PAGELENGTH_INFO_EXCPT;
+
+ /* Indicate that this is page is saveable */
+ page->mode_page.ps = 1;
+
+ /*
+ * We will return the same data for default, current and saved page.
+ * The only changeable bit is dexcpt and that bit is required
+ * by the ATA specification to be preserved across power cycles.
+ */
+ if (pcntrl != 1) {
+ page->dexcpt = !(sata_id->ai_features85 & SATA_SMART_SUPPORTED);
+ page->mrie = MRIE_ONLY_ON_REQUEST;
+ }
+ else
+ page->dexcpt = 1; /* Only changeable parameter */
+
+ return (PAGELENGTH_INFO_EXCPT + sizeof (struct mode_info_excpt_page));
}
@@ -6090,55 +6163,109 @@ sata_mode_select_page_8(sata_pkt_txlate_t *spx, struct mode_cache_scsi3 *page,
return (SATA_SUCCESS);
failure:
- scsipkt->pkt_reason = CMD_INCOMPLETE;
- *scsipkt->pkt_scbp = STATUS_CHECK;
- sense = sata_arq_sense(spx);
- switch (spx->txlt_sata_pkt->satapkt_reason) {
- case SATA_PKT_PORT_ERROR:
- /*
- * We have no device data. Assume no data transfered.
- */
- sense->es_key = KEY_HARDWARE_ERROR;
- break;
+ sata_xlate_errors(spx);
- case SATA_PKT_DEV_ERROR:
- if (spx->txlt_sata_pkt->satapkt_cmd.satacmd_status_reg &
- SATA_STATUS_ERR) {
- /*
- * determine dev error reason from error
- * reg content
- */
- sata_decode_device_error(spx, sense);
- break;
- }
- /* No extended sense key - no info available */
- break;
+ return (SATA_FAILURE);
+}
- case SATA_PKT_TIMEOUT:
- /*
- * scsipkt->pkt_reason = CMD_TIMEOUT; This causes problems.
- */
- scsipkt->pkt_reason = CMD_INCOMPLETE;
- /* No extended sense key */
- break;
+/*
+ * Process mode select informational exceptions control page 0x1c
+ *
+ * The only changeable bit is dexcpt (disable exceptions).
+ * MRIE (method of reporting informational exceptions) must be
+ * "only on request".
+ *
+ * Return SATA_SUCCESS if operation succeeded, SATA_FAILURE otherwise.
+ * If operation resulted in changing device setup, dmod flag should be set to
+ * one (1). If parameters were not changed, dmod flag should be set to 0.
+ * Upon return, if operation required sending command to the device, the rval
+ * should be set to the value returned by sata_hba_start. If operation
+ * did not require device access, rval should be set to TRAN_ACCEPT.
+ * The pagelen should be set to the length of the page.
+ *
+ * This function has to be called with a port mutex held.
+ *
+ * Returns SATA_SUCCESS if operation was successful, SATA_FAILURE otherwise.
+ */
+static int
+sata_mode_select_page_1c(
+ sata_pkt_txlate_t *spx,
+ struct mode_info_excpt_page *page,
+ int parmlen,
+ int *pagelen,
+ int *rval,
+ int *dmod)
+{
+ struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+ sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd;
+ sata_drive_info_t *sdinfo;
+ sata_id_t *sata_id;
+ struct scsi_extended_sense *sense;
- case SATA_PKT_ABORTED:
- scsipkt->pkt_reason = CMD_ABORTED;
- /* No extended sense key */
- break;
+ sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+ &spx->txlt_sata_pkt->satapkt_device);
+ sata_id = &sdinfo->satadrv_id;
- case SATA_PKT_RESET:
+ *dmod = 0;
+
+ /* Verify parameters length. If too short, drop it */
+ if (((PAGELENGTH_INFO_EXCPT + sizeof (struct mode_page)) < parmlen) ||
+ page->perf || page->test || (page->mrie != MRIE_ONLY_ON_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_PARAMETER_LIST;
+ *pagelen = parmlen;
+ *rval = TRAN_ACCEPT;
+ return (SATA_FAILURE);
+ }
+
+ *pagelen = PAGELENGTH_INFO_EXCPT + sizeof (struct mode_page);
+
+ 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;
+ *pagelen = parmlen;
+ *rval = TRAN_ACCEPT;
+ return (SATA_FAILURE);
+ }
+
+ /* If already in the state requested, we are done */
+ if (page->dexcpt == ! (sata_id->ai_features85 & SATA_SMART_ENABLED)) {
+ /* nothing to do */
+ *rval = TRAN_ACCEPT;
+ return (SATA_SUCCESS);
+ }
+
+ scmd->satacmd_flags.sata_data_direction = SATA_DIR_NODATA_XFER;
+
+ /* Build SMART_ENABLE or SMART_DISABLE command */
+ scmd->satacmd_addr_type = 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 = page->dexcpt ?
+ SATA_SMART_DISABLE_OPS : SATA_SMART_ENABLE_OPS;
+ scmd->satacmd_device_reg = 0; /* Always device 0 */
+ scmd->satacmd_cmd_reg = SATAC_SMART;
+
+ /* Transfer command to HBA */
+ if (sata_hba_start(spx, rval) != 0)
/*
- * pkt aborted either by an explicit reset request from
- * a host, or due to error recovery
+ * Pkt not accepted for execution.
*/
- scsipkt->pkt_reason = CMD_RESET;
- break;
+ return (SATA_FAILURE);
+
+ *dmod = 1; /* At least may have been modified */
+
+ /* Now process return */
+ if (spx->txlt_sata_pkt->satapkt_reason == SATA_PKT_COMPLETED)
+ return (SATA_SUCCESS);
+
+ /* Packet did not complete successfully */
+ sata_xlate_errors(spx);
- default:
- scsipkt->pkt_reason = CMD_TRAN_ERR;
- break;
- }
return (SATA_FAILURE);
}
@@ -11218,3 +11345,66 @@ sata_gen_sysevent(sata_hba_inst_t *sata_hba_inst, sata_address_t *saddr,
nvlist_free(ev_attr_list);
}
+
+/*
+ * sata_xlate_errors() is used to translate (S)ATA error
+ * information to SCSI information returned in the SCSI
+ * packet.
+ */
+static void
+sata_xlate_errors(sata_pkt_txlate_t *spx)
+{
+ struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+ struct scsi_extended_sense *sense;
+
+ scsipkt->pkt_reason = CMD_INCOMPLETE;
+ *scsipkt->pkt_scbp = STATUS_CHECK;
+ sense = sata_arq_sense(spx);
+
+ switch (spx->txlt_sata_pkt->satapkt_reason) {
+ case SATA_PKT_PORT_ERROR:
+ /*
+ * We have no device data. Assume no data transfered.
+ */
+ sense->es_key = KEY_HARDWARE_ERROR;
+ break;
+
+ case SATA_PKT_DEV_ERROR:
+ if (spx->txlt_sata_pkt->satapkt_cmd.satacmd_status_reg &
+ SATA_STATUS_ERR) {
+ /*
+ * determine dev error reason from error
+ * reg content
+ */
+ sata_decode_device_error(spx, sense);
+ break;
+ }
+ /* No extended sense key - no info available */
+ break;
+
+ case SATA_PKT_TIMEOUT:
+ /*
+ * scsipkt->pkt_reason = CMD_TIMEOUT; This causes problems.
+ */
+ scsipkt->pkt_reason = CMD_INCOMPLETE;
+ /* No extended sense key */
+ break;
+
+ case SATA_PKT_ABORTED:
+ scsipkt->pkt_reason = CMD_ABORTED;
+ /* No extended sense key */
+ break;
+
+ case SATA_PKT_RESET:
+ /*
+ * pkt aborted either by an explicit reset request from
+ * a host, or due to error recovery
+ */
+ scsipkt->pkt_reason = CMD_RESET;
+ break;
+
+ default:
+ scsipkt->pkt_reason = CMD_TRAN_ERR;
+ break;
+ }
+}
diff --git a/usr/src/uts/common/sys/scsi/generic/mode.h b/usr/src/uts/common/sys/scsi/generic/mode.h
index 826a8c669e..f54f69a67c 100644
--- a/usr/src/uts/common/sys/scsi/generic/mode.h
+++ b/usr/src/uts/common/sys/scsi/generic/mode.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -342,6 +341,51 @@ struct mode_control_scsi3 {
#define CTRL_QMOD_RESTRICT 0x0
#define CTRL_QMOD_UNRESTRICT 0x1
+/*
+ * Informational Exceptions Control Mode Page
+ */
+
+#define PAGELENGTH_INFO_EXCPT 0x0A
+
+struct mode_info_excpt_page {
+ struct mode_page mode_page; /* common mode page header */
+#if defined(_BIT_FIELDS_LTOH)
+ uchar_t log_err : 1; /* log errors */
+ uchar_t : 1; /* reserved */
+ uchar_t test : 1; /* create test failure */
+ uchar_t dexcpt : 1; /* disable exception */
+ uchar_t ewasc : 1; /* enable warning */
+ uchar_t ebf : 1; /* enable background function */
+ uchar_t : 1; /* reserved */
+ uchar_t perf : 1; /* performance */
+ uchar_t mrie : 4; /* method of reporting info. excpts. */
+ uchar_t : 4; /* reserved */
+#elif defined(_BIT_FIELDS_HTOL)
+ uchar_t perf : 1; /* performance */
+ uchar_t : 1; /* reserved */
+ uchar_t ebf : 1; /* enable background function */
+ uchar_t ewasc : 1; /* enable warning */
+ uchar_t dexcpt : 1; /* disable exception */
+ uchar_t test : 1; /* create test failure */
+ uchar_t : 1; /* reserved */
+ uchar_t log_err : 1; /* log errors */
+ uchar_t : 4; /* reserved */
+ uchar_t mrie : 4; /* method of reporting info. excpts. */
+#else
+#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+ uchar_t interval_timer[4]; /* interval timer */
+ uchar_t report_count[4]; /* report count */
+};
+
+#define MRIE_NO_REPORT 0x0
+#define MRIE_ASYNCH 0x1
+#define MRIE_UNIT_ATTN 0x2
+#define MRIE_COND_RECVD_ERR 0x3
+#define MRIE_UNCOND_RECVD_ERR 0x4
+#define MRIE_NO_SENSE 0x5
+#define MRIE_ONLY_ON_REQUEST 0x6
+
#ifdef __cplusplus
}
#endif