Mercurial > illumos > illumos-gate
diff usr/src/uts/common/io/sata/impl/sata.c @ 1940:c302ad4d1aa7
6404894 Informational exceptions log parameter should be 4 bytes
6412375 Need to add support for tagged queuing in the marvell88sx driver
6412380 sata framework doesn't always utilize correct queuing mode
6412384 queue depth is incorrect for SATA controllers
6412386 Some SATA disks do no use the 19th entry in the self test log
6412390 SATA LOG SENSE results can be incorrect
6412398 allow scatter/gather list length for marvell88sx to be tunable
6420987 sata_hba_ioctl() may hold mutex upon exit
author | ls24207 |
---|---|
date | Fri, 05 May 2006 13:30:06 -0700 |
parents | 1005b1d56b1c |
children | 01f4efa62f05 |
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c Fri May 05 13:27:41 2006 -0700 +++ b/usr/src/uts/common/io/sata/impl/sata.c Fri May 05 13:30:06 2006 -0700 @@ -63,7 +63,7 @@ #define SATA_ENABLE_QUEUING 1 #define SATA_ENABLE_NCQ 2 #define SATA_ENABLE_PROCESS_EVENTS 4 -static int sata_func_enable = SATA_ENABLE_PROCESS_EVENTS; +int sata_func_enable = SATA_ENABLE_PROCESS_EVENTS | SATA_ENABLE_QUEUING; #ifdef SATA_DEBUG #define SATA_LOG_D(args) sata_log args @@ -1106,6 +1106,8 @@ } /* Sanity check */ if (SATA_PORT_DEACTIVATE_FUNC(sata_hba_inst) == NULL) { + mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)-> + cport_mutex); /* No physical port deactivation supported. */ break; } @@ -2714,6 +2716,7 @@ * SCMD_WRITE_G4 * SCMD_WRITE_G5 * SCMD_SEEK (noop) + * SCMD_SDIAG * * All other commands are rejected as unsupported. * @@ -2860,7 +2863,6 @@ rval = sata_txlt_nodata_cmd_immediate(spx); break; - /* Other cases will be filed later */ /* postponed until phase 2 of the development */ default: @@ -4879,34 +4881,49 @@ * to appropriate command if possible */ if (sata_func_enable & SATA_ENABLE_QUEUING) { - if (sdinfo->satadrv_queue_depth > 1 && - SATA_QDEPTH(spx->txlt_sata_hba_inst) > 1) { - /* Queuing supported by controller and device */ - if ((sata_func_enable & SATA_ENABLE_NCQ) && - (sdinfo->satadrv_features_support & - SATA_DEV_F_NCQ) && - (SATA_FEATURES(spx->txlt_sata_hba_inst) & - SATA_CTLF_NCQ)) { - /* NCQ supported - use FPDMA READ */ + boolean_t using_queuing; + + /* Queuing supported by controller and device? */ + if ((sata_func_enable & SATA_ENABLE_NCQ) && + (sdinfo->satadrv_features_support & + SATA_DEV_F_NCQ) && + (SATA_FEATURES(spx->txlt_sata_hba_inst) & + SATA_CTLF_NCQ)) { + using_queuing = B_TRUE; + + /* NCQ supported - use FPDMA READ */ + scmd->satacmd_cmd_reg = + SATAC_READ_FPDMA_QUEUED; + scmd->satacmd_features_reg_ext = + scmd->satacmd_sec_count_msb; + scmd->satacmd_sec_count_msb = 0; + scmd->satacmd_rle_sata_cmd = NULL; + } else if ((sdinfo->satadrv_features_support & + SATA_DEV_F_TCQ) && + (SATA_FEATURES(spx->txlt_sata_hba_inst) & + SATA_CTLF_QCMD)) { + using_queuing = B_TRUE; + + /* Legacy queueing */ + if (sdinfo->satadrv_features_support & + SATA_DEV_F_LBA48) { scmd->satacmd_cmd_reg = - SATAC_READ_FPDMA_QUEUED; + SATAC_READ_DMA_QUEUED_EXT; scmd->satacmd_features_reg_ext = scmd->satacmd_sec_count_msb; scmd->satacmd_sec_count_msb = 0; } else { - /* Legacy queueing */ - if (sdinfo->satadrv_features_support & - SATA_DEV_F_LBA48) { - scmd->satacmd_cmd_reg = - SATAC_READ_DMA_QUEUED_EXT; - scmd->satacmd_features_reg_ext = - scmd->satacmd_sec_count_msb; - scmd->satacmd_sec_count_msb = 0; - } else { - scmd->satacmd_cmd_reg = - SATAC_READ_DMA_QUEUED; - } - } + scmd->satacmd_cmd_reg = + SATAC_READ_DMA_QUEUED; + } + } else /* Queuing not supported */ + using_queuing = B_FALSE; + + /* + * If queuing, the sector count goes in the features register + * and the secount count will contain the tag. + */ + if (using_queuing) { scmd->satacmd_features_reg = scmd->satacmd_sec_count_lsb; scmd->satacmd_sec_count_lsb = 0; @@ -5080,35 +5097,45 @@ * to appropriate command if possible */ if (sata_func_enable & SATA_ENABLE_QUEUING) { - if (sdinfo->satadrv_queue_depth > 1 && - SATA_QDEPTH(spx->txlt_sata_hba_inst) > 1) { - /* Queuing supported by controller and device */ - if ((sata_func_enable & SATA_ENABLE_NCQ) && - (sdinfo->satadrv_features_support & - SATA_DEV_F_NCQ) && - (SATA_FEATURES(spx->txlt_sata_hba_inst) & - SATA_CTLF_NCQ)) { - /* NCQ supported - use FPDMA WRITE */ + boolean_t using_queuing; + + /* Queuing supported by controller and device? */ + if ((sata_func_enable & SATA_ENABLE_NCQ) && + (sdinfo->satadrv_features_support & + SATA_DEV_F_NCQ) && + (SATA_FEATURES(spx->txlt_sata_hba_inst) & + SATA_CTLF_NCQ)) { + using_queuing = B_TRUE; + + /* NCQ supported - use FPDMA WRITE */ + scmd->satacmd_cmd_reg = + SATAC_WRITE_FPDMA_QUEUED; + scmd->satacmd_features_reg_ext = + scmd->satacmd_sec_count_msb; + scmd->satacmd_sec_count_msb = 0; + scmd->satacmd_rle_sata_cmd = NULL; + } else if ((sdinfo->satadrv_features_support & + SATA_DEV_F_TCQ) && + (SATA_FEATURES(spx->txlt_sata_hba_inst) & + SATA_CTLF_QCMD)) { + using_queuing = B_TRUE; + + /* Legacy queueing */ + if (sdinfo->satadrv_features_support & + SATA_DEV_F_LBA48) { scmd->satacmd_cmd_reg = - SATAC_WRITE_FPDMA_QUEUED; + SATAC_WRITE_DMA_QUEUED_EXT; scmd->satacmd_features_reg_ext = scmd->satacmd_sec_count_msb; scmd->satacmd_sec_count_msb = 0; - scmd->satacmd_rle_sata_cmd = NULL; } else { - /* Legacy queueing */ - if (sdinfo->satadrv_features_support & - SATA_DEV_F_LBA48) { - scmd->satacmd_cmd_reg = - SATAC_WRITE_DMA_QUEUED_EXT; - scmd->satacmd_features_reg_ext = - scmd->satacmd_sec_count_msb; - scmd->satacmd_sec_count_msb = 0; - } else { - scmd->satacmd_cmd_reg = - SATAC_WRITE_DMA_QUEUED; - } - } + scmd->satacmd_cmd_reg = + SATAC_WRITE_DMA_QUEUED; + } + } else /* Queuing not supported */ + using_queuing = B_FALSE; + + if (using_queuing) { scmd->satacmd_features_reg = scmd->satacmd_sec_count_lsb; scmd->satacmd_sec_count_lsb = 0; @@ -5320,7 +5347,6 @@ return (TRAN_ACCEPT); } - /* * Send pkt to SATA HBA driver * @@ -6414,10 +6440,13 @@ rval = sata_ext_smart_selftest_read_log(sata_hba_inst, sdinfo, ext_selftest_log, 0); if (rval == 0) { - int index; + int index, start_index; struct smart_ext_selftest_log_entry *entry; + static const struct smart_ext_selftest_log_entry empty = + {0}; uint16_t block_num; int count; + boolean_t only_one_block = B_FALSE; index = ext_selftest_log-> smart_ext_selftest_log_index[0]; @@ -6427,6 +6456,7 @@ goto out; --index; /* Correct for 0 origin */ + start_index = index; /* remember where we started */ block_num = index / ENTRIES_PER_EXT_SELFTEST_LOG_BLK; if (block_num != 0) { rval = sata_ext_smart_selftest_read_log( @@ -6449,9 +6479,28 @@ uint8_t add_sense_code; uint8_t add_sense_code_qual; + /* If this is an unused entry, we are done */ + if (bcmp(entry, &empty, sizeof (empty)) == 0) { + /* Broken firmware on some disks */ + if (index + 1 == + ENTRIES_PER_EXT_SELFTEST_LOG_BLK) { + --entry; + --index; + if (bcmp(entry, &empty, + sizeof (empty)) == 0) + goto out; + } else + goto out; + } + + if (only_one_block && + start_index == index) + goto out; + lpp->param_code[0] = 0; lpp->param_code[1] = count; - lpp->param_ctrl_flags = 0; + lpp->param_ctrl_flags = + LOG_CTRL_LP | LOG_CTRL_LBIN; lpp->param_len = SCSI_LOG_SENSE_SELFTEST_PARAM_LEN; @@ -6521,20 +6570,38 @@ 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]; + if (status != 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]; + } else { /* No bad block address */ + lpp->param_values[4] = 0xff; + lpp->param_values[5] = 0xff; + lpp->param_values[6] = 0xff; + lpp->param_values[7] = 0xff; + lpp->param_values[8] = 0xff; + lpp->param_values[9] = 0xff; + lpp->param_values[10] = 0xff; + lpp->param_values[11] = 0xff; + } + lpp->param_values[12] = sense_key; lpp->param_values[13] = add_sense_code; lpp->param_values[14] = add_sense_code_qual; @@ -6565,14 +6632,16 @@ [1] == 0)) goto out; block_num = - logdir.read_log_ext_nblks[0] + logdir.read_log_ext_nblks [EXT_SMART_SELFTEST_LOG_PAGE - - 1]; + - 1][0]; block_num |= logdir. - read_log_ext_nblks[1] + read_log_ext_nblks [EXT_SMART_SELFTEST_LOG_PAGE - - 1] << 8; + - 1][1] << 8; --block_num; + only_one_block = + (block_num == 0); } rval = sata_ext_smart_selftest_read_log( sata_hba_inst, sdinfo, @@ -6605,6 +6674,8 @@ int index; int count; struct smart_selftest_log_entry *entry; + static const struct smart_selftest_log_entry empty = + { 0 }; index = selftest_log->smart_selftest_log_index; if (index == 0) @@ -6621,9 +6692,13 @@ uint8_t add_sense_code; uint8_t add_sense_code_qual; + if (bcmp(entry, &empty, sizeof (empty)) == 0) + goto done; + lpp->param_code[0] = 0; lpp->param_code[1] = count; - lpp->param_ctrl_flags = 0; + lpp->param_ctrl_flags = + LOG_CTRL_LP | LOG_CTRL_LBIN; lpp->param_len = SCSI_LOG_SENSE_SELFTEST_PARAM_LEN; @@ -6692,18 +6767,29 @@ 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]; + if (status != 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]; + } else { /* No block address */ + lpp->param_values[4] = 0xff; + lpp->param_values[5] = 0xff; + lpp->param_values[6] = 0xff; + lpp->param_values[7] = 0xff; + lpp->param_values[8] = 0xff; + lpp->param_values[9] = 0xff; + lpp->param_values[10] = 0xff; + lpp->param_values[11] = 0xff; + } lpp->param_values[12] = sense_key; lpp->param_values[13] = add_sense_code; lpp->param_values[14] = add_sense_code_qual; @@ -6765,7 +6851,7 @@ break; case 0: case -1: /* failed to get data */ - lpp->param_values[0] = 0; + lpp->param_values[0] = 0; /* No failure predicted */ lpp->param_values[1] = 0; break; #if defined(SATA_DEBUG) @@ -6797,7 +6883,8 @@ kmem_free(smart_data, 512); } - lpp->param_values[2] = temp; + lpp->param_values[2] = temp; /* most recent temperature */ + lpp->param_values[3] = 0; /* required vendor specific byte */ lpp->param_len = SCSI_INFO_EXCEPTIONS_PARAM_LEN; @@ -8225,7 +8312,7 @@ if (sdinfo->satadrv_features_support & SATA_DEV_F_NCQ) (void) strlcat(msg_buf, ", Native Command Queueing", MAXPATHLEN); - else if (sdinfo->satadrv_id.ai_cmdset83 & SATA_RW_DMA_QUEUED_CMD) + if (sdinfo->satadrv_features_support & SATA_DEV_F_TCQ) (void) strlcat(msg_buf, ", Queuing", MAXPATHLEN); if ((sdinfo->satadrv_id.ai_cmdset82 & SATA_SMART_SUPPORTED) && (sdinfo->satadrv_id.ai_features85 & SATA_SMART_ENABLED)) @@ -8923,8 +9010,11 @@ sdinfo->satadrv_queue_depth = sdinfo->satadrv_id.ai_qdepth; if (sdinfo->satadrv_id.ai_cmdset83 & SATA_RW_DMA_QUEUED_CMD) - if (sdinfo->satadrv_queue_depth == 0) - sdinfo->satadrv_queue_depth = 1; + ++sdinfo->satadrv_queue_depth; + + if ((sdinfo->satadrv_id.ai_cmdset83 & SATA_RW_DMA_QUEUED_CMD) && + (sdinfo->satadrv_id.ai_features86 & SATA_RW_DMA_QUEUED_CMD)) + sdinfo->satadrv_features_support |= SATA_DEV_F_TCQ; rval = 0; } @@ -10959,16 +11049,23 @@ scmd->satacmd_features_reg = SATA_SMART_RETURN_STATUS; scmd->satacmd_device_reg = 0; /* Always device 0 */ scmd->satacmd_cmd_reg = SATAC_SMART; + mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + /* 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) { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); /* * Whoops, no SMART RETURN STATUS */ rval = -1; } else { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); if (scmd->satacmd_error_reg & SATA_ERROR_ABORT) { rval = -1; goto fail; @@ -11065,17 +11162,23 @@ scmd->satacmd_features_reg = SATA_SMART_READ_DATA; scmd->satacmd_device_reg = 0; /* Always device 0 */ scmd->satacmd_cmd_reg = SATAC_SMART; + mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); /* 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) { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); /* * Whoops, no SMART DATA available */ rval = -1; goto fail; } else { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); if (rval != DDI_SUCCESS) { @@ -11169,16 +11272,25 @@ scmd->satacmd_device_reg = 0; /* Always device 0 */ scmd->satacmd_cmd_reg = SATAC_READ_LOG_EXT; + mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + /* 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) { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + /* * Whoops, no SMART selftest log info available */ rval = -1; goto fail; } else { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); if (rval != DDI_SUCCESS) { @@ -11270,17 +11382,23 @@ scmd->satacmd_features_reg = SATA_SMART_READ_LOG; scmd->satacmd_device_reg = 0; /* Always device 0 */ scmd->satacmd_cmd_reg = SATAC_SMART; + mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); /* 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) { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); /* * Whoops, no SMART DATA available */ rval = -1; goto fail; } else { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); if (rval != DDI_SUCCESS) { @@ -11369,16 +11487,25 @@ scmd->satacmd_device_reg = 0; /* Always device 0 */ scmd->satacmd_cmd_reg = SATAC_SMART; + mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + /* 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) { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + /* * Whoops, no SMART DATA available */ rval = -1; goto fail; } else { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); if (rval != DDI_SUCCESS) { @@ -11467,16 +11594,23 @@ scmd->satacmd_device_reg = 0; /* Always device 0 */ scmd->satacmd_cmd_reg = SATAC_READ_LOG_EXT; + mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); + /* 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) { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); /* * Whoops, no SMART selftest log info available */ rval = -1; goto fail; } else { + mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, + sdinfo->satadrv_addr.cport))); rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); if (rval != DDI_SUCCESS) {