Mercurial > illumos > illumos-gate
changeset 2960:0a0e45155fbd
6469980 sata module should retry identify device up to 60 sec after the device is hotplugged
6472682 sata module needs to use sata_device values returned by HBA driver when sata_pkt is rejected
author | pawelw |
---|---|
date | Fri, 20 Oct 2006 17:13:50 -0700 |
parents | 54668e3addac |
children | 8b33bed4151e |
files | usr/src/uts/common/io/sata/impl/sata.c usr/src/uts/common/sys/sata/impl/sata.h |
diffstat | 2 files changed, 485 insertions(+), 329 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c Fri Oct 20 16:46:58 2006 -0700 +++ b/usr/src/uts/common/io/sata/impl/sata.c Fri Oct 20 17:13:50 2006 -0700 @@ -110,8 +110,9 @@ static void sata_remove_hba_instance(dev_info_t *); static int sata_validate_sata_hba_tran(dev_info_t *, sata_hba_tran_t *); static void sata_probe_ports(sata_hba_inst_t *); -static int sata_reprobe_port(sata_hba_inst_t *, sata_device_t *); -static void sata_make_device_nodes(dev_info_t *, sata_hba_inst_t *); +static int sata_reprobe_port(sata_hba_inst_t *, sata_device_t *, int); +static int sata_add_device(dev_info_t *, sata_hba_inst_t *, int cport, + int pmport); static dev_info_t *sata_create_target_node(dev_info_t *, sata_hba_inst_t *, sata_address_t *); static int sata_validate_scsi_address(sata_hba_inst_t *, @@ -690,15 +691,11 @@ * controller/port/multipliers/device configuration and will create * attachment points. * We may end-up with just a controller with no devices attached. + * For the ports with a supported device attached, device target nodes + * are created and devices are initialized. */ sata_probe_ports(sata_hba_inst); - /* - * Create child nodes for all possible target devices currently - * attached to controller's ports and port multiplier device ports. - */ - sata_make_device_nodes(sata_tran->sata_tran_hba_dip, sata_hba_inst); - sata_hba_inst->satahba_attached = 1; return (DDI_SUCCESS); @@ -1133,15 +1130,14 @@ */ /* Check the current state of the port */ - if (sata_reprobe_port(sata_hba_inst, &sata_device) != - SATA_SUCCESS) { - rv = EIO; - break; - } + rval = (*SATA_PROBE_PORT_FUNC(sata_hba_inst)) + (dip, &sata_device); mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, cport)-> cport_mutex); - if (cportinfo->cport_state & - (SATA_PSTATE_SHUTDOWN | SATA_PSTATE_FAILED)) { + sata_update_port_info(sata_hba_inst, &sata_device); + if (rval != SATA_SUCCESS || + (sata_device.satadev_state & SATA_PSTATE_FAILED)) { + cportinfo->cport_state = SATA_PSTATE_FAILED; mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)-> cport_mutex); rv = EIO; @@ -1353,8 +1349,11 @@ mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)->cport_mutex); - if (sata_reprobe_port(sata_hba_inst, &sata_device) == - SATA_FAILURE) + /* + * Probe the port to find its state and attached device. + */ + if (sata_reprobe_port(sata_hba_inst, &sata_device, + SATA_DEV_IDENTIFY_RETRY) == SATA_FAILURE) rv = EIO; /* * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE @@ -1466,8 +1465,8 @@ * Always reprobe port, to get current device info. */ mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)->cport_mutex); - if (sata_reprobe_port(sata_hba_inst, &sata_device) != - SATA_SUCCESS) { + if (sata_reprobe_port(sata_hba_inst, &sata_device, + SATA_DEV_IDENTIFY_RETRY) != SATA_SUCCESS) { rv = EIO; break; } @@ -1680,8 +1679,8 @@ * port state is unknown - it's state is HBA-specific. * Re-probe port to get its state. */ - if (sata_reprobe_port(sata_hba_inst, &sata_device) != - SATA_SUCCESS) { + if (sata_reprobe_port(sata_hba_inst, &sata_device, + SATA_DEV_IDENTIFY_RETRY) != SATA_SUCCESS) { rv = EIO; break; } @@ -1830,7 +1829,9 @@ SATA_ADDR_CPORT; if (sata_reprobe_port(sata_hba_inst, - &sata_device) != SATA_SUCCESS) + &sata_device, + SATA_DEV_IDENTIFY_RETRY) != + SATA_SUCCESS) rv = EIO; } @@ -2062,7 +2063,8 @@ * If port probing failed, the device type would be * set to SATA_DTYPE_NONE. */ - (void) sata_reprobe_port(sata_hba_inst, &sata_device); + (void) sata_reprobe_port(sata_hba_inst, &sata_device, + SATA_DEV_IDENTIFY_RETRY); /* * Generate sysevent - @@ -2125,8 +2127,8 @@ * port state is unknown - it's state is HBA-specific. * Force port re-probing to get it into a known state. */ - if (sata_reprobe_port(sata_hba_inst, &sata_device) != - SATA_SUCCESS) { + if (sata_reprobe_port(sata_hba_inst, &sata_device, + SATA_DEV_IDENTIFY_RETRY) != SATA_SUCCESS) { rv = EIO; break; } @@ -2655,7 +2657,10 @@ return (NULL); } /* Set sata address */ - spx->txlt_sata_pkt->satapkt_device = sata_device; + spx->txlt_sata_pkt->satapkt_device.satadev_addr = + sata_device.satadev_addr; + spx->txlt_sata_pkt->satapkt_device.satadev_rev = + sata_device.satadev_rev; if ((bp == NULL) || (bp->b_bcount == 0)) return (pkt); @@ -5468,7 +5473,7 @@ int stat; sata_hba_inst_t *sata_hba_inst = spx->txlt_sata_hba_inst; sata_drive_info_t *sdinfo; - sata_device_t sata_device; + sata_device_t *sata_device; uint8_t cmd; struct sata_cmd_flags cmd_flags; @@ -5490,7 +5495,7 @@ } cmd = spx->txlt_sata_pkt->satapkt_cmd.satacmd_cmd_reg; cmd_flags = spx->txlt_sata_pkt->satapkt_cmd.satacmd_flags; - sata_device = spx->txlt_sata_pkt->satapkt_device; /* local copy */ + sata_device = &spx->txlt_sata_pkt->satapkt_device; mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, sdinfo->satadrv_addr.cport))); @@ -5541,15 +5546,17 @@ * detected before pkt execution begun. */ if (spx->txlt_sata_pkt->satapkt_device.satadev_addr.qual == - SATA_ADDR_CPORT) + SATA_ADDR_CPORT || + spx->txlt_sata_pkt->satapkt_device.satadev_addr.qual == + SATA_ADDR_DCPORT) sata_log(sata_hba_inst, CE_CONT, "port %d error", - sata_device.satadev_addr.cport); + sata_device->satadev_addr.cport); else sata_log(sata_hba_inst, CE_CONT, "port %d pmport %d error\n", - sata_device.satadev_addr.cport, - sata_device.satadev_addr.pmport); + sata_device->satadev_addr.cport, + sata_device->satadev_addr.pmport); /* * Update the port/device structure. @@ -5559,7 +5566,7 @@ * because original packet's sata address refered to a device * attached to some port. */ - sata_update_port_info(sata_hba_inst, &sata_device); + sata_update_port_info(sata_hba_inst, sata_device); spx->txlt_scsi_pkt->pkt_reason = CMD_TRAN_ERR; *rval = TRAN_FATAL_ERROR; break; @@ -5628,7 +5635,7 @@ * Check if device is still configured - it may have * disapeared from the configuration */ - sdinfo = sata_get_device_info(sata_hba_inst, &sata_device); + sdinfo = sata_get_device_info(sata_hba_inst, sata_device); if (sdinfo != NULL) { /* * Restore the flag that requests clearing of @@ -7121,12 +7128,17 @@ /* * Probe all SATA ports of the specified HBA instance. + * The assumption is that there are no target and attachment point minor nodes + * created by the boot subsystems, so we do not need to prune device tree. + * * This function is called only from sata_hba_attach(). It does not have to * be protected by controller mutex, because the hba_attached flag is not set * yet and no one would be touching this HBA instance other then this thread. * Determines if port is active and what type of the device is attached * (if any). Allocates necessary structures for each port. - * Creates attachment point minor node for each non-failed port. + * + * An AP (Attachement Point) node is created for each SATA device port even + * when there is no device attached. */ static void @@ -7142,6 +7154,7 @@ int rval; dev_t minor_number; char name[16]; + clock_t start_time, cur_time; /* * Probe controller ports first, to find port status and @@ -7179,6 +7192,8 @@ } /* Probe port */ + start_time = ddi_get_lbolt(); + reprobe_cport: sata_device.satadev_addr.cport = ncport; sata_device.satadev_addr.pmport = 0; sata_device.satadev_addr.qual = SATA_ADDR_CPORT; @@ -7209,18 +7224,38 @@ * There is some device attached. * Allocate device info structure */ - mutex_exit(&cportinfo->cport_mutex); - drive = kmem_zalloc(sizeof (sata_drive_info_t), - KM_SLEEP); - mutex_enter(&cportinfo->cport_mutex); - SATA_CPORTINFO_DRV_INFO(cportinfo) = drive; + if (SATA_CPORTINFO_DRV_INFO(cportinfo) == NULL) { + mutex_exit(&cportinfo->cport_mutex); + SATA_CPORTINFO_DRV_INFO(cportinfo) = + kmem_zalloc(sizeof (sata_drive_info_t), + KM_SLEEP); + mutex_enter(&cportinfo->cport_mutex); + } + drive = SATA_CPORTINFO_DRV_INFO(cportinfo); drive->satadrv_addr = cportinfo->cport_addr; drive->satadrv_addr.qual = SATA_ADDR_DCPORT; drive->satadrv_type = cportinfo->cport_dev_type; drive->satadrv_state = SATA_STATE_UNKNOWN; + + mutex_exit(&cportinfo->cport_mutex); + if (sata_add_device(dip, sata_hba_inst, ncport, 0) != + SATA_SUCCESS) { + /* + * Plugged device was not correctly identified. + * Retry, within a SATA_DEV_IDENTIFY_TIMEOUT + */ + cur_time = ddi_get_lbolt(); + if ((cur_time - start_time) < + drv_usectohz(SATA_DEV_IDENTIFY_TIMEOUT)) { + /* sleep for a while */ + delay(drv_usectohz( + SATA_DEV_IDENTIFY_RETRY_DELAY)); + goto reprobe_cport; + } + } } else { + mutex_exit(&cportinfo->cport_mutex); ASSERT(cportinfo->cport_dev_type == SATA_DTYPE_PMULT); - mutex_exit(&cportinfo->cport_mutex); pminfo = kmem_zalloc(sizeof (sata_pmult_info_t), KM_SLEEP); mutex_enter(&cportinfo->cport_mutex); @@ -7234,12 +7269,12 @@ mutex_init(&pminfo->pmult_mutex, NULL, MUTEX_DRIVER, NULL); pminfo->pmult_state = SATA_STATE_PROBING; + mutex_exit(&cportinfo->cport_mutex); /* Probe Port Multiplier ports */ for (npmport = 0; npmport < pminfo->pmult_num_dev_ports; npmport++) { - mutex_exit(&cportinfo->cport_mutex); pmportinfo = kmem_zalloc( sizeof (sata_pmport_info_t), KM_SLEEP); mutex_enter(&cportinfo->cport_mutex); @@ -7249,14 +7284,12 @@ pmportinfo->pmport_addr.qual = SATA_ADDR_PMPORT; pminfo->pmult_dev_port[npmport] = pmportinfo; + mutex_init(&pmportinfo->pmport_mutex, NULL, MUTEX_DRIVER, NULL); - sata_device.satadev_addr.pmport = npmport; - sata_device.satadev_addr.qual = - SATA_ADDR_PMPORT; - mutex_exit(&cportinfo->cport_mutex); + /* Create an attachment point */ minor_number = SATA_MAKE_AP_MINOR( ddi_get_instance(dip), ncport, npmport, 1); @@ -7270,6 +7303,13 @@ "point for port %d pmult port %d", ncport, npmport); } + + start_time = ddi_get_lbolt(); + reprobe_pmport: + sata_device.satadev_addr.pmport = npmport; + sata_device.satadev_addr.qual = + SATA_ADDR_PMPORT; + rval = (*SATA_PROBE_PORT_FUNC(sata_hba_inst)) (dip, &sata_device); mutex_enter(&cportinfo->cport_mutex); @@ -7281,6 +7321,7 @@ if (rval != SATA_SUCCESS) { pmportinfo->pmport_state = SATA_PSTATE_FAILED; + mutex_exit(&cportinfo->cport_mutex); continue; } pmportinfo->pmport_state &= @@ -7291,9 +7332,10 @@ pmportinfo->pmport_state |= SATA_STATE_READY; if (pmportinfo->pmport_dev_type == - SATA_DTYPE_NONE) + SATA_DTYPE_NONE) { + mutex_exit(&cportinfo->cport_mutex); continue; - + } /* Port multipliers cannot be chained */ ASSERT(pmportinfo->pmport_dev_type != SATA_DTYPE_PMULT); @@ -7302,18 +7344,15 @@ * Multiplier device port * Allocate device info structure */ - mutex_exit(&cportinfo->cport_mutex); - drive = kmem_zalloc( - sizeof (sata_drive_info_t), KM_SLEEP); - rval = (*SATA_PROBE_PORT_FUNC(sata_hba_inst)) - (dip, &sata_device); - mutex_enter(&cportinfo->cport_mutex); - - /* sata_update_port_info() */ - sata_update_port_scr(&pmportinfo->pmport_scr, - &sata_device); - - pmportinfo->pmport_sata_drive = drive; + if (pmportinfo->pmport_sata_drive == NULL) { + mutex_exit(&cportinfo->cport_mutex); + pmportinfo->pmport_sata_drive = + kmem_zalloc( + sizeof (sata_drive_info_t), + KM_SLEEP); + mutex_enter(&cportinfo->cport_mutex); + } + drive = pmportinfo->pmport_sata_drive; drive->satadrv_addr.cport = pmportinfo->pmport_addr.cport; drive->satadrv_addr.pmport = npmport; @@ -7321,38 +7360,51 @@ drive->satadrv_type = pmportinfo-> pmport_dev_type; drive->satadrv_state = SATA_STATE_UNKNOWN; + + mutex_exit(&cportinfo->cport_mutex); + if (sata_add_device(dip, sata_hba_inst, ncport, + npmport) != SATA_SUCCESS) { + /* + * Plugged device was not correctly + * identified. Retry, within the + * SATA_DEV_IDENTIFY_TIMEOUT + */ + cur_time = ddi_get_lbolt(); + if ((cur_time - start_time) < + drv_usectohz( + SATA_DEV_IDENTIFY_TIMEOUT)) { + /* sleep for a while */ + delay(drv_usectohz( + SATA_DEV_IDENTIFY_RETRY_DELAY)); + goto reprobe_pmport; + } + } } pmportinfo->pmport_state = SATA_STATE_PROBED | SATA_STATE_READY; } - mutex_exit(&cportinfo->cport_mutex); - } -} - - - -/* - * Create SATA device nodes for specified HBA instance (SCSI target + } +} + +/* + * Add SATA device for specified HBA instance & port (SCSI target * device nodes). - * This function is called only from sata_hba_attach(). The hba_attached flag - * is not set yet, so no ports or device data structures would be touched - * by anyone other then this thread, therefore per-port mutex protection is - * not needed. - * The assumption is that there are no target and attachment point minor nodes - * created by the boot subsystems, so we do not need to prune device tree. - * An AP (Attachement Point) node is created for each SATA device port even - * when there is no device attached. - * A target node is created when there is a supported type of device attached, + * This function is called (indirectly) only from sata_hba_attach(). + * A target node is created when there is a supported type device attached, * but may be removed if it cannot be put online. * * This function cannot be called from an interrupt context. * * ONLY DISK TARGET NODES ARE CREATED NOW - */ -static void -sata_make_device_nodes(dev_info_t *pdip, sata_hba_inst_t *sata_hba_inst) -{ - int ncport, npmport; + * + * Returns SATA_SUCCESS when port/device was fully processed, SATA_FAILURE when + * device identification failed - adding a device could be retried. + * + */ +static int +sata_add_device(dev_info_t *pdip, sata_hba_inst_t *sata_hba_inst, int cport, + int pmport) +{ sata_cport_info_t *cportinfo; sata_pmult_info_t *pminfo; sata_pmport_info_t *pmportinfo; @@ -7360,177 +7412,151 @@ sata_device_t sata_device; int rval; - /* - * Walk through pre-probed sata ports info in sata_hba_inst structure - */ - for (ncport = 0; ncport < SATA_NUM_CPORTS(sata_hba_inst); ncport++) { - cportinfo = SATA_CPORT_INFO(sata_hba_inst, ncport); + + + cportinfo = SATA_CPORT_INFO(sata_hba_inst, cport); + ASSERT(cportinfo->cport_dev_type != SATA_DTYPE_NONE); + mutex_enter(&cportinfo->cport_mutex); + /* + * Some device is attached to a controller port. + * We rely on controllers distinquishing between no-device, + * attached port multiplier and other kind of attached device. + * We need to get Identify Device data and determine + * positively the dev type before trying to attach + * the target driver. + */ + sata_device.satadev_rev = SATA_DEVICE_REV; + if (cportinfo->cport_dev_type != SATA_DTYPE_PMULT) { + /* + * Not port multiplier. + */ + sata_device.satadev_addr = cportinfo->cport_addr; + sata_device.satadev_addr.qual = SATA_ADDR_DCPORT; + mutex_exit(&cportinfo->cport_mutex); + + rval = sata_probe_device(sata_hba_inst, &sata_device); + if (rval != SATA_SUCCESS || + sata_device.satadev_type == SATA_DTYPE_UNKNOWN) + return (SATA_FAILURE); + mutex_enter(&cportinfo->cport_mutex); - if (!(cportinfo->cport_state & SATA_STATE_PROBED)) { - mutex_exit(&cportinfo->cport_mutex); - continue; - } - if (cportinfo->cport_state == SATA_PSTATE_FAILED) { - mutex_exit(&cportinfo->cport_mutex); - continue; - } - if (cportinfo->cport_dev_type == SATA_DTYPE_NONE) { - /* No device attached to the controller port */ - mutex_exit(&cportinfo->cport_mutex); - continue; - } - /* - * Some device is attached to a controller port. - * We rely on controllers distinquishing between no-device, - * attached port multiplier and other kind of attached device. - * We need to get Identify Device data and determine - * positively the dev type before trying to attach - * the target driver. - */ - sata_device.satadev_rev = SATA_DEVICE_REV; - if (cportinfo->cport_dev_type != SATA_DTYPE_PMULT) { + if ((sata_device.satadev_type & SATA_VALID_DEV_TYPE) == 0) { /* - * Not port multiplier. + * Could not determine device type or + * a device is not supported. + * Degrade this device to unknown. */ - sata_device.satadev_addr = cportinfo->cport_addr; - sata_device.satadev_addr.qual = SATA_ADDR_DCPORT; + cportinfo->cport_dev_type = SATA_DTYPE_UNKNOWN; mutex_exit(&cportinfo->cport_mutex); - rval = sata_probe_device(sata_hba_inst, &sata_device); - if (rval != SATA_SUCCESS || - sata_device.satadev_type == SATA_DTYPE_UNKNOWN) - continue; - - mutex_enter(&cportinfo->cport_mutex); - if ((sata_device.satadev_type & - SATA_VALID_DEV_TYPE) == 0) { - /* - * Could not determine device type or - * a device is not supported. - * Degrade this device to unknown. - */ - cportinfo->cport_dev_type = SATA_DTYPE_UNKNOWN; - mutex_exit(&cportinfo->cport_mutex); - continue; - } - cportinfo->cport_dev_type = sata_device.satadev_type; - mutex_exit(&cportinfo->cport_mutex); - - if (sata_initialize_device(sata_hba_inst, - SATA_CPORTINFO_DRV_INFO(cportinfo)) != SATA_SUCCESS) - /* Retry */ - (void) sata_initialize_device(sata_hba_inst, - SATA_CPORTINFO_DRV_INFO(cportinfo)); - - mutex_enter(&cportinfo->cport_mutex); - sata_show_drive_info(sata_hba_inst, + return (SATA_SUCCESS); + } + cportinfo->cport_dev_type = sata_device.satadev_type; + mutex_exit(&cportinfo->cport_mutex); + + /* + * Initialize device to the desired state. Even if it + * fails, the device will still attach but syslog + * will show the warning. + */ + if (sata_initialize_device(sata_hba_inst, + SATA_CPORTINFO_DRV_INFO(cportinfo)) != SATA_SUCCESS) + /* Retry */ + (void) sata_initialize_device(sata_hba_inst, SATA_CPORTINFO_DRV_INFO(cportinfo)); - mutex_exit(&cportinfo->cport_mutex); - cdip = sata_create_target_node(pdip, sata_hba_inst, - &sata_device.satadev_addr); - mutex_enter(&cportinfo->cport_mutex); - if (cdip == NULL) { - /* - * Attaching target node failed. - * We retain sata_drive_info structure... - */ - (SATA_CPORTINFO_DRV_INFO(cportinfo))-> - satadrv_type = SATA_DTYPE_UNKNOWN; - (SATA_CPORTINFO_DRV_INFO(cportinfo))-> - satadrv_state = SATA_STATE_UNKNOWN; - cportinfo->cport_dev_type = SATA_DTYPE_UNKNOWN; - mutex_exit(&cportinfo->cport_mutex); - continue; - } + + mutex_enter(&cportinfo->cport_mutex); + sata_show_drive_info(sata_hba_inst, + SATA_CPORTINFO_DRV_INFO(cportinfo)); + mutex_exit(&cportinfo->cport_mutex); + cdip = sata_create_target_node(pdip, sata_hba_inst, + &sata_device.satadev_addr); + mutex_enter(&cportinfo->cport_mutex); + if (cdip == NULL) { + /* + * Attaching target node failed. + * We retain sata_drive_info structure... + */ + (SATA_CPORTINFO_DRV_INFO(cportinfo))-> + satadrv_type = SATA_DTYPE_UNKNOWN; (SATA_CPORTINFO_DRV_INFO(cportinfo))-> - satadrv_state = SATA_STATE_READY; - } else { - /* This must be Port Multiplier type */ - if (cportinfo->cport_dev_type != SATA_DTYPE_PMULT) { - SATA_LOG_D((sata_hba_inst, CE_WARN, - "sata_make_device_nodes: " - "unknown dev type %x", - cportinfo->cport_dev_type)); - mutex_exit(&cportinfo->cport_mutex); - continue; - } - pminfo = SATA_CPORTINFO_PMULT_INFO(cportinfo); - for (npmport = 0; - npmport < pminfo->pmult_num_dev_ports; - npmport++) { - pmportinfo = pminfo->pmult_dev_port[npmport]; - if (pmportinfo->pmport_state & - SATA_PSTATE_FAILED) { - continue; - } - if (pmportinfo->pmport_dev_type & - SATA_DTYPE_NONE) - /* No device attached */ - continue; - - sata_device.satadev_addr = - pmportinfo->pmport_addr; - sata_device.satadev_addr.qual = - SATA_ADDR_DPMPORT; - mutex_exit(&cportinfo->cport_mutex); - rval = sata_probe_device(sata_hba_inst, - &sata_device); - if (rval != SATA_SUCCESS || - sata_device.satadev_type == - SATA_DTYPE_UNKNOWN) { - mutex_enter(&cportinfo->cport_mutex); - continue; - } - mutex_enter(&cportinfo->cport_mutex); - if ((sata_device.satadev_type & - SATA_VALID_DEV_TYPE) == 0) { - /* - * Could not determine device type. - * Degrade this device to unknown. - */ - pmportinfo->pmport_dev_type = - SATA_DTYPE_UNKNOWN; - continue; - } - pmportinfo->pmport_dev_type = - sata_device.satadev_type; - mutex_exit(&cportinfo->cport_mutex); - if (sata_initialize_device(sata_hba_inst, - pmportinfo->pmport_sata_drive) != - SATA_SUCCESS) - /* Retry */ - (void) sata_initialize_device( - sata_hba_inst, - pmportinfo->pmport_sata_drive); - - mutex_enter(&cportinfo->cport_mutex); - sata_show_drive_info(sata_hba_inst, - pmportinfo->pmport_sata_drive); - mutex_exit(&cportinfo->cport_mutex); - cdip = sata_create_target_node(pdip, - sata_hba_inst, &sata_device.satadev_addr); - mutex_enter(&cportinfo->cport_mutex); - if (cdip == NULL) { - /* - * Attaching target node failed. - * We retain sata_drive_info - * structure... - */ - pmportinfo->pmport_sata_drive-> - satadrv_type = SATA_DTYPE_UNKNOWN; - pmportinfo->pmport_sata_drive-> - satadrv_state = SATA_STATE_UNKNOWN; - pmportinfo->pmport_dev_type = - SATA_DTYPE_UNKNOWN; - continue; - } - pmportinfo->pmport_sata_drive-> - satadrv_state |= SATA_STATE_READY; - } - } + satadrv_state = SATA_STATE_UNKNOWN; + cportinfo->cport_dev_type = SATA_DTYPE_UNKNOWN; + mutex_exit(&cportinfo->cport_mutex); + return (SATA_SUCCESS); + } + (SATA_CPORTINFO_DRV_INFO(cportinfo))-> + satadrv_state = SATA_STATE_READY; + } else { + /* This must be Port Multiplier type */ + if (cportinfo->cport_dev_type != SATA_DTYPE_PMULT) { + SATA_LOG_D((sata_hba_inst, CE_WARN, + "sata_add_device: " + "unrecognized dev type %x", + cportinfo->cport_dev_type)); + mutex_exit(&cportinfo->cport_mutex); + return (SATA_SUCCESS); + } + pminfo = SATA_CPORTINFO_PMULT_INFO(cportinfo); + pmportinfo = pminfo->pmult_dev_port[pmport]; + sata_device.satadev_addr = pmportinfo->pmport_addr; + sata_device.satadev_addr.qual = SATA_ADDR_DPMPORT; mutex_exit(&cportinfo->cport_mutex); - } -} - + + rval = sata_probe_device(sata_hba_inst, &sata_device); + if (rval != SATA_SUCCESS || + sata_device.satadev_type == SATA_DTYPE_UNKNOWN) { + return (SATA_FAILURE); + } + mutex_enter(&cportinfo->cport_mutex); + if ((sata_device.satadev_type & SATA_VALID_DEV_TYPE) == 0) { + /* + * Could not determine device type. + * Degrade this device to unknown. + */ + pmportinfo->pmport_dev_type = SATA_DTYPE_UNKNOWN; + mutex_exit(&cportinfo->cport_mutex); + return (SATA_SUCCESS); + } + pmportinfo->pmport_dev_type = sata_device.satadev_type; + mutex_exit(&cportinfo->cport_mutex); + /* + * Initialize device to the desired state. + * Even if it fails, the device will still + * attach but syslog will show the warning. + */ + if (sata_initialize_device(sata_hba_inst, + pmportinfo->pmport_sata_drive) != SATA_SUCCESS) + /* Retry */ + (void) sata_initialize_device(sata_hba_inst, + pmportinfo->pmport_sata_drive); + + mutex_enter(&cportinfo->cport_mutex); + sata_show_drive_info(sata_hba_inst, + pmportinfo->pmport_sata_drive); + mutex_exit(&cportinfo->cport_mutex); + cdip = sata_create_target_node(pdip, sata_hba_inst, + &sata_device.satadev_addr); + mutex_enter(&cportinfo->cport_mutex); + if (cdip == NULL) { + /* + * Attaching target node failed. + * We retain sata_drive_info structure... + */ + pmportinfo->pmport_sata_drive-> + satadrv_type = SATA_DTYPE_UNKNOWN; + pmportinfo->pmport_sata_drive-> + satadrv_state = SATA_STATE_UNKNOWN; + pmportinfo->pmport_dev_type = + SATA_DTYPE_UNKNOWN; + mutex_exit(&cportinfo->cport_mutex); + return (SATA_SUCCESS); + } + pmportinfo->pmport_sata_drive->satadrv_state |= + SATA_STATE_READY; + } + mutex_exit(&cportinfo->cport_mutex); + return (SATA_SUCCESS); +} /* @@ -7691,21 +7717,47 @@ * Assumption: sata address is already validated. * SATA_SUCCESS is returned if port is re-probed sucessfully, regardless of * the presence of a device and its type. + * + * flag arg specifies that the function should try multiple times to identify + * device type and to initialize it, or it should return immediately on failure. + * SATA_DEV_IDENTIFY_RETRY - retry + * SATA_DEV_IDENTIFY_NORETRY - no retry + * * SATA_FAILURE is returned if one of the operations failed. + * + * This function cannot be called in interrupt context - it may sleep. */ static int -sata_reprobe_port(sata_hba_inst_t *sata_hba_inst, sata_device_t *sata_device) +sata_reprobe_port(sata_hba_inst_t *sata_hba_inst, sata_device_t *sata_device, + int flag) { sata_cport_info_t *cportinfo; sata_drive_info_t *sdinfo; boolean_t init_device = B_FALSE; int prev_device_type = SATA_DTYPE_NONE; int prev_device_settings = 0; + clock_t start_time; + int retry = B_FALSE; int rval; /* We only care about host sata cport for now */ cportinfo = SATA_CPORT_INFO(sata_hba_inst, sata_device->satadev_addr.cport); + sdinfo = SATA_CPORTINFO_DRV_INFO(cportinfo); + if (sdinfo != NULL) { + /* + * We are re-probing port with a previously attached device. + * Save previous device type and settings + */ + prev_device_type = cportinfo->cport_dev_type; + prev_device_settings = sdinfo->satadrv_settings; + } + if (flag == SATA_DEV_IDENTIFY_RETRY) { + start_time = ddi_get_lbolt(); + retry = B_TRUE; + } +retry_probe: + /* probe port */ mutex_enter(&cportinfo->cport_mutex); cportinfo->cport_state &= ~SATA_PORT_STATE_CLEAR_MASK; @@ -7814,17 +7866,13 @@ * as well as some internal framework states). */ init_device = B_TRUE; - } else { - /* - * Save previous device type and settings - */ - prev_device_type = cportinfo->cport_dev_type; - prev_device_settings = sdinfo->satadrv_settings; - } - + } cportinfo->cport_dev_type = SATA_DTYPE_UNKNOWN; sata_device->satadev_addr.qual = sdinfo->satadrv_addr.qual; } else { + /* + * The device is a port multiplier - not handled now. + */ cportinfo->cport_dev_type = SATA_DTYPE_UNKNOWN; mutex_exit(&cportinfo->cport_mutex); return (SATA_SUCCESS); @@ -7836,16 +7884,34 @@ */ rval = sata_probe_device(sata_hba_inst, sata_device); - /* - * If we are dealing with the same type of a device as before, - * restore its settings flags. - */ - if (sata_device->satadev_type == prev_device_type) - sdinfo->satadrv_settings = prev_device_settings; - - /* Set initial device features, if necessary */ - if (rval == SATA_SUCCESS && init_device == B_TRUE) { - rval = sata_initialize_device(sata_hba_inst, sdinfo); + if (rval == SATA_SUCCESS) { + /* + * If we are dealing with the same type of a device as before, + * restore its settings flags. + */ + if (sata_device->satadev_type == prev_device_type) + sdinfo->satadrv_settings = prev_device_settings; + + /* Set initial device features, if necessary */ + if (init_device == B_TRUE) { + rval = sata_initialize_device(sata_hba_inst, sdinfo); + } + if (rval == SATA_SUCCESS) + return (rval); + } + + if (retry) { + clock_t cur_time = ddi_get_lbolt(); + /* + * A device was not successfully identified or initialized. + * Track retry time for device identification. + */ + if ((cur_time - start_time) < + drv_usectohz(SATA_DEV_IDENTIFY_TIMEOUT)) { + /* sleep for a while */ + delay(drv_usectohz(SATA_DEV_IDENTIFY_RETRY_DELAY)); + goto retry_probe; + } } return (rval); } @@ -8070,15 +8136,17 @@ * successully. * If a device cannot be identified, sata_device's dev_state and dev_type * fields are set to unknown. - * - */ + * There are no retries in this function. Any retries should be managed by + * the caller. + */ + static int sata_probe_device(sata_hba_inst_t *sata_hba_inst, sata_device_t *sata_device) { sata_drive_info_t *sdinfo; sata_drive_info_t new_sdinfo; /* local drive info struct */ - int retry_cnt; + int rval; ASSERT((SATA_CPORT_STATE(sata_hba_inst, sata_device->satadev_addr.cport) & @@ -8112,34 +8180,28 @@ new_sdinfo.satadrv_addr = sata_device->satadev_addr; mutex_exit(&(SATA_CPORT_MUTEX(sata_hba_inst, sata_device->satadev_addr.cport))); - for (retry_cnt = 0; retry_cnt <= SATA_DEVICE_IDENTIFY_RETRY; - retry_cnt++) { - new_sdinfo.satadrv_type = SATA_DTYPE_ATADISK; - if (sata_identify_device(sata_hba_inst, &new_sdinfo) == 0) { - /* Got something responding to ATA Identify Device */ - sata_device->satadev_type = new_sdinfo.satadrv_type; - break; - } + new_sdinfo.satadrv_type = SATA_DTYPE_ATADISK; + rval = sata_identify_device(sata_hba_inst, &new_sdinfo); + if (rval == 1) { + /* We may try to check for ATAPI device */ if (SATA_FEATURES(sata_hba_inst) & SATA_CTLF_ATAPI) { /* * HBA supports ATAPI - try to issue Identify Packet * Device command. */ new_sdinfo.satadrv_type = SATA_DTYPE_ATAPICD; - if (sata_identify_device(sata_hba_inst, - &new_sdinfo) == 0) { - /* - * Got something responding to Identify Packet - * Device cmd. - */ - /* Set UDMA mode here as well ? - phase 2 */ - sata_device->satadev_type = - new_sdinfo.satadrv_type; - break; - } - } - } - if (retry_cnt <= SATA_DEVICE_IDENTIFY_RETRY) { + rval = sata_identify_device(sata_hba_inst, &new_sdinfo); + } + } + if (rval == -1) + goto failure; + if (rval == 0) { + /* + * Got something responding to ATA Identify Device or to + * Identify Packet Device cmd. + */ + sata_device->satadev_type = new_sdinfo.satadrv_type; + /* save device info, if possible */ mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, sata_device->satadev_addr.cport))); @@ -8267,17 +8329,22 @@ * * Cannot be called from interrupt level. * - * Returns 0 if device was identified as supported device, -1 otherwise. + * Returns: + * 0 if device was identified as a supported device, + * 1 if device was not idenitfied but identify attempt could be retried, + * -1if device was not idenitfied and identify attempt should not be retried. */ static int sata_identify_device(sata_hba_inst_t *sata_hba_inst, sata_drive_info_t *sdinfo) { uint16_t cfg_word; + int rval; int i; /* fetch device identify data */ - if (sata_fetch_device_identify_data(sata_hba_inst, sdinfo) != 0) + if ((rval = sata_fetch_device_identify_data( + sata_hba_inst, sdinfo)) != 0) goto fail_unknown; cfg_word = sdinfo->satadrv_id.ai_config; @@ -8309,6 +8376,7 @@ sata_log(sata_hba_inst, CE_WARN, "SATA disk device at port %d does not support LBA", sdinfo->satadrv_addr.cport); + rval = -1; goto fail_unknown; } } @@ -8329,6 +8397,7 @@ "mode 4 or higher", sdinfo->satadrv_addr.cport); SATA_LOG_D((sata_hba_inst, CE_WARN, "mode 4 or higher required, %d supported", i)); + rval = -1; goto fail_unknown; } @@ -8338,7 +8407,7 @@ /* Invalidate sata_drive_info ? */ sdinfo->satadrv_type = SATA_DTYPE_UNKNOWN; sdinfo->satadrv_state = SATA_STATE_UNKNOWN; - return (-1); + return (rval); } /* @@ -9115,7 +9184,10 @@ * The device_info structure has to be set to device type (for selecting proper * device identify command). * - * Returns 0 if success, -1 otherwise. + * Returns: + * 0 if cmd succeeded + * 1 if cmd was rejected and could be retried, + * -1if cmd failed and should not be retried (port error) * * Cannot be called in an interrupt context. */ @@ -9136,7 +9208,7 @@ spkt = sata_pkt_alloc(spx, SLEEP_FUNC); if (spkt == NULL) { kmem_free(spx, sizeof (sata_pkt_txlate_t)); - return (-1); + return (1); /* may retry later */ } /* address is needed now */ spkt->satapkt_device.satadev_addr = sdinfo->satadrv_addr; @@ -9151,7 +9223,7 @@ SATA_LOG_D((sata_hba_inst, CE_WARN, "sata_fetch_device_identify_data: " "cannot allocate buffer for ID")); - return (-1); + return (1); /* may retry later */ } /* Fill sata_pkt */ @@ -9185,24 +9257,17 @@ } /* 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) { - /* - * Woops, no Identify Data. - * Invalidate sata_drive_info ? - */ - rval = -1; - } else { -#ifdef SATA_DEBUG + rval = (*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst), spkt); + if (rval == SATA_TRAN_ACCEPTED && + spkt->satapkt_reason == SATA_PKT_COMPLETED) { if ((sdinfo->satadrv_id.ai_config & 4) == 1) { sata_log(sata_hba_inst, CE_WARN, "SATA disk device at port %d - " "partial Identify Data", sdinfo->satadrv_addr.cport); + rval = 1; /* may retry later */ goto fail; } -#endif /* Update sata_drive_info */ rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0, DDI_DMA_SYNC_FORKERNEL); @@ -9258,6 +9323,23 @@ (sdinfo->satadrv_features_support & SATA_DEV_F_TCQ)) ++sdinfo->satadrv_queue_depth; rval = 0; + } else { + /* + * Woops, no Identify Data. + */ + if (rval == SATA_TRAN_BUSY || rval == SATA_TRAN_QUEUE_FULL) { + rval = 1; /* may retry later */ + } else if (rval == SATA_TRAN_ACCEPTED) { + if (spkt->satapkt_reason == SATA_PKT_DEV_ERROR || + spkt->satapkt_reason == SATA_PKT_ABORTED || + spkt->satapkt_reason == SATA_PKT_TIMEOUT || + spkt->satapkt_reason == SATA_PKT_RESET) + rval = 1; /* may retry later */ + else + rval = -1; + } else { + rval = -1; + } } fail: /* Free allocated resources */ @@ -10611,7 +10693,7 @@ sata_device_t sata_device; sata_cport_info_t *cportinfo; sata_drive_info_t *sdinfo; - int event_flags; + uint32_t event_flags; int rval; SATADBG1(SATA_DBG_EVENTS_PROC, sata_hba_inst, @@ -10949,6 +11031,11 @@ * the device info structure is created and attached to the SATA port info * structure. * + * If attached device cannot be identified or set-up, the retry for the + * attach processing is set-up. Subsequent daemon run would try again to + * identify the device, until the time limit is reached + * (SATA_DEV_IDENTIFY_TIMEOUT). + * * This function cannot be called in interrupt context (it may sleep). * * NOTE: Process cports event only, no port multiplier ports. @@ -10961,6 +11048,7 @@ sata_drive_info_t *sdevinfo; sata_device_t sata_device; dev_info_t *tdip; + uint32_t event_flags; int rval; SATADBG1(SATA_DBG_EVENTS_PROC, sata_hba_inst, @@ -10974,6 +11062,7 @@ /* If the port is in SHUTDOWN or FAILED state, ignore event. */ if ((cportinfo->cport_state & (SATA_PSTATE_SHUTDOWN | SATA_PSTATE_FAILED)) != 0) { + cportinfo->cport_dev_attach_time = 0; mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)-> cport_mutex); return; @@ -10990,8 +11079,8 @@ SATA_CPORTINFO_DRV_INFO(cportinfo) = NULL; (void) kmem_free((void *)sdevinfo, sizeof (sata_drive_info_t)); - SATA_LOG_D((sata_hba_inst, CE_WARN, - "Arbitrarily detaching old device info.")); + SATADBG1(SATA_DBG_EVENTS_PROC, sata_hba_inst, + "Arbitrarily detaching old device info.", NULL); } cportinfo->cport_dev_type = SATA_DTYPE_NONE; @@ -11011,6 +11100,7 @@ if (rval != SATA_SUCCESS) { /* Something went wrong? Fail the port */ cportinfo->cport_state = SATA_PSTATE_FAILED; + cportinfo->cport_dev_attach_time = 0; mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)-> cport_mutex); SATA_LOG_D((sata_hba_inst, CE_WARN, "Port %d probing failed", @@ -11030,6 +11120,7 @@ /* * No device - ignore attach event. */ + cportinfo->cport_dev_attach_time = 0; mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)-> cport_mutex); SATADBG1(SATA_DBG_EVENTS_PROC, sata_hba_inst, @@ -11080,35 +11171,92 @@ * It is not clear, what should be done here. * For now, we will not attach a new device */ + mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, + saddr->cport)->cport_mutex); + cportinfo->cport_dev_attach_time = 0; + mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, + saddr->cport)->cport_mutex); return; } } /* - * Reprobing port will take care of the creation of the device info + * Port reprobing will take care of the creation of the device info * structure and determination of the device type. */ sata_device.satadev_addr = *saddr; - (void) sata_reprobe_port(sata_hba_inst, &sata_device); - /* - * If device was successfully attached, an explicit - * 'configure' command is needed to configure it. - */ + rval = sata_reprobe_port(sata_hba_inst, &sata_device, + SATA_DEV_IDENTIFY_NORETRY); + mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex); if ((cportinfo->cport_state & SATA_STATE_READY) && - cportinfo->cport_dev_type != SATA_DTYPE_NONE) { - sata_log(sata_hba_inst, CE_WARN, - "SATA device attached at port %d", saddr->cport); - - if (SATA_CPORTINFO_DRV_INFO(cportinfo) != NULL) { - sata_drive_info_t new_sdinfo; - - /* Log device info data */ - new_sdinfo = *(SATA_CPORTINFO_DRV_INFO(cportinfo)); - sata_show_drive_info(sata_hba_inst, &new_sdinfo); - } - } + (cportinfo->cport_dev_type != SATA_DTYPE_NONE)) { + /* Some device is attached to the port */ + if (cportinfo->cport_dev_type == SATA_DTYPE_UNKNOWN) { + /* + * A device was not successfully attached. + * Track retry time for device identification. + */ + if (cportinfo->cport_dev_attach_time != 0) { + clock_t cur_time = ddi_get_lbolt(); + /* + * If the retry time limit was not exceeded, + * reinstate attach event. + */ + if ((cur_time - + cportinfo->cport_dev_attach_time) < + drv_usectohz( + SATA_DEV_IDENTIFY_TIMEOUT)) { + /* OK, restore attach event */ + cportinfo->cport_event_flags |= + SATA_EVNT_DEVICE_ATTACHED; + } else { + /* Timeout - cannot identify device */ + cportinfo->cport_dev_attach_time = 0; + } + } else { + /* + * Start tracking time for dev identification. + * save current time (lbolt value). + */ + cportinfo->cport_dev_attach_time = + ddi_get_lbolt(); + /* Restore attach event */ + cportinfo->cport_event_flags |= + SATA_EVNT_DEVICE_ATTACHED; + } + } else { + /* + * If device was successfully attached, an explicit + * 'configure' command will be needed to configure it. + */ + cportinfo->cport_dev_attach_time = 0; + sata_log(sata_hba_inst, CE_WARN, + "SATA device attached at port %d", saddr->cport); + + if (SATA_CPORTINFO_DRV_INFO(cportinfo) != NULL) { + sata_drive_info_t new_sdinfo; + + /* Log device info data */ + new_sdinfo = + *(SATA_CPORTINFO_DRV_INFO(cportinfo)); + sata_show_drive_info(sata_hba_inst, + &new_sdinfo); + } + } + } else { + cportinfo->cport_dev_attach_time = 0; + } + event_flags = cportinfo->cport_event_flags; mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex); + if (event_flags != 0) { + mutex_enter(&sata_hba_inst->satahba_mutex); + sata_hba_inst->satahba_event_flags |= SATA_EVNT_MAIN; + mutex_exit(&sata_hba_inst->satahba_mutex); + mutex_enter(&sata_mutex); + sata_event_pending |= SATA_EVNT_MAIN; + mutex_exit(&sata_mutex); + } }
--- a/usr/src/uts/common/sys/sata/impl/sata.h Fri Oct 20 16:46:58 2006 -0700 +++ b/usr/src/uts/common/sys/sata/impl/sata.h Fri Oct 20 17:13:50 2006 -0700 @@ -162,6 +162,8 @@ } cport_devp; /* lbolt value at link lost */ clock_t cport_link_lost_time; + /* lbolt value @ dev attached */ + clock_t cport_dev_attach_time; struct sata_port_stats cport_stats; /* Port statistics */ }; @@ -286,6 +288,8 @@ /* lbolt value at link lost */ clock_t pmport_link_lost_time; + /* lbolt value @ dev attached */ + clock_t pmport_dev_attach_time; struct sata_port_stats pmport_stats; /* Port statistics */ }; @@ -368,8 +372,12 @@ #define SATA_EVNT_DAEMON_TERM_TIMEOUT 100000 /* 100 ms */ #define SATA_EVNT_DAEMON_TERM_WAIT 60000000 /* 60 s */ #define SATA_EVNT_LINK_LOST_TIMEOUT 1000000 /* 1 s */ +#define SATA_DEV_IDENTIFY_TIMEOUT 60000000 /* 60 s */ +#define SATA_DEV_IDENTIFY_RETRY_DELAY 10000 /* 10 ms */ -#define SATA_DEVICE_IDENTIFY_RETRY 2 +/* DEVICE IDENTIFY and device initialization retry delay */ +#define SATA_DEV_IDENTIFY_RETRY 1 +#define SATA_DEV_IDENTIFY_NORETRY 0 /* * sata_scsi's hba_open_flag: field indicating open devctl instance.