Mercurial > illumos > illumos-gate
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.