sata.c revision 7a70ede882eacbae00c8d5209afb443e7755684c
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/Aint sata_debug_flags = 0;
2N/A#ifdef SATA_DEBUG
2N/A sata_address_t *);
2N/A sata_device_t *);
2N/A ddi_dma_attr_t *);
2N/Astatic void sata_event_daemon(void *);
2N/Astatic void sata_event_thread_control(int);
2N/A sata_address_t *);
2N/A sata_address_t *);
2N/A sata_pkt_txlate_t *, int);
2N/A struct mode_cache_scsi3 *, int, int *, int *, int *);
2N/A struct mode_info_excpt_page *, int, int *, int *, int *);
2N/A sata_hba_inst_t *);
2N/A sata_hba_inst_t *);
2N/A sata_hba_inst_t *);
2N/A struct smart_data *);
2N/A struct smart_selftest_log *);
2N/A struct read_log_ext_directory *);
2N/Astatic int sata_event_thread_terminate = 0;
2N/Astatic int sata_event_pending = 0;
2N/Astatic int sata_event_thread_active = 0;
2N/A#ifdef SATA_DEBUG
2N/A int hba_attach_state = 0;
2N/A return (DDI_FAILURE);
2N/A return (DDI_FAILURE);
2N/A return (DDI_FAILURE);
2N/A return (DDI_FAILURE);
2N/A#ifdef SATA_DEBUG
2N/A sizeof (taskq_name));
2N/A#ifdef SATA_DEBUG
2N/A * controller/port/multipliers/device configuration and will create
2N/A return (DDI_SUCCESS);
2N/A sizeof (struct sata_hba_inst));
2N/A return (DDI_FAILURE);
2N/A case DDI_DETACH:
2N/A return (DDI_FAILURE);
2N/A return (DDI_FAILURE);
2N/A return (DDI_FAILURE);
2N/A NDI_DEVI_REMOVE) !=
2N/A NDI_SUCCESS) {
2N/A return (DDI_FAILURE);
2N/A sizeof (sata_drive_info_t));
2N/A sizeof (sata_cport_info_t));
2N/A sizeof (struct sata_hba_inst));
2N/A return (DDI_SUCCESS);
2N/A case DDI_SUSPEND:
2N/A return (DDI_FAILURE);
2N/A return (DDI_FAILURE);
2N/A#ifndef __lock_lint
2N/A#ifndef __lock_lint
2N/A#ifndef __lock_lint
2N/A case DEVCTL_DEVICE_GETSTATE:
2N/A case DEVCTL_DEVICE_ONLINE:
2N/A case DEVCTL_DEVICE_OFFLINE:
2N/A case DEVCTL_DEVICE_REMOVE:
2N/A case DEVCTL_BUS_GETSTATE:
2N/A case DEVCTL_AP_DISCONNECT:
2N/A SATA_SUCCESS) {
2N/A (SATA_VALID_DEV_TYPE))) {
2N/A sizeof (sata_drive_info_t));
2N/A case DEVCTL_AP_UNCONFIGURE:
2N/A NDI_SUCCESS) {
2N/A case DEVCTL_AP_CONNECT:
2N/A &sata_device);
2N/A case DEVCTL_AP_CONFIGURE:
2N/A &sata_device);
2N/A SATA_SUCCESS) {
2N/A case DEVCTL_AP_GETSTATE:
2N/A case DEVCTL_AP_CONTROL:
2N/A#ifdef _MULTI_DATAMODEL
2N/A case SATA_CFGA_RESET_PORT:
2N/A &sata_device);
2N/A SATA_SUCCESS) {
2N/A case SATA_CFGA_RESET_DEVICE:
2N/A &sata_device);
2N/A &sata_device);
2N/A * port disconnect/connect and re-probing is
2N/A case SATA_CFGA_RESET_ALL:
2N/A SATA_EVNT_LOCK_PORT_BUSY) != 0) {
2N/A &sata_device);
2N/A NDI_UNCONFIG) !=
2N/A NDI_SUCCESS) {
2N/A NDI_DEVI_REMOVE) !=
2N/A NDI_SUCCESS) {
2N/A sizeof (sata_drive_info_t));
case SATA_CFGA_PORT_ACTIVATE:
&sata_device);
cport));
case SATA_CFGA_PORT_SELF_TEST:
&sata_device);
SATA_SUCCESS) {
NULL) {
case SATA_CFGA_GET_AP_TYPE:
const char *ap_type;
case SATA_DTYPE_NONE:
case SATA_DTYPE_ATADISK:
case SATA_DTYPE_ATAPICD:
case SATA_DTYPE_PMULT:
case SATA_DTYPE_UNKNOWN:
case SATA_CFGA_GET_MODEL_INFO:
&sata_device);
char ap_info[
&sata_device);
char ap_info[
&sata_device);
if (rval != 0) {
if (dcp) {
return (rv);
#ifndef __lock_lint
&sata_device) != 0)
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_SUCCESS);
return (DDI_SUCCESS);
int rval;
return (rval);
#ifndef __lock_lint
&sata_device) != 0)
static struct scsi_pkt *
int rval;
return (NULL);
return (NULL);
return (pkt);
* Packet was preallocated/initialized by previous call
return (pkt);
switch (rval) {
case DDI_DMA_NORESOURCES:
case DDI_DMA_NOMAPPING:
case DDI_DMA_BADATTR:
case DDI_DMA_TOOBIG:
return (NULL);
return (pkt);
int cport;
int rval;
return (TRAN_FATAL_ERROR);
return (rval);
case SCMD_INQUIRY:
case SCMD_TEST_UNIT_READY:
case SCMD_START_STOP:
case SCMD_READ_CAPACITY:
case SCMD_REQUEST_SENSE:
case SCMD_LOG_SENSE_G1:
case SCMD_LOG_SELECT_G1:
case SCMD_MODE_SENSE:
case SCMD_MODE_SENSE_G1:
case SCMD_MODE_SELECT:
case SCMD_MODE_SELECT_G1:
case SCMD_SYNCHRONIZE_CACHE:
case SCMD_READ:
case SCMD_READ_G1:
case SCMD_READ_G4:
case SCMD_READ_G5:
case SCMD_WRITE:
case SCMD_WRITE_G1:
case SCMD_WRITE_G4:
case SCMD_WRITE_G5:
case SCMD_SEEK:
return (rval);
SATA_SUCCESS) {
int val;
} else if (val == 0 &&
int rval;
NULL) {
case SCSI_CAP_ARQ:
case SCSI_CAP_SECTOR_SIZE:
case SCSI_CAP_TAGGED_QING:
case SCSI_CAP_DMA_MAX:
&adj_dma_attr);
return (rval);
* All supported capabilities are fixed/unchangeable.
#ifndef __lock_lint
int rval;
case SCSI_CAP_ARQ:
case SCSI_CAP_SECTOR_SIZE:
case SCSI_CAP_TAGGED_QING:
case SCSI_CAP_DMA_MAX:
return (rval);
#ifndef __lock_lint
#ifndef __lock_lint
int rval;
int direction;
return (TRAN_BADPKT);
return (TRAN_FATAL_ERROR);
return (TRAN_BUSY);
return (TRAN_ACCEPT);
#ifdef _LITTLE_ENDIAN
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int rval;
return (rval);
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int count;
uint8_t *p;
int rval;
return (rval);
goto done;
unsigned int bufsize;
sizeof (struct scsi_inquiry));
case INQUIRY_SUP_VPD_PAGE:
case INQUIRY_USN_PAGE:
#ifdef _LITTLE_ENDIAN
goto done;
done:
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int rval;
return (rval);
sizeof (struct scsi_extended_sense));
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int power_state;
int rval;
return (rval);
switch (power_state) {
case SATA_PWRMODE_ACTIVE:
case SATA_PWRMODE_IDLE:
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int rval;
int synch;
return (rval);
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
return (rval);
if (synch) {
return (TRAN_ACCEPT);
int rval;
return (rval);
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int rval;
return (rval);
len = 0;
bdlen = 0;
#ifndef __lock_lint
case MODEPAGE_RW_ERRRECOV:
case MODEPAGE_CACHING:
goto done;
case MODEPAGE_INFO_EXCPT:
goto err;
case MODEPAGE_POWER_COND:
case MODEPAGE_ALLPAGES:
err:
goto done;
done:
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int dmod = 0;
return (rval);
goto done;
while (pllen > 0) {
case MODEPAGE_CACHING:
goto done;
case MODEPAGE_INFO_EXCPT:
goto done;
done:
if (dmod != 0) {
int rv;
&new_sdinfo);
if (rv == 0) {
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (rval);
int rval;
return (rval);
switch (pc) {
case PC_CUMMULATIVE_VALUES:
goto done;
switch (page_code) {
goto done;
len = 0;
switch (page_code) {
goto done;
goto done;
goto done;
goto done;
goto done;
goto no_header;
goto done;
done:
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
int rval;
int synch;
return (rval);
case SCMD_READ:
case SCMD_READ_G1:
case SCMD_READ_G5:
case SCMD_READ_G4:
#ifndef __lock_lint
SATA_DEV_F_NCQ) &&
SATA_CTLF_NCQ)) {
SATA_DEV_F_TCQ) &&
SATA_CTLF_QCMD)) {
if (using_queuing) {
return (rval);
if (synch) {
return (TRAN_ACCEPT);
int rval;
int synch;
return (rval);
case SCMD_WRITE:
case SCMD_WRITE_G1:
case SCMD_WRITE_G5:
case SCMD_WRITE_G4:
#ifndef __lock_lint
SATA_DEV_F_NCQ) &&
SATA_CTLF_NCQ)) {
SATA_DEV_F_TCQ) &&
SATA_CTLF_QCMD)) {
if (using_queuing) {
return (rval);
if (synch) {
return (TRAN_ACCEPT);
int rval;
int synch;
return (rval);
* scmd->satacmd_flags.sata_data_direction default -
case SCMD_READ:
case SCMD_READ_G1:
case SCMD_READ_G5:
case SCMD_READ_G4:
case SCMD_WRITE:
case SCMD_WRITE_G1:
case SCMD_WRITE_G5:
case SCMD_WRITE_G4:
return (rval);
if (synch) {
return (TRAN_ACCEPT);
int rval;
int synch;
return (rval);
return (rval);
if (synch) {
return (TRAN_ACCEPT);
int stat;
switch (stat) {
case SATA_TRAN_ACCEPTED:
case SATA_TRAN_QUEUE_FULL:
case SATA_TRAN_PORT_ERROR:
* Communication/link with device or general port error
case SATA_TRAN_BUSY:
cmd);
cmd);
TQ_SLEEP) == 0)
return (TRAN_BUSY);
return (TRAN_ACCEPT);
* Extract error LBA from sata_pkt.satapkt_cmd register fields
*lba = 0;
static struct scsi_extended_sense *
return (sense);
int rval;
case SATA_PKT_PORT_ERROR:
case SATA_PKT_DEV_ERROR:
case SATAC_READ_DMA:
case SATAC_READ_DMA_EXT:
case SATAC_READ_DMA_QUEUED:
case SATAC_READ_FPDMA_QUEUED:
case SATAC_WRITE_DMA:
case SATAC_WRITE_DMA_EXT:
case SATAC_WRITE_DMA_QUEUED:
case SATAC_WRITE_FPDMA_QUEUED:
case SATA_PKT_TIMEOUT:
case SATA_PKT_ABORTED:
case SATA_PKT_RESET:
case SATA_PKT_PORT_ERROR:
case SATA_PKT_DEV_ERROR:
case SATA_PKT_TIMEOUT:
case SATA_PKT_ABORTED:
case SATA_PKT_RESET:
#ifndef __lock_lint
return (PAGELENGTH_DAD_MODE_CACHE_SCSI3 +
sizeof (struct mode_page));
#ifndef __lock_lint
*dmod = 0;
return (SATA_FAILURE);
return (SATA_SUCCESS);
wce = 0;
return (SATA_SUCCESS);
if (dra == 0)
return (SATA_FAILURE);
return (SATA_FAILURE);
goto failure;
return (SATA_SUCCESS);
return (SATA_FAILURE);
int parmlen,
int *pagelen,
int *rval,
int *dmod)
*dmod = 0;
return (SATA_FAILURE);
return (SATA_FAILURE);
return (SATA_SUCCESS);
return (SATA_FAILURE);
return (SATA_SUCCESS);
return (SATA_FAILURE);
int rval;
ext_selftest_log, 0);
if (rval == 0) {
int count;
if (index == 0)
goto out;
if (block_num != 0) {
if (rval != 0)
goto out;
entry =
++count) {
--entry;
--index;
sizeof (empty)) == 0)
goto out;
goto out;
if (only_one_block &&
goto out;
switch (status) {
add_sense_code_qual = 0;
if (status != 0) {
if (index < 0) {
if (block_num > 0) {
--block_num;
struct read_log_ext_directory
rval =
&logdir);
goto out;
goto out;
--block_num;
(block_num == 0);
if (rval != 0)
goto out;
index =
out:
sizeof (struct smart_ext_selftest_log));
KM_SLEEP);
if (rval == 0) {
int index;
int count;
if (index == 0)
goto done;
++count) {
goto done;
switch (status) {
if (status != 0) {
if (index < 0) {
index =
done:
int rval;
/* Now get the SMART status w.r.t. threshold exceeded */
switch (rval) {
#if defined(SATA_DEBUG)
temp = 0;
int rval;
return (sizeof (struct smart_data));
return (SATA_FAILURE);
return (SATA_FAILURE);
return (SATA_SUCCESS);
#ifdef SATA_DEBUG
if (sata_hba_list) {
if (sata_hba_list_tail) {
int rval;
DDI_SUCCESS) {
ncport);
KM_SLEEP);
KM_SLEEP);
NULL);
for (npmport = 0;
npmport++) {
0) != DDI_SUCCESS) {
&sata_device);
&sata_device);
int rval;
SATA_VALID_DEV_TYPE) == 0) {
for (npmport = 0;
npmport++) {
&sata_device);
SATA_VALID_DEV_TYPE) == 0) {
(void) sata_initialize_device(
static dev_info_t *
int rval;
int ncompatible;
int target;
target));
return (NULL);
#ifdef SATA_DEBUG
target);
for (i = 0; i < ncompatible; i++) {
return (NULL);
goto fail;
goto fail;
goto fail;
(void *)cdip));
goto fail;
return (cdip);
return (NULL);
fail:
return (NULL);
int rval;
return (SATA_FAILURE);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (rval);
else if (sata_write_cache == 0)
goto invalid_address;
goto invalid_address;
goto invalid_address;
goto out;
goto out;
goto out;
SATA_VALID_DEV_TYPE) == 0) {
goto out;
goto out;
NULL ||
goto out;
pmport);
goto out;
goto out;
out:
return (rval);
static dev_info_t *
#ifndef __lock_lint
return (NULL);
return (dip);
int retry_cnt;
return (SATA_FAILURE);
retry_cnt++) {
&new_sdinfo) == 0) {
return (SATA_FAILURE);
return (SATA_SUCCESS);
return (SATA_FAILURE);
static sata_drive_info_t *
return (NULL);
return (NULL);
return (NULL);
return (NULL);
return (NULL);
return (NULL);
return (NULL);
goto fail_unknown;
SATA_ATAPI_TYPE) &&
goto fail_unknown;
goto fail_unknown;
int valid_version;
#ifdef SATA_DEBUG
valid_version = i;
#ifdef __i386
static uint64_t
return (capacity);
static struct buf *
return (bp);
static sata_pkt_t *
int kmsflag;
return (NULL);
return (spkt);
* If a device is being probed/initialized, there are
int rval;
rval));
return (rval);
&cookie,
&bufsz,
(void) ddi_dma_free_handle(
#ifdef SATA_DEBUG
return (rval);
#ifdef SATA_DEBUG
mbuf_count++;
NULL,
switch (rval) {
case DDI_DMA_PARTIAL_MAP:
(void) ddi_dma_unbind_handle(
(void) ddi_dma_free_handle(
return (DDI_FAILURE);
case DDI_DMA_MAPPED:
return (rval);
&cookie,
return (DDI_SUCCESS);
sizeof (ddi_dma_cookie_t));
sizeof (ddi_dma_cookie_t) *
if ((cur_txfer_len +
return (DDI_SUCCESS);
int rval;
sizeof (sata_id_t));
rval = 0;
fail:
return (rval);
int i, mode;
return (SATA_FAILURE);
if (i < mode) {
goto failure;
return (result);
int cache_op)
char *infop;
goto failure;
switch (cache_op) {
return (rval);
static int32_t
port));
return (port);
static dev_info_t *
int ncport;
int circ;
return (cdip);
int port_state;
case SATA_DTYPE_NONE:
case SATA_DTYPE_UNKNOWN:
case SATA_DTYPE_ATAPINONCD:
case SATA_DTYPE_ATADISK:
case SATA_DTYPE_ATAPICD:
int circ;
static int sata_event_thread_terminating = 0;
static int sata_event_thread_starting = 0;
#ifdef SATA_DEBUG
(void (*)())sata_event_daemon,
#ifdef SATA_DEBUG
pathname[0] = 0;
if (sata_debug_flags == 0)
char *lcp;
static char *err_msg_evnt_1 =
static char *err_msg_evnt_2 =
int linkevent;
goto event_info;
pstats =
pstats =
if (linkevent) {
linkevent = 0;
goto event_info;
if (sata_event_thread_active == 0)
#ifndef __lock_lint
loop:
SATA_EVNT_SKIP) != 0) {
goto loop;
#ifdef SATA_DEBUG
if (sata_event_thread_active != 0) {
goto loop;
int ncport;
NULL);
if ((event_flags &
saddr);
saddr);
saddr);
if (event_flags &
saddr);
saddr);
int rval;
SATA_VALID_DEV_TYPE) == 0) {
SATA_FAILURE) {
SATA_VALID_DEV_TYPE) != 0 &&
int event_flags;
int rval;
goto linklost;
NULL);
SATA_VALID_DEV_TYPE) != 0) {
goto done;
#ifdef SATA_DEBUG
if ((cur_time -
done:
if (event_flags != 0) {
int rval;
sizeof (sata_drive_info_t));
int rval;
sizeof (sata_drive_info_t));
* Explicit port disconnect/connect or physical device
char *finfox;
int cache_op;
return (SATA_FAILURE);
return (SATA_FAILURE);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (rval);
int rval;
goto fail;
goto fail;
rval = 0;
goto fail;
fail:
return (rval);
int rval;
#if ! defined(lint)
sizeof (struct smart_data));
goto fail;
sizeof (struct smart_data));
fail:
return (rval);
int rval;
#if ! defined(lint)
sizeof (struct smart_ext_selftest_log));
goto fail;
sizeof (struct smart_ext_selftest_log));
rval = 0;
fail:
return (rval);
int rval;
#if ! defined(lint)
sizeof (struct smart_selftest_log));
goto fail;
sizeof (struct smart_selftest_log));
rval = 0;
fail:
return (rval);
int rval;
goto fail;
rval = 0;
fail:
return (rval);
int rval;
#if ! defined(lint)
sizeof (struct read_log_ext_directory));
goto fail;
sizeof (struct read_log_ext_directory));
rval = 0;
fail:
return (rval);
int hint)
int err;
if (err != 0) {
if (err != 0) {
if (err != 0) {
case SATA_PKT_PORT_ERROR:
case SATA_PKT_DEV_ERROR:
case SATA_PKT_TIMEOUT:
case SATA_PKT_ABORTED:
case SATA_PKT_RESET: