Mercurial > illumos > illumos-gate
changeset 11222:5e56af24ae09
6398342 SATA Framework should support ATA PASS THROUGH command
author | Alan Perry <Alan.Perry@Sun.COM> |
---|---|
date | Tue, 01 Dec 2009 17:42:03 -0800 |
parents | b211d0a04b63 |
children | 8fbbe7960a8e |
files | usr/src/uts/common/io/sata/impl/sata.c usr/src/uts/common/sys/sata/impl/sata.h usr/src/uts/common/sys/sata/sata_satl.h usr/src/uts/common/sys/scsi/generic/sense.h |
diffstat | 4 files changed, 591 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c Tue Dec 01 12:24:43 2009 -0800 +++ b/usr/src/uts/common/io/sata/impl/sata.c Tue Dec 01 17:42:03 2009 -0800 @@ -51,6 +51,9 @@ #include <sys/sata/sata_defs.h> #include <sys/sata/sata_cfgadm.h> #include <sys/sata/sata_blacklist.h> +#include <sys/sata/sata_satl.h> + +#include <sys/scsi/impl/spc3_types.h> /* Debug flags - defined in sata.h */ int sata_debug_flags = 0; @@ -205,6 +208,7 @@ static int sata_txlt_log_select(sata_pkt_txlate_t *); static int sata_txlt_mode_sense(sata_pkt_txlate_t *); static int sata_txlt_mode_select(sata_pkt_txlate_t *); +static int sata_txlt_ata_pass_thru(sata_pkt_txlate_t *); static int sata_txlt_synchronize_cache(sata_pkt_txlate_t *); static int sata_txlt_write_buffer(sata_pkt_txlate_t *); static int sata_txlt_nodata_cmd_immediate(sata_pkt_txlate_t *); @@ -213,10 +217,14 @@ static int sata_txlt_invalid_command(sata_pkt_txlate_t *); static int sata_txlt_check_condition(sata_pkt_txlate_t *, uchar_t, uchar_t); static int sata_txlt_lba_out_of_range(sata_pkt_txlate_t *); +static int sata_txlt_ata_pass_thru_illegal_cmd(sata_pkt_txlate_t *); static void sata_txlt_rw_completion(sata_pkt_t *); static void sata_txlt_nodata_cmd_completion(sata_pkt_t *); +static void sata_txlt_apt_completion(sata_pkt_t *sata_pkt); static void sata_txlt_download_mcode_cmd_completion(sata_pkt_t *); static int sata_emul_rw_completion(sata_pkt_txlate_t *); +static void sata_fill_ata_return_desc(sata_pkt_t *, uint8_t, uint8_t, + uint8_t); static struct scsi_extended_sense *sata_immediate_error_response( sata_pkt_txlate_t *, int); static struct scsi_extended_sense *sata_arq_sense(sata_pkt_txlate_t *); @@ -2189,7 +2197,7 @@ * We need to operate with auto request sense enabled. */ pkt = scsi_hba_pkt_alloc(dip, ap, cmdlen, - MAX(statuslen, sizeof (struct scsi_arq_status)), + MAX(statuslen, SATA_MAX_SENSE_LEN), tgtlen, sizeof (sata_pkt_txlate_t), callback, arg); if (pkt == NULL) @@ -2561,6 +2569,13 @@ rval = sata_txlt_nodata_cmd_immediate(spx); break; + case SPC3_CMD_ATA_COMMAND_PASS_THROUGH12: + case SPC3_CMD_ATA_COMMAND_PASS_THROUGH16: + if (bp != NULL && (bp->b_flags & (B_PHYS | B_PAGEIO))) + bp_mapin(bp); + rval = sata_txlt_ata_pass_thru(spx); + break; + /* Other cases will be filed later */ /* postponed until phase 2 of the development */ default: @@ -4910,7 +4925,244 @@ return (rval); } - +/* + * Translate command: ATA Pass Through + * Incomplete implementation. Only supports No-Data, PIO Data-In, and + * PIO Data-Out protocols. Also supports CK_COND bit. + * + * Mapping of the incoming CDB bytes to the outgoing satacmd bytes is + * described in Table 111 of SAT-2 (Draft 9). + */ +static int +sata_txlt_ata_pass_thru(sata_pkt_txlate_t *spx) +{ + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd; + struct buf *bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp; + int extend; + uint64_t lba; + uint16_t feature, sec_count; + int t_len, synch; + int rval, reason; + + mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx))); + + rval = sata_txlt_generic_pkt_info(spx, &reason); + if ((rval != TRAN_ACCEPT) || (reason == CMD_DEV_GONE)) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (rval); + } + + /* T_DIR bit */ + if (scsipkt->pkt_cdbp[2] & SATL_APT_BM_T_DIR) + scmd->satacmd_flags.sata_data_direction = SATA_DIR_READ; + else + scmd->satacmd_flags.sata_data_direction = SATA_DIR_WRITE; + + /* MULTIPLE_COUNT field. If non-zero, invalid command (for now). */ + if (((scsipkt->pkt_cdbp[1] >> 5) & 0x7) != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + } + + /* OFFLINE field. If non-zero, invalid command (for now). */ + if (((scsipkt->pkt_cdbp[2] >> 6) & 0x3) != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + } + + /* PROTOCOL field */ + switch ((scsipkt->pkt_cdbp[1] >> 1) & 0xf) { + case SATL_APT_P_HW_RESET: + case SATL_APT_P_SRST: + case SATL_APT_P_DMA: + case SATL_APT_P_DMA_QUEUED: + case SATL_APT_P_DEV_DIAG: + case SATL_APT_P_DEV_RESET: + case SATL_APT_P_UDMA_IN: + case SATL_APT_P_UDMA_OUT: + case SATL_APT_P_FPDMA: + case SATL_APT_P_RET_RESP: + /* Not yet implemented */ + default: + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + + case SATL_APT_P_NON_DATA: + scmd->satacmd_flags.sata_data_direction = SATA_DIR_NODATA_XFER; + break; + + case SATL_APT_P_PIO_DATA_IN: + /* If PROTOCOL disagrees with T_DIR, invalid command */ + if (scmd->satacmd_flags.sata_data_direction == SATA_DIR_WRITE) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + } + + /* if there is a buffer, release its DMA resources */ + if ((bp != NULL) && bp->b_un.b_addr && bp->b_bcount) { + sata_scsi_dmafree(NULL, scsipkt); + } else { + /* if there is no buffer, how do you PIO in? */ + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + } + + break; + + case SATL_APT_P_PIO_DATA_OUT: + /* If PROTOCOL disagrees with T_DIR, invalid command */ + if (scmd->satacmd_flags.sata_data_direction == SATA_DIR_READ) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + } + + /* if there is a buffer, release its DMA resources */ + if ((bp != NULL) && bp->b_un.b_addr && bp->b_bcount) { + sata_scsi_dmafree(NULL, scsipkt); + } else { + /* if there is no buffer, how do you PIO out? */ + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (sata_txlt_ata_pass_thru_illegal_cmd(spx)); + } + + break; + } + + /* Parse the ATA cmd fields, transfer some straight to the satacmd */ + switch ((uint_t)scsipkt->pkt_cdbp[0]) { + case SPC3_CMD_ATA_COMMAND_PASS_THROUGH12: + feature = scsipkt->pkt_cdbp[3]; + + sec_count = scsipkt->pkt_cdbp[4]; + + lba = scsipkt->pkt_cdbp[8] & 0xf; + lba = (lba << 8) | scsipkt->pkt_cdbp[7]; + lba = (lba << 8) | scsipkt->pkt_cdbp[6]; + lba = (lba << 8) | scsipkt->pkt_cdbp[5]; + + scmd->satacmd_device_reg = scsipkt->pkt_cdbp[13] & 0xf0; + scmd->satacmd_cmd_reg = scsipkt->pkt_cdbp[9]; + + break; + + case SPC3_CMD_ATA_COMMAND_PASS_THROUGH16: + if (scsipkt->pkt_cdbp[1] & SATL_APT_BM_EXTEND) { + extend = 1; + + feature = scsipkt->pkt_cdbp[3]; + feature = (feature << 8) | scsipkt->pkt_cdbp[4]; + + sec_count = scsipkt->pkt_cdbp[5]; + sec_count = (sec_count << 8) | scsipkt->pkt_cdbp[6]; + + lba = scsipkt->pkt_cdbp[11]; + lba = (lba << 8) | scsipkt->pkt_cdbp[12]; + lba = (lba << 8) | scsipkt->pkt_cdbp[9]; + lba = (lba << 8) | scsipkt->pkt_cdbp[10]; + lba = (lba << 8) | scsipkt->pkt_cdbp[7]; + lba = (lba << 8) | scsipkt->pkt_cdbp[8]; + + scmd->satacmd_device_reg = scsipkt->pkt_cdbp[13]; + scmd->satacmd_cmd_reg = scsipkt->pkt_cdbp[14]; + } else { + feature = scsipkt->pkt_cdbp[3]; + + sec_count = scsipkt->pkt_cdbp[5]; + + lba = scsipkt->pkt_cdbp[13] & 0xf; + lba = (lba << 8) | scsipkt->pkt_cdbp[12]; + lba = (lba << 8) | scsipkt->pkt_cdbp[10]; + lba = (lba << 8) | scsipkt->pkt_cdbp[8]; + + scmd->satacmd_device_reg = scsipkt->pkt_cdbp[13] & + 0xf0; + scmd->satacmd_cmd_reg = scsipkt->pkt_cdbp[14]; + } + + break; + } + + /* CK_COND bit */ + if (scsipkt->pkt_cdbp[2] & SATL_APT_BM_CK_COND) { + if (extend) { + scmd->satacmd_flags.sata_copy_out_sec_count_msb = 1; + scmd->satacmd_flags.sata_copy_out_lba_low_msb = 1; + scmd->satacmd_flags.sata_copy_out_lba_mid_msb = 1; + scmd->satacmd_flags.sata_copy_out_lba_high_msb = 1; + } + + scmd->satacmd_flags.sata_copy_out_sec_count_lsb = 1; + scmd->satacmd_flags.sata_copy_out_lba_low_lsb = 1; + scmd->satacmd_flags.sata_copy_out_lba_mid_lsb = 1; + scmd->satacmd_flags.sata_copy_out_lba_high_lsb = 1; + scmd->satacmd_flags.sata_copy_out_device_reg = 1; + scmd->satacmd_flags.sata_copy_out_error_reg = 1; + } + + /* Transfer remaining parsed ATA cmd values to the satacmd */ + if (extend) { + scmd->satacmd_addr_type = ATA_ADDR_LBA48; + + scmd->satacmd_features_reg_ext = (feature >> 8) & 0xff; + scmd->satacmd_sec_count_msb = (sec_count >> 8) & 0xff; + scmd->satacmd_lba_low_msb = (lba >> 8) & 0xff; + scmd->satacmd_lba_mid_msb = (lba >> 8) & 0xff; + scmd->satacmd_lba_high_msb = lba >> 40; + } else { + scmd->satacmd_addr_type = ATA_ADDR_LBA28; + + scmd->satacmd_features_reg_ext = 0; + scmd->satacmd_sec_count_msb = 0; + scmd->satacmd_lba_low_msb = 0; + scmd->satacmd_lba_mid_msb = 0; + scmd->satacmd_lba_high_msb = 0; + } + + scmd->satacmd_features_reg = feature & 0xff; + scmd->satacmd_sec_count_lsb = sec_count & 0xff; + scmd->satacmd_lba_low_lsb = lba & 0xff; + scmd->satacmd_lba_mid_lsb = (lba >> 8) & 0xff; + scmd->satacmd_lba_high_lsb = (lba >> 16) & 0xff; + + /* Determine transfer length */ + switch (scsipkt->pkt_cdbp[2] & 0x3) { /* T_LENGTH field */ + case 1: + t_len = feature; + break; + case 2: + t_len = sec_count; + break; + default: + t_len = 0; + break; + } + + /* Adjust transfer length for the Byte Block bit */ + if ((scsipkt->pkt_cdbp[2] >> 2) & 1) + t_len *= SATA_DISK_SECTOR_SIZE; + + /* Start processing command */ + if (!(spx->txlt_sata_pkt->satapkt_op_mode & SATA_OPMODE_SYNCH)) { + spx->txlt_sata_pkt->satapkt_comp = sata_txlt_apt_completion; + synch = FALSE; + } else { + synch = TRUE; + } + + if (sata_hba_start(spx, &rval) != 0) { + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + return (rval); + } + + mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx))); + + if (synch) { + sata_txlt_apt_completion(spx->txlt_sata_pkt); + } + + return (TRAN_ACCEPT); +} /* * Translate command: Log Sense @@ -6430,6 +6682,39 @@ return (sense); } +/* + * ATA Pass Through support + * Sets flags indicating that an invalid value was found in some + * field in the command. It could be something illegal according to + * the SAT-2 spec or it could be a feature that is not (yet?) + * supported. + */ +static int +sata_txlt_ata_pass_thru_illegal_cmd(sata_pkt_txlate_t *spx) +{ + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + struct scsi_extended_sense *sense = sata_arq_sense(spx); + + scsipkt->pkt_reason = CMD_CMPLT; + *scsipkt->pkt_scbp = STATUS_CHECK; + scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS; + + sense = sata_arq_sense(spx); + sense->es_key = KEY_ILLEGAL_REQUEST; + sense->es_add_code = SD_SCSI_ASC_INVALID_FIELD_IN_CDB; + + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 && + scsipkt->pkt_comp != NULL) + /* scsi callback required */ + if (taskq_dispatch(SATA_TXLT_TASKQ(spx), + (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt, + TQ_SLEEP) == NULL) + /* Scheduling the callback failed */ + return (TRAN_BUSY); + + return (TRAN_ACCEPT); +} /* * Emulated SATA Read/Write command completion for zero-length requests. @@ -6649,6 +6934,180 @@ scsi_hba_pkt_comp(scsipkt); } +/* + * Completion handler for ATA Pass Through command + */ +static void +sata_txlt_apt_completion(sata_pkt_t *sata_pkt) +{ + sata_pkt_txlate_t *spx = + (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private; + sata_cmd_t *scmd = &sata_pkt->satapkt_cmd; + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + struct buf *bp; + uint8_t sense_key = 0, addl_sense_code = 0, addl_sense_qual = 0; + + if (sata_pkt->satapkt_reason == SATA_PKT_COMPLETED) { + /* Normal completion */ + scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS; + scsipkt->pkt_reason = CMD_CMPLT; + *scsipkt->pkt_scbp = STATUS_GOOD; + + /* + * If the command has CK_COND set + */ + if (scsipkt->pkt_cdbp[2] & SATL_APT_BM_CK_COND) { + *scsipkt->pkt_scbp = STATUS_CHECK; + sata_fill_ata_return_desc(sata_pkt, + KEY_RECOVERABLE_ERROR, + SD_SCSI_ASC_ATP_INFO_AVAIL, 0); + } + + if (spx->txlt_tmp_buf != NULL) { + /* Temporary buffer was used */ + bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp; + if (bp->b_flags & B_READ) { + bcopy(spx->txlt_tmp_buf, bp->b_un.b_addr, + bp->b_bcount); + } + } + } else { + scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS; + scsipkt->pkt_reason = CMD_INCOMPLETE; + *scsipkt->pkt_scbp = STATUS_CHECK; + + /* + * If DF or ERR was set, the HBA should have copied out the + * status and error registers to the satacmd structure. + */ + if (scmd->satacmd_status_reg & SATA_STATUS_DF) { + sense_key = KEY_HARDWARE_ERROR; + addl_sense_code = SD_SCSI_ASC_INTERNAL_TARGET_FAILURE; + addl_sense_qual = 0; + } else if (scmd->satacmd_status_reg & SATA_STATUS_ERR) { + if (scmd->satacmd_error_reg & SATA_ERROR_NM) { + sense_key = KEY_NOT_READY; + addl_sense_code = + SD_SCSI_ASC_MEDIUM_NOT_PRESENT; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_UNC) { + sense_key = KEY_MEDIUM_ERROR; + addl_sense_code = SD_SCSI_ASC_UNREC_READ_ERR; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_ILI) { + sense_key = KEY_DATA_PROTECT; + addl_sense_code = SD_SCSI_ASC_WRITE_PROTECTED; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_IDNF) { + sense_key = KEY_ILLEGAL_REQUEST; + addl_sense_code = SD_SCSI_ASC_LBA_OUT_OF_RANGE; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_ABORT) { + sense_key = KEY_ABORTED_COMMAND; + addl_sense_code = SD_SCSI_ASC_NO_ADD_SENSE; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_MC) { + sense_key = KEY_UNIT_ATTENTION; + addl_sense_code = + SD_SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_MCR) { + sense_key = KEY_UNIT_ATTENTION; + addl_sense_code = SD_SCSI_ASC_OP_MEDIUM_REM_REQ; + addl_sense_qual = 0; + } else if (scmd->satacmd_error_reg & SATA_ERROR_ICRC) { + sense_key = KEY_ABORTED_COMMAND; + addl_sense_code = + SD_SCSI_ASC_INFO_UNIT_IUCRC_ERR; + addl_sense_qual = 0; + } + } + + sata_fill_ata_return_desc(sata_pkt, sense_key, addl_sense_code, + addl_sense_qual); + } + + if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) + /* scsi callback required */ + scsi_hba_pkt_comp(scsipkt); +} + +/* + * j + */ +static void +sata_fill_ata_return_desc(sata_pkt_t *sata_pkt, uint8_t sense_key, + uint8_t addl_sense_code, uint8_t addl_sense_qual) +{ + sata_pkt_txlate_t *spx = + (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private; + sata_cmd_t *scmd = &sata_pkt->satapkt_cmd; + struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt; + struct sata_apt_sense_data *apt_sd = + (struct sata_apt_sense_data *)scsipkt->pkt_scbp; + struct scsi_descr_sense_hdr *sds = &(apt_sd->apt_sd_hdr); + struct scsi_ata_status_ret_sense_descr *ata_ret_desc = + &(apt_sd->apt_sd_sense); + int extend = 0; + + if ((scsipkt->pkt_cdbp[0] == SPC3_CMD_ATA_COMMAND_PASS_THROUGH16) && + (scsipkt->pkt_cdbp[2] & SATL_APT_BM_EXTEND)) + extend = 1; + + scsipkt->pkt_state |= STATE_ARQ_DONE; + + /* update the residual count */ + *(uchar_t *)&apt_sd->apt_status = STATUS_CHECK; + *(uchar_t *)&apt_sd->apt_rqpkt_status = STATUS_GOOD; + apt_sd->apt_rqpkt_reason = CMD_CMPLT; + apt_sd->apt_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_XFERRED_DATA | STATE_SENT_CMD | STATE_GOT_STATUS; + apt_sd->apt_rqpkt_resid = scsipkt->pkt_scblen - + sizeof (struct sata_apt_sense_data); + + /* + * Fill in the Descriptor sense header + */ + bzero(sds, sizeof (struct scsi_descr_sense_hdr)); + sds->ds_code = CODE_FMT_DESCR_CURRENT; + sds->ds_class = CLASS_EXTENDED_SENSE; + sds->ds_key = sense_key & 0xf; + sds->ds_add_code = addl_sense_code; + sds->ds_qual_code = addl_sense_qual; + sds->ds_addl_sense_length = + sizeof (struct scsi_ata_status_ret_sense_descr); + + /* + * Fill in the ATA Return descriptor sense data + */ + bzero(ata_ret_desc, sizeof (struct scsi_ata_status_ret_sense_descr)); + ata_ret_desc->ars_descr_type = DESCR_ATA_STATUS_RETURN; + ata_ret_desc->ars_addl_length = 0xc; + ata_ret_desc->ars_error = scmd->satacmd_error_reg; + ata_ret_desc->ars_sec_count_lsb = scmd->satacmd_sec_count_lsb; + ata_ret_desc->ars_lba_low_lsb = scmd->satacmd_lba_low_lsb; + ata_ret_desc->ars_lba_mid_lsb = scmd->satacmd_lba_mid_lsb; + ata_ret_desc->ars_lba_high_lsb = scmd->satacmd_lba_high_lsb; + ata_ret_desc->ars_device = scmd->satacmd_device_reg; + ata_ret_desc->ars_status = scmd->satacmd_status_reg; + + if (extend == 1) { + ata_ret_desc->ars_extend = 1; + ata_ret_desc->ars_sec_count_msb = scmd->satacmd_sec_count_msb; + ata_ret_desc->ars_lba_low_msb = scmd->satacmd_lba_low_msb; + ata_ret_desc->ars_lba_mid_msb = scmd->satacmd_lba_mid_msb; + ata_ret_desc->ars_lba_high_msb = scmd->satacmd_lba_high_msb; + } else { + ata_ret_desc->ars_extend = 0; + ata_ret_desc->ars_sec_count_msb = 0; + ata_ret_desc->ars_lba_low_msb = 0; + ata_ret_desc->ars_lba_mid_msb = 0; + ata_ret_desc->ars_lba_high_msb = 0; + } +} + static void sata_set_arq_data(sata_pkt_t *sata_pkt) {
--- a/usr/src/uts/common/sys/sata/impl/sata.h Tue Dec 01 12:24:43 2009 -0800 +++ b/usr/src/uts/common/sys/sata/impl/sata.h Tue Dec 01 17:42:03 2009 -0800 @@ -483,6 +483,30 @@ _NOTE(SCHEME_PROTECTS_DATA("unshared data", sata_pkt_txlate)) _NOTE(SCHEME_PROTECTS_DATA("unshared data", scsi_pkt)) +/* Length of largest sense buffer used by sata */ +#define SATA_MAX_SENSE_LEN MAX(sizeof (struct scsi_arq_status), \ + sizeof (struct scsi_arq_status) - sizeof (struct scsi_extended_sense) + \ + sizeof (struct scsi_descr_sense_hdr) + \ + MAX(sizeof (struct scsi_cmd_specific_sense_descr), \ + sizeof (struct scsi_ata_status_ret_sense_descr))) + +/* + * Sense Data structure for ATA Pass Through + * This is the entire sense data block passed back up to scsi. It is + * effectively the scsi_arq_status structure for ATA Sense Return descriptor + * format sense data. + */ +struct sata_apt_sense_data { + struct scsi_status apt_status; + struct scsi_status apt_rqpkt_status; + uchar_t apt_rqpkt_reason; + uchar_t apt_rqpkt_resid; + uint_t apt_rqpkt_state; + uint_t apt_rqpkt_statistics; + struct scsi_descr_sense_hdr apt_sd_hdr; + struct scsi_ata_status_ret_sense_descr apt_sd_sense; +}; + /* * Additional scsi sense code definitions. @@ -490,18 +514,25 @@ * usr/src/uts/common/sys/scsi/generic/sense.h */ #define SD_SCSI_ASC_NO_ADD_SENSE 0x00 +#define SD_SCSI_ASC_ATP_INFO_AVAIL 0x00 #define SD_SCSI_ASC_LU_NOT_READY 0x04 +#define SD_SCSI_ASC_LU_NOT_RESPONSE 0x05 #define SD_SCSI_ASC_WRITE_ERR 0x0c #define SD_SCSI_ASC_UNREC_READ_ERR 0x11 #define SD_SCSI_ASC_INVALID_COMMAND_CODE 0x20 #define SD_SCSI_ASC_LBA_OUT_OF_RANGE 0x21 #define SD_SCSI_ASC_INVALID_FIELD_IN_CDB 0x24 #define SD_SCSI_ASC_INVALID_FIELD_IN_PARAMS_LIST 0x26 +#define SD_SCSI_ASC_WRITE_PROTECTED 0x27 +#define SD_SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 #define SD_SCSI_ASC_RESET 0x29 -#define SD_SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 #define SD_SCSI_ASC_CMD_SEQUENCE_ERR 0x2c +#define SD_SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a +#define SD_SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SD_SCSI_ASC_INTERNAL_TARGET_FAILURE 0x44 +#define SD_SCSI_ASC_INFO_UNIT_IUCRC_ERR 0x47 +#define SD_SCSI_ASC_OP_MEDIUM_REM_REQ 0x5a #define SD_SCSI_ASC_LOW_POWER_CONDITION_ON 0x5e -#define SD_SCSI_ASC_LU_NOT_RESPONSE 0x05 /* SCSI defs missing from scsi headers */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/sata/sata_satl.h Tue Dec 01 17:42:03 2009 -0800 @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SATA_SATL_H +#define _SATA_SATL_H + +#include <sys/scsi/impl/spc3_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Definitions and declarations + * ANSI SCSI / ATA Translation - 2 (SAT-2) specification + */ + +/* + * SATL ATA Pass Through PROTOCOL field values + */ +#define SATL_APT_P_HW_RESET 0 /* ATA hardware reset */ +#define SATL_APT_P_SRST 0x1 /* Software reset */ +#define SATL_APT_P_NON_DATA 0x3 /* Non-data */ +#define SATL_APT_P_PIO_DATA_IN 0x4 /* PIO Data-in */ +#define SATL_APT_P_PIO_DATA_OUT 0x5 /* PIO Data-out */ +#define SATL_APT_P_DMA 0x6 /* DMA */ +#define SATL_APT_P_DMA_QUEUED 0x7 /* DMA Queued */ +#define SATL_APT_P_DEV_DIAG 0x8 /* Device Diagnostics */ +#define SATL_APT_P_DEV_RESET 0x9 /* Device Reset */ +#define SATL_APT_P_UDMA_IN 0xa /* UDMA Data In */ +#define SATL_APT_P_UDMA_OUT 0xb /* UDMA Data Out */ +#define SATL_APT_P_FPDMA 0xc /* FPDMA */ +#define SATL_APT_P_RET_RESP 0xf /* Return Response Info */ + +/* + * SATL ATA Pass Through bit masks + */ +#define SATL_APT_BM_EXTEND 0x01 +#define SATL_APT_BM_CK_COND 0x20 +#define SATL_APT_BM_T_DIR 0x08 +#define SATL_APT_BM_BYTE_BLOCK 0x04 + +#ifdef __cplusplus +} +#endif + +#endif /* _SATA_SATL_H */
--- a/usr/src/uts/common/sys/scsi/generic/sense.h Tue Dec 01 12:24:43 2009 -0800 +++ b/usr/src/uts/common/sys/scsi/generic/sense.h Tue Dec 01 17:42:03 2009 -0800 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SCSI_GENERIC_SENSE_H #define _SYS_SCSI_GENERIC_SENSE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -345,6 +343,31 @@ #endif /* _BIT_FIELDS_LTOH */ }; +struct scsi_ata_status_ret_sense_descr { + uchar_t ars_descr_type; /* Descriptor type (0x09) */ + uchar_t ars_addl_length; /* Additional byte count (0x0c) */ +#if defined(_BIT_FIELDS_LTOH) + uchar_t ars_extend : 1, + ars_reserved1 : 7; /* reserved */ +#elif defined(_BIT_FIELDS_HTOL) + uchar_t ars_reserved1 : 7, /* reserved */ + ars_extend : 1; +#else +#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined +#endif /* _BIT_FIELDS_LTOH */ + uchar_t ars_error; + uchar_t ars_sec_count_msb; + uchar_t ars_sec_count_lsb; + uchar_t ars_lba_low_msb; + uchar_t ars_lba_low_lsb; + uchar_t ars_lba_mid_msb; + uchar_t ars_lba_mid_lsb; + uchar_t ars_lba_high_msb; + uchar_t ars_lba_high_lsb; + uchar_t ars_device; + uchar_t ars_status; +}; + struct scsi_vendor_specific_sense_descr { uchar_t vss_descr_type; /* Descriptor type (0x80-0xFF) */ uchar_t vss_addl_length; /* Additional byte count */ @@ -366,6 +389,7 @@ #define DESCR_OSD_OID 0x06 #define DESCR_OSD_RESP_INTEGRITY 0x07 #define DESCR_OSD_ATTR_ID 0x08 +#define DESCR_ATA_STATUS_RETURN 0x09 #ifdef __cplusplus }