14c06356bSdh142964 /* 24c06356bSdh142964 * CDDL HEADER START 34c06356bSdh142964 * 44c06356bSdh142964 * The contents of this file are subject to the terms of the 54c06356bSdh142964 * Common Development and Distribution License (the "License"). 64c06356bSdh142964 * You may not use this file except in compliance with the License. 74c06356bSdh142964 * 84c06356bSdh142964 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94c06356bSdh142964 * or http://www.opensolaris.org/os/licensing. 104c06356bSdh142964 * See the License for the specific language governing permissions 114c06356bSdh142964 * and limitations under the License. 124c06356bSdh142964 * 134c06356bSdh142964 * When distributing Covered Code, include this CDDL HEADER in each 144c06356bSdh142964 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154c06356bSdh142964 * If applicable, add the following below this CDDL HEADER, with the 164c06356bSdh142964 * fields enclosed by brackets "[]" replaced with your own identifying 174c06356bSdh142964 * information: Portions Copyright [yyyy] [name of copyright owner] 184c06356bSdh142964 * 194c06356bSdh142964 * CDDL HEADER END 204c06356bSdh142964 * 214c06356bSdh142964 * 224c06356bSdh142964 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 234c06356bSdh142964 * Use is subject to license terms. 244c06356bSdh142964 */ 254c06356bSdh142964 /* 264c06356bSdh142964 * SCSI (SCSA) midlayer interface for PMC drier. 274c06356bSdh142964 */ 284c06356bSdh142964 294c06356bSdh142964 #include <sys/scsi/adapters/pmcs/pmcs.h> 304c06356bSdh142964 314c06356bSdh142964 extern scsi_lun_t scsi_lun64_to_lun(scsi_lun64_t lun64); 324c06356bSdh142964 334c06356bSdh142964 static int pmcs_scsa_tran_tgt_init(dev_info_t *, dev_info_t *, 344c06356bSdh142964 scsi_hba_tran_t *, struct scsi_device *); 354c06356bSdh142964 static void pmcs_scsa_tran_tgt_free(dev_info_t *, dev_info_t *, 364c06356bSdh142964 scsi_hba_tran_t *, struct scsi_device *); 374c06356bSdh142964 static int pmcs_scsa_start(struct scsi_address *, struct scsi_pkt *); 384c06356bSdh142964 static int pmcs_scsa_abort(struct scsi_address *, struct scsi_pkt *); 394c06356bSdh142964 static int pmcs_scsa_reset(struct scsi_address *, int); 404c06356bSdh142964 static int pmcs_scsi_reset_notify(struct scsi_address *, int, 414c06356bSdh142964 void (*)(caddr_t), caddr_t); 424c06356bSdh142964 static int pmcs_scsa_getcap(struct scsi_address *, char *, int); 434c06356bSdh142964 static int pmcs_scsa_setcap(struct scsi_address *, char *, int, int); 444c06356bSdh142964 static int pmcs_scsa_setup_pkt(struct scsi_pkt *, int (*)(caddr_t), caddr_t); 454c06356bSdh142964 static void pmcs_scsa_teardown_pkt(struct scsi_pkt *); 4696c4a178SChris Horne 4796c4a178SChris Horne static int pmcs_smp_init(dev_info_t *, dev_info_t *, smp_hba_tran_t *, 4896c4a178SChris Horne smp_device_t *); 4996c4a178SChris Horne static void pmcs_smp_free(dev_info_t *, dev_info_t *, smp_hba_tran_t *, 5096c4a178SChris Horne smp_device_t *); 514c06356bSdh142964 static int pmcs_smp_start(struct smp_pkt *); 524c06356bSdh142964 534c06356bSdh142964 static int pmcs_scsi_quiesce(dev_info_t *); 544c06356bSdh142964 static int pmcs_scsi_unquiesce(dev_info_t *); 554c06356bSdh142964 564c06356bSdh142964 static int pmcs_cap(struct scsi_address *, char *, int, int, int); 574c06356bSdh142964 static pmcs_xscsi_t * 584c06356bSdh142964 pmcs_addr2xp(struct scsi_address *, uint64_t *, pmcs_cmd_t *); 594c06356bSdh142964 static int pmcs_SAS_run(pmcs_cmd_t *, pmcwork_t *); 604c06356bSdh142964 static void pmcs_SAS_done(pmcs_hw_t *, pmcwork_t *, uint32_t *); 614c06356bSdh142964 624c06356bSdh142964 static int pmcs_SATA_run(pmcs_cmd_t *, pmcwork_t *); 634c06356bSdh142964 static void pmcs_SATA_done(pmcs_hw_t *, pmcwork_t *, uint32_t *); 644c06356bSdh142964 static uint8_t pmcs_SATA_rwparm(uint8_t *, uint32_t *, uint64_t *, uint64_t); 654c06356bSdh142964 664c06356bSdh142964 static void pmcs_ioerror(pmcs_hw_t *, pmcs_dtype_t pmcs_dtype, 674c06356bSdh142964 pmcwork_t *, uint32_t *); 684c06356bSdh142964 694c06356bSdh142964 704c06356bSdh142964 int 714c06356bSdh142964 pmcs_scsa_init(pmcs_hw_t *pwp, const ddi_dma_attr_t *ap) 724c06356bSdh142964 { 734c06356bSdh142964 scsi_hba_tran_t *tran; 744c06356bSdh142964 ddi_dma_attr_t pmcs_scsa_dattr; 754c06356bSdh142964 int flags; 764c06356bSdh142964 774c06356bSdh142964 (void) memcpy(&pmcs_scsa_dattr, ap, sizeof (ddi_dma_attr_t)); 784c06356bSdh142964 pmcs_scsa_dattr.dma_attr_sgllen = 794c06356bSdh142964 ((PMCS_SGL_NCHUNKS - 1) * (PMCS_MAX_CHUNKS - 1)) + PMCS_SGL_NCHUNKS; 804c06356bSdh142964 pmcs_scsa_dattr.dma_attr_flags = DDI_DMA_RELAXED_ORDERING; 814c06356bSdh142964 pmcs_scsa_dattr.dma_attr_flags |= DDI_DMA_FLAGERR; 824c06356bSdh142964 834c06356bSdh142964 /* 844c06356bSdh142964 * Allocate a transport structure 854c06356bSdh142964 */ 864c06356bSdh142964 tran = scsi_hba_tran_alloc(pwp->dip, SCSI_HBA_CANSLEEP); 874c06356bSdh142964 if (tran == NULL) { 88c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 89c3bc407cSdh142964 "scsi_hba_tran_alloc failed"); 904c06356bSdh142964 return (DDI_FAILURE); 914c06356bSdh142964 } 924c06356bSdh142964 934c06356bSdh142964 tran->tran_hba_private = pwp; 944c06356bSdh142964 tran->tran_tgt_init = pmcs_scsa_tran_tgt_init; 954c06356bSdh142964 tran->tran_tgt_free = pmcs_scsa_tran_tgt_free; 964c06356bSdh142964 tran->tran_start = pmcs_scsa_start; 974c06356bSdh142964 tran->tran_abort = pmcs_scsa_abort; 984c06356bSdh142964 tran->tran_reset = pmcs_scsa_reset; 994c06356bSdh142964 tran->tran_reset_notify = pmcs_scsi_reset_notify; 1004c06356bSdh142964 tran->tran_getcap = pmcs_scsa_getcap; 1014c06356bSdh142964 tran->tran_setcap = pmcs_scsa_setcap; 1024c06356bSdh142964 tran->tran_setup_pkt = pmcs_scsa_setup_pkt; 1034c06356bSdh142964 tran->tran_teardown_pkt = pmcs_scsa_teardown_pkt; 1044c06356bSdh142964 tran->tran_quiesce = pmcs_scsi_quiesce; 1054c06356bSdh142964 tran->tran_unquiesce = pmcs_scsi_unquiesce; 1064c06356bSdh142964 tran->tran_interconnect_type = INTERCONNECT_SAS; 1074c06356bSdh142964 tran->tran_hba_len = sizeof (pmcs_cmd_t); 1084c06356bSdh142964 1094c06356bSdh142964 /* 1104c06356bSdh142964 * Attach this instance of the hba 1114c06356bSdh142964 */ 1124c06356bSdh142964 1134c06356bSdh142964 flags = SCSI_HBA_TRAN_SCB | SCSI_HBA_TRAN_CDB | SCSI_HBA_ADDR_COMPLEX | 1144c06356bSdh142964 SCSI_HBA_TRAN_PHCI | SCSI_HBA_HBA; 1154c06356bSdh142964 1164c06356bSdh142964 if (scsi_hba_attach_setup(pwp->dip, &pmcs_scsa_dattr, tran, flags)) { 1174c06356bSdh142964 scsi_hba_tran_free(tran); 118c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 119c3bc407cSdh142964 "scsi_hba_attach failed"); 1204c06356bSdh142964 return (DDI_FAILURE); 1214c06356bSdh142964 } 1224c06356bSdh142964 pwp->tran = tran; 1234c06356bSdh142964 1244c06356bSdh142964 /* 1254c06356bSdh142964 * Attach the SMP part of this hba 1264c06356bSdh142964 */ 12796c4a178SChris Horne pwp->smp_tran = smp_hba_tran_alloc(pwp->dip); 1284c06356bSdh142964 ASSERT(pwp->smp_tran != NULL); 12996c4a178SChris Horne pwp->smp_tran->smp_tran_hba_private = pwp; 13096c4a178SChris Horne pwp->smp_tran->smp_tran_init = pmcs_smp_init; 13196c4a178SChris Horne pwp->smp_tran->smp_tran_free = pmcs_smp_free; 13296c4a178SChris Horne pwp->smp_tran->smp_tran_start = pmcs_smp_start; 1334c06356bSdh142964 13496c4a178SChris Horne if (smp_hba_attach_setup(pwp->dip, pwp->smp_tran) != DDI_SUCCESS) { 135c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 13696c4a178SChris Horne "smp_hba_attach failed"); 13796c4a178SChris Horne smp_hba_tran_free(pwp->smp_tran); 1384c06356bSdh142964 pwp->smp_tran = NULL; 1394c06356bSdh142964 scsi_hba_tran_free(tran); 1404c06356bSdh142964 return (DDI_FAILURE); 1414c06356bSdh142964 } 1424c06356bSdh142964 1434c06356bSdh142964 return (DDI_SUCCESS); 1444c06356bSdh142964 } 1454c06356bSdh142964 1464c06356bSdh142964 /* 1474c06356bSdh142964 * SCSA entry points 1484c06356bSdh142964 */ 1494c06356bSdh142964 1504c06356bSdh142964 static int 1514c06356bSdh142964 pmcs_scsa_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 1524c06356bSdh142964 scsi_hba_tran_t *tran, struct scsi_device *sd) 1534c06356bSdh142964 { 1544c06356bSdh142964 pmcs_hw_t *pwp = NULL; 1554c06356bSdh142964 int rval; 1564c06356bSdh142964 char *variant_prop = "sata"; 1574c06356bSdh142964 char *tgt_port = NULL, *ua = NULL; 1584c06356bSdh142964 pmcs_xscsi_t *tgt = NULL; 1594c06356bSdh142964 pmcs_iport_t *iport; 1604c06356bSdh142964 pmcs_lun_t *lun = NULL; 1614c06356bSdh142964 pmcs_phy_t *phyp = NULL; 1624c06356bSdh142964 uint64_t lun_num; 1634c06356bSdh142964 boolean_t got_scratch = B_FALSE; 1644c06356bSdh142964 1654c06356bSdh142964 /* 1664c06356bSdh142964 * First, make sure we're an iport and get the pointer to the HBA 1674c06356bSdh142964 * node's softstate 1684c06356bSdh142964 */ 1694c06356bSdh142964 if (scsi_hba_iport_unit_address(hba_dip) == NULL) { 170c3bc407cSdh142964 pmcs_prt(TRAN2PMC(tran), PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 1714c06356bSdh142964 "%s: We don't enumerate devices on the HBA node", __func__); 1724c06356bSdh142964 goto tgt_init_fail; 1734c06356bSdh142964 } 1744c06356bSdh142964 1754c06356bSdh142964 pwp = ITRAN2PMC(tran); 1764c06356bSdh142964 iport = ITRAN2IPORT(tran); 1774c06356bSdh142964 1784c06356bSdh142964 /* 1794c06356bSdh142964 * Get the target address 1804c06356bSdh142964 */ 1814c06356bSdh142964 rval = scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH, 1824c06356bSdh142964 SCSI_ADDR_PROP_TARGET_PORT, &tgt_port); 1834c06356bSdh142964 if (rval != DDI_PROP_SUCCESS) { 184c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 185c3bc407cSdh142964 "Couldn't get target UA"); 1864c06356bSdh142964 pwp = NULL; 1874c06356bSdh142964 goto tgt_init_fail; 1884c06356bSdh142964 } 189c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL, 190c3bc407cSdh142964 "got tgt_port '%s'", tgt_port); 1914c06356bSdh142964 1924c06356bSdh142964 /* 1934c06356bSdh142964 * Validate that this tran_tgt_init is for an active iport. 1944c06356bSdh142964 */ 1954c06356bSdh142964 if (iport->ua_state == UA_INACTIVE) { 196c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1974c06356bSdh142964 "%s: Got tran_tgt_init on inactive iport for '%s'", 1984c06356bSdh142964 __func__, tgt_port); 1994c06356bSdh142964 pwp = NULL; 2004c06356bSdh142964 goto tgt_init_fail; 2014c06356bSdh142964 } 2024c06356bSdh142964 2034c06356bSdh142964 /* 2044c06356bSdh142964 * Since we're going to wait for scratch, be sure to acquire it while 2054c06356bSdh142964 * we're not holding any other locks 2064c06356bSdh142964 */ 2074c06356bSdh142964 (void) pmcs_acquire_scratch(pwp, B_TRUE); 2084c06356bSdh142964 got_scratch = B_TRUE; 2094c06356bSdh142964 2104c06356bSdh142964 mutex_enter(&pwp->lock); 2114c06356bSdh142964 2124c06356bSdh142964 /* 2134c06356bSdh142964 * See if there's already a target softstate. If not, allocate one. 2144c06356bSdh142964 */ 2154c06356bSdh142964 tgt = pmcs_get_target(iport, tgt_port); 2164c06356bSdh142964 2174c06356bSdh142964 if (tgt == NULL) { 2184c06356bSdh142964 goto tgt_init_fail; 2194c06356bSdh142964 } 2204c06356bSdh142964 2214c06356bSdh142964 phyp = tgt->phy; 2224c06356bSdh142964 if (!IS_ROOT_PHY(phyp)) { 2234c06356bSdh142964 pmcs_inc_phy_ref_count(phyp); 2244c06356bSdh142964 } 2254c06356bSdh142964 ASSERT(mutex_owned(&phyp->phy_lock)); 2264c06356bSdh142964 227c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, phyp, tgt, "tgt = 0x%p, dip = 0x%p", 2284c06356bSdh142964 (void *)tgt, (void *)tgt_dip); 2294c06356bSdh142964 2304c06356bSdh142964 /* 2314c06356bSdh142964 * Now get the full "w<WWN>,LUN" unit-address (including LU). 2324c06356bSdh142964 */ 2334c06356bSdh142964 ua = scsi_device_unit_address(sd); 2344c06356bSdh142964 if (ua == NULL) { 235c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 2364c06356bSdh142964 "Couldn't get LU unit address"); 2374c06356bSdh142964 goto tgt_init_fail; 2384c06356bSdh142964 } 239c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, tgt, "got lun ua '%s'", ua); 2404c06356bSdh142964 2414c06356bSdh142964 lun_num = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH, 2424c06356bSdh142964 SCSI_ADDR_PROP_LUN64, SCSI_LUN64_ILLEGAL); 2434c06356bSdh142964 if (lun_num == SCSI_LUN64_ILLEGAL) { 244c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 245c3bc407cSdh142964 "No LUN for tgt %p", (void *)tgt); 2464c06356bSdh142964 goto tgt_init_fail; 2474c06356bSdh142964 } 2484c06356bSdh142964 249c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, "%s: @%s tgt 0x%p phy " 250c3bc407cSdh142964 "0x%p (%s)", __func__, ua, (void *)tgt, (void *)phyp, phyp->path); 2514c06356bSdh142964 2524c06356bSdh142964 mutex_enter(&tgt->statlock); 2534c06356bSdh142964 tgt->dtype = phyp->dtype; 2544c06356bSdh142964 if (tgt->dtype != SAS && tgt->dtype != SATA) { 255c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 256c3bc407cSdh142964 "PHY 0x%p went away?", (void *)phyp); 2574c06356bSdh142964 goto tgt_init_fail; 2584c06356bSdh142964 } 2594c06356bSdh142964 2604c06356bSdh142964 /* We don't support SATA devices at LUN > 0. */ 2614c06356bSdh142964 if ((tgt->dtype == SATA) && (lun_num > 0)) { 262c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 2634c06356bSdh142964 "%s: No support for SATA devices at LUN > 0 " 2644c06356bSdh142964 "(target = 0x%p)", __func__, (void *)tgt); 2654c06356bSdh142964 goto tgt_init_fail; 2664c06356bSdh142964 } 2674c06356bSdh142964 2684c06356bSdh142964 /* 2694c06356bSdh142964 * Allocate LU soft state. We use ddi_soft_state_bystr_zalloc instead 2704c06356bSdh142964 * of kmem_alloc because ddi_soft_state_bystr_zalloc allows us to 2714c06356bSdh142964 * verify that the framework never tries to initialize two scsi_device 2724c06356bSdh142964 * structures with the same unit-address at the same time. 2734c06356bSdh142964 */ 2744c06356bSdh142964 if (ddi_soft_state_bystr_zalloc(tgt->lun_sstate, ua) != DDI_SUCCESS) { 275c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, phyp, tgt, 2764c06356bSdh142964 "Couldn't allocate LU soft state"); 2774c06356bSdh142964 goto tgt_init_fail; 2784c06356bSdh142964 } 2794c06356bSdh142964 2804c06356bSdh142964 lun = ddi_soft_state_bystr_get(tgt->lun_sstate, ua); 2814c06356bSdh142964 if (lun == NULL) { 282c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, phyp, tgt, 283c3bc407cSdh142964 "Couldn't get LU soft state"); 2844c06356bSdh142964 goto tgt_init_fail; 2854c06356bSdh142964 } 2864c06356bSdh142964 scsi_device_hba_private_set(sd, lun); 2874c06356bSdh142964 lun->lun_num = lun_num; 2884c06356bSdh142964 2894c06356bSdh142964 /* convert the scsi_lun64_t value to SCSI standard form */ 2904c06356bSdh142964 lun->scsi_lun = scsi_lun64_to_lun(lun_num); 2914c06356bSdh142964 2924c06356bSdh142964 ASSERT(strlen(ua) < (PMCS_MAX_UA_SIZE - 1)); 2934c06356bSdh142964 bcopy(ua, lun->unit_address, strnlen(ua, PMCS_MAX_UA_SIZE - 1)); 2944c06356bSdh142964 2954c06356bSdh142964 lun->target = tgt; 2964c06356bSdh142964 2974c06356bSdh142964 /* 2984c06356bSdh142964 * If this is the first tran_tgt_init, add this target to our list 2994c06356bSdh142964 */ 3004c06356bSdh142964 if (tgt->target_num == PMCS_INVALID_TARGET_NUM) { 3014c06356bSdh142964 int target; 3024c06356bSdh142964 for (target = 0; target < pwp->max_dev; target++) { 3034c06356bSdh142964 if (pwp->targets[target] != NULL) { 3044c06356bSdh142964 continue; 3054c06356bSdh142964 } 3064c06356bSdh142964 3074c06356bSdh142964 pwp->targets[target] = tgt; 3084c06356bSdh142964 tgt->target_num = (uint16_t)target; 3094c06356bSdh142964 break; 3104c06356bSdh142964 } 3114c06356bSdh142964 3124c06356bSdh142964 if (target == pwp->max_dev) { 313c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 3144c06356bSdh142964 "Target list full."); 3154c06356bSdh142964 goto tgt_init_fail; 3164c06356bSdh142964 } 3174c06356bSdh142964 } 3184c06356bSdh142964 3194c06356bSdh142964 tgt->dip = sd->sd_dev; 320499cfd15SDavid Hollister tgt->sd = sd; 3214c06356bSdh142964 3224c06356bSdh142964 if (!pmcs_assign_device(pwp, tgt)) { 3234c06356bSdh142964 pmcs_release_scratch(pwp); 3244c06356bSdh142964 pwp->targets[tgt->target_num] = NULL; 3254c06356bSdh142964 tgt->target_num = PMCS_INVALID_TARGET_NUM; 3264c06356bSdh142964 tgt->phy = NULL; 327c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 3284c06356bSdh142964 "%s: pmcs_assign_device failed for target 0x%p", 3294c06356bSdh142964 __func__, (void *)tgt); 3304c06356bSdh142964 goto tgt_init_fail; 3314c06356bSdh142964 } 3324c06356bSdh142964 3334c06356bSdh142964 pmcs_release_scratch(pwp); 3344c06356bSdh142964 tgt->ref_count++; 3354c06356bSdh142964 3364c06356bSdh142964 (void) scsi_device_prop_update_int(sd, SCSI_DEVICE_PROP_PATH, 3374c06356bSdh142964 SCSI_ADDR_PROP_TARGET, (uint32_t)(tgt->target_num)); 3384c06356bSdh142964 3394c06356bSdh142964 /* SM-HBA */ 3404c06356bSdh142964 if (tgt->dtype == SATA) { 3414c06356bSdh142964 /* TCR in PSARC/1997/281 opinion */ 3424c06356bSdh142964 (void) scsi_device_prop_update_string(sd, 3434c06356bSdh142964 SCSI_DEVICE_PROP_PATH, "variant", variant_prop); 3444c06356bSdh142964 } 3454c06356bSdh142964 3464c06356bSdh142964 tgt->phy_addressable = PMCS_PHY_ADDRESSABLE(phyp); 3474c06356bSdh142964 3484c06356bSdh142964 if (tgt->phy_addressable) { 3494c06356bSdh142964 (void) scsi_device_prop_update_int(sd, SCSI_DEVICE_PROP_PATH, 3504c06356bSdh142964 SCSI_ADDR_PROP_SATA_PHY, phyp->phynum); 3514c06356bSdh142964 } 3524c06356bSdh142964 3534c06356bSdh142964 /* SM-HBA */ 3544c06356bSdh142964 (void) pmcs_smhba_set_scsi_device_props(pwp, phyp, sd); 355499cfd15SDavid Hollister /* 356499cfd15SDavid Hollister * Make sure attached port and target port pm props are updated 357499cfd15SDavid Hollister * By passing in 0s, we're not actually updating any values, but 358499cfd15SDavid Hollister * the properties should now get updated on the node. 359499cfd15SDavid Hollister */ 360499cfd15SDavid Hollister pmcs_update_phy_pm_props(phyp, 0, 0, B_TRUE); 3614c06356bSdh142964 3624c06356bSdh142964 mutex_exit(&tgt->statlock); 3634c06356bSdh142964 pmcs_unlock_phy(phyp); 3644c06356bSdh142964 mutex_exit(&pwp->lock); 3654c06356bSdh142964 scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port); 3664c06356bSdh142964 return (DDI_SUCCESS); 3674c06356bSdh142964 3684c06356bSdh142964 tgt_init_fail: 3694c06356bSdh142964 if (got_scratch) { 3704c06356bSdh142964 pmcs_release_scratch(pwp); 3714c06356bSdh142964 } 3724c06356bSdh142964 if (lun) { 3734c06356bSdh142964 ddi_soft_state_bystr_free(tgt->lun_sstate, ua); 3744c06356bSdh142964 } 3754c06356bSdh142964 if (phyp) { 3764c06356bSdh142964 mutex_exit(&tgt->statlock); 3774c06356bSdh142964 pmcs_unlock_phy(phyp); 3784c06356bSdh142964 /* 3794c06356bSdh142964 * phyp's ref count was incremented in pmcs_new_tport. 3804c06356bSdh142964 * We're failing configuration, we now need to decrement it. 3814c06356bSdh142964 */ 3824c06356bSdh142964 if (!IS_ROOT_PHY(phyp)) { 3834c06356bSdh142964 pmcs_dec_phy_ref_count(phyp); 3844c06356bSdh142964 } 3854c06356bSdh142964 phyp->target = NULL; 3864c06356bSdh142964 } 3874c06356bSdh142964 if (tgt && tgt->ref_count == 0) { 3884c06356bSdh142964 ddi_soft_state_bystr_free(iport->tgt_sstate, tgt_port); 3894c06356bSdh142964 } 3904c06356bSdh142964 if (pwp) { 3914c06356bSdh142964 mutex_exit(&pwp->lock); 3924c06356bSdh142964 } 3934c06356bSdh142964 if (tgt_port) { 3944c06356bSdh142964 scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port); 3954c06356bSdh142964 } 3964c06356bSdh142964 return (DDI_FAILURE); 3974c06356bSdh142964 } 3984c06356bSdh142964 3994c06356bSdh142964 static void 4004c06356bSdh142964 pmcs_scsa_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip, 4014c06356bSdh142964 scsi_hba_tran_t *tran, struct scsi_device *sd) 4024c06356bSdh142964 { 4034c06356bSdh142964 _NOTE(ARGUNUSED(hba_dip, tgt_dip)); 4044c06356bSdh142964 pmcs_hw_t *pwp; 4054c06356bSdh142964 pmcs_lun_t *lun; 4064c06356bSdh142964 pmcs_xscsi_t *target; 4074c06356bSdh142964 char *unit_address; 4084c06356bSdh142964 pmcs_phy_t *phyp; 4094c06356bSdh142964 4104c06356bSdh142964 if (scsi_hba_iport_unit_address(hba_dip) == NULL) { 4114c06356bSdh142964 pwp = TRAN2PMC(tran); 412c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 4134c06356bSdh142964 "%s: We don't enumerate devices on the HBA node", __func__); 4144c06356bSdh142964 return; 4154c06356bSdh142964 } 4164c06356bSdh142964 4174c06356bSdh142964 lun = (pmcs_lun_t *)scsi_device_hba_private_get(sd); 4184c06356bSdh142964 4194c06356bSdh142964 ASSERT((lun != NULL) && (lun->target != NULL)); 4204c06356bSdh142964 ASSERT(lun->target->ref_count > 0); 4214c06356bSdh142964 4224c06356bSdh142964 target = lun->target; 4234c06356bSdh142964 4244c06356bSdh142964 unit_address = lun->unit_address; 4254c06356bSdh142964 ddi_soft_state_bystr_free(lun->target->lun_sstate, unit_address); 4264c06356bSdh142964 4274c06356bSdh142964 pwp = ITRAN2PMC(tran); 4284c06356bSdh142964 mutex_enter(&pwp->lock); 4294c06356bSdh142964 mutex_enter(&target->statlock); 4304c06356bSdh142964 ASSERT(target->phy); 4314c06356bSdh142964 phyp = target->phy; 4324c06356bSdh142964 433af685682SSrikanth, Ramana if (target->recover_wait) { 434af685682SSrikanth, Ramana mutex_exit(&target->statlock); 435af685682SSrikanth, Ramana mutex_exit(&pwp->lock); 436af685682SSrikanth, Ramana pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, target, "%s: " 437af685682SSrikanth, Ramana "Target 0x%p in device state recovery, fail tran_tgt_free", 438af685682SSrikanth, Ramana __func__, (void *)target); 439af685682SSrikanth, Ramana return; 440af685682SSrikanth, Ramana } 441af685682SSrikanth, Ramana 4424c06356bSdh142964 /* 4434c06356bSdh142964 * If this target still has a PHY pointer and that PHY's target pointer 4444c06356bSdh142964 * has been cleared, then that PHY has been reaped. In that case, there 4454c06356bSdh142964 * would be no need to decrement the reference count 4464c06356bSdh142964 */ 4474c06356bSdh142964 if (phyp && !IS_ROOT_PHY(phyp) && phyp->target) { 4484c06356bSdh142964 pmcs_dec_phy_ref_count(phyp); 4494c06356bSdh142964 } 4504c06356bSdh142964 4514c06356bSdh142964 if (--target->ref_count == 0) { 4524c06356bSdh142964 /* 4534c06356bSdh142964 * Remove this target from our list. The target soft 4544c06356bSdh142964 * state will remain, and the device will remain registered 4554c06356bSdh142964 * with the hardware unless/until we're told the device 4564c06356bSdh142964 * physically went away. 4574c06356bSdh142964 */ 458c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, target, 4594c06356bSdh142964 "%s: Free target 0x%p (vtgt %d)", __func__, (void *)target, 4604c06356bSdh142964 target->target_num); 4614c06356bSdh142964 pwp->targets[target->target_num] = NULL; 4624c06356bSdh142964 target->target_num = PMCS_INVALID_TARGET_NUM; 4634c06356bSdh142964 /* 4644c06356bSdh142964 * If the target still has a PHY pointer, break the linkage 4654c06356bSdh142964 */ 4664c06356bSdh142964 if (phyp) { 4674c06356bSdh142964 phyp->target = NULL; 4684c06356bSdh142964 } 4694c06356bSdh142964 target->phy = NULL; 4704c06356bSdh142964 pmcs_destroy_target(target); 4714c06356bSdh142964 } else { 4724c06356bSdh142964 mutex_exit(&target->statlock); 4734c06356bSdh142964 } 4744c06356bSdh142964 4754c06356bSdh142964 mutex_exit(&pwp->lock); 4764c06356bSdh142964 } 4774c06356bSdh142964 4784c06356bSdh142964 static int 4794c06356bSdh142964 pmcs_scsa_start(struct scsi_address *ap, struct scsi_pkt *pkt) 4804c06356bSdh142964 { 4814c06356bSdh142964 pmcs_cmd_t *sp = PKT2CMD(pkt); 4824c06356bSdh142964 pmcs_hw_t *pwp = ADDR2PMC(ap); 4834c06356bSdh142964 pmcs_xscsi_t *xp; 4844c06356bSdh142964 boolean_t blocked; 4854c06356bSdh142964 uint32_t hba_state; 4864c06356bSdh142964 487c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, 488c3bc407cSdh142964 "%s: pkt %p sd %p cdb0=0x%02x dl=%lu", __func__, (void *)pkt, 4894c06356bSdh142964 (void *)scsi_address_device(&pkt->pkt_address), 4904c06356bSdh142964 pkt->pkt_cdbp[0] & 0xff, pkt->pkt_dma_len); 4914c06356bSdh142964 4924c06356bSdh142964 if (pkt->pkt_flags & FLAG_NOINTR) { 493c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL, 494c3bc407cSdh142964 "%s: nointr pkt", __func__); 4954c06356bSdh142964 return (TRAN_BADPKT); 4964c06356bSdh142964 } 4974c06356bSdh142964 4984c06356bSdh142964 sp->cmd_tag = 0; 4994c06356bSdh142964 pkt->pkt_state = pkt->pkt_statistics = 0; 5004c06356bSdh142964 pkt->pkt_reason = CMD_INCOMPLETE; 5014c06356bSdh142964 5024c06356bSdh142964 mutex_enter(&pwp->lock); 5034c06356bSdh142964 hba_state = pwp->state; 5044c06356bSdh142964 blocked = pwp->blocked; 5054c06356bSdh142964 mutex_exit(&pwp->lock); 5064c06356bSdh142964 5074c06356bSdh142964 if (hba_state != STATE_RUNNING) { 508c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 509c3bc407cSdh142964 "%s: hba dead", __func__); 5104c06356bSdh142964 return (TRAN_FATAL_ERROR); 5114c06356bSdh142964 } 5124c06356bSdh142964 5134c06356bSdh142964 xp = pmcs_addr2xp(ap, NULL, sp); 5144c06356bSdh142964 if (xp == NULL) { 515c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, 5164c06356bSdh142964 "%s: dropping due to null target", __func__); 517b18a19c2SJesse Butler goto dead_target; 5184c06356bSdh142964 } 5194c06356bSdh142964 ASSERT(mutex_owned(&xp->statlock)); 5204c06356bSdh142964 5214c06356bSdh142964 /* 522b18a19c2SJesse Butler * First, check to see if the device is gone. 5234c06356bSdh142964 */ 524b18a19c2SJesse Butler if (xp->dev_gone) { 525*601c90f1SSrikanth, Ramana xp->actv_pkts++; 5264c06356bSdh142964 mutex_exit(&xp->statlock); 527c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, xp, 528b18a19c2SJesse Butler "%s: dropping due to dead target 0x%p", 5294c06356bSdh142964 __func__, (void *)xp); 530b18a19c2SJesse Butler goto dead_target; 5314c06356bSdh142964 } 5324c06356bSdh142964 5334c06356bSdh142964 /* 5344c06356bSdh142964 * If we're blocked (quiesced) just return. 5354c06356bSdh142964 */ 5364c06356bSdh142964 if (blocked) { 537c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 538c3bc407cSdh142964 "%s: hba blocked", __func__); 539*601c90f1SSrikanth, Ramana xp->actv_pkts++; 5404c06356bSdh142964 mutex_exit(&xp->statlock); 5414c06356bSdh142964 mutex_enter(&xp->wqlock); 5424c06356bSdh142964 STAILQ_INSERT_TAIL(&xp->wq, sp, cmd_next); 5434c06356bSdh142964 mutex_exit(&xp->wqlock); 5444c06356bSdh142964 return (TRAN_ACCEPT); 5454c06356bSdh142964 } 5464c06356bSdh142964 5474c06356bSdh142964 /* 5484c06356bSdh142964 * If we're draining or resetting, queue and return. 5494c06356bSdh142964 */ 5504c06356bSdh142964 if (xp->draining || xp->resetting || xp->recover_wait) { 551*601c90f1SSrikanth, Ramana xp->actv_pkts++; 5524c06356bSdh142964 mutex_exit(&xp->statlock); 5534c06356bSdh142964 mutex_enter(&xp->wqlock); 5544c06356bSdh142964 STAILQ_INSERT_TAIL(&xp->wq, sp, cmd_next); 5554c06356bSdh142964 mutex_exit(&xp->wqlock); 556c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, xp, 5574c06356bSdh142964 "%s: draining/resetting/recovering (cnt %u)", 5584c06356bSdh142964 __func__, xp->actv_cnt); 5594c06356bSdh142964 /* 5604c06356bSdh142964 * By the time we get here, draining or 5614c06356bSdh142964 * resetting may have come and gone, not 5624c06356bSdh142964 * yet noticing that we had put something 5634c06356bSdh142964 * on the wait queue, so schedule a worker 5644c06356bSdh142964 * to look at this later. 5654c06356bSdh142964 */ 5664c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 5674c06356bSdh142964 return (TRAN_ACCEPT); 5684c06356bSdh142964 } 569*601c90f1SSrikanth, Ramana 570*601c90f1SSrikanth, Ramana xp->actv_pkts++; 5714c06356bSdh142964 mutex_exit(&xp->statlock); 5724c06356bSdh142964 5734c06356bSdh142964 /* 5744c06356bSdh142964 * Queue this command to the tail of the wait queue. 5754c06356bSdh142964 * This keeps us getting commands out of order. 5764c06356bSdh142964 */ 5774c06356bSdh142964 mutex_enter(&xp->wqlock); 5784c06356bSdh142964 STAILQ_INSERT_TAIL(&xp->wq, sp, cmd_next); 5794c06356bSdh142964 mutex_exit(&xp->wqlock); 5804c06356bSdh142964 5814c06356bSdh142964 /* 5824c06356bSdh142964 * Now run the queue for this device. 5834c06356bSdh142964 */ 5844c06356bSdh142964 (void) pmcs_scsa_wq_run_one(pwp, xp); 5854c06356bSdh142964 5864c06356bSdh142964 return (TRAN_ACCEPT); 5874c06356bSdh142964 588b18a19c2SJesse Butler dead_target: 5894c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS; 5904c06356bSdh142964 pkt->pkt_reason = CMD_DEV_GONE; 5914c06356bSdh142964 mutex_enter(&pwp->cq_lock); 5924c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 5934c06356bSdh142964 PMCS_CQ_RUN_LOCKED(pwp); 5944c06356bSdh142964 mutex_exit(&pwp->cq_lock); 5954c06356bSdh142964 return (TRAN_ACCEPT); 5964c06356bSdh142964 } 5974c06356bSdh142964 5984c06356bSdh142964 static int 5994c06356bSdh142964 pmcs_scsa_abort(struct scsi_address *ap, struct scsi_pkt *pkt) 6004c06356bSdh142964 { 6014c06356bSdh142964 pmcs_hw_t *pwp = ADDR2PMC(ap); 6024c06356bSdh142964 pmcs_cmd_t *sp = PKT2CMD(pkt); 6034c06356bSdh142964 pmcs_xscsi_t *xp = sp->cmd_target; 6044c06356bSdh142964 pmcs_phy_t *pptr; 6054c06356bSdh142964 uint32_t tag; 6064c06356bSdh142964 uint64_t lun; 6074c06356bSdh142964 pmcwork_t *pwrk; 6084c06356bSdh142964 6094c06356bSdh142964 mutex_enter(&pwp->lock); 6104c06356bSdh142964 if (pwp->state != STATE_RUNNING) { 6114c06356bSdh142964 mutex_exit(&pwp->lock); 612c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 613c3bc407cSdh142964 "%s: hba dead", __func__); 6144c06356bSdh142964 return (0); 6154c06356bSdh142964 } 6164c06356bSdh142964 mutex_exit(&pwp->lock); 6174c06356bSdh142964 6184c06356bSdh142964 if (sp->cmd_lun) { 6194c06356bSdh142964 lun = sp->cmd_lun->lun_num; 6204c06356bSdh142964 } else { 6214c06356bSdh142964 lun = 0; 6224c06356bSdh142964 } 6234c06356bSdh142964 if (xp == NULL) { 6244c06356bSdh142964 return (0); 6254c06356bSdh142964 } 6264c06356bSdh142964 6274c06356bSdh142964 /* 6284c06356bSdh142964 * See if we have a real work structure associated with this cmd. 6294c06356bSdh142964 */ 6304c06356bSdh142964 pwrk = pmcs_tag2wp(pwp, sp->cmd_tag); 6314c06356bSdh142964 if (pwrk && pwrk->arg == sp) { 6324c06356bSdh142964 tag = pwrk->htag; 6334c06356bSdh142964 pptr = pwrk->phy; 6344c06356bSdh142964 pwrk->timer = 0; /* we don't time this here */ 6354c06356bSdh142964 ASSERT(pwrk->state == PMCS_WORK_STATE_ONCHIP); 6364c06356bSdh142964 mutex_exit(&pwrk->lock); 6374c06356bSdh142964 pmcs_lock_phy(pptr); 6384c06356bSdh142964 if (pptr->dtype == SAS) { 6394c06356bSdh142964 if (pmcs_ssp_tmf(pwp, pptr, SAS_ABORT_TASK, tag, lun, 6404c06356bSdh142964 NULL)) { 6414c06356bSdh142964 pptr->abort_pending = 1; 6424c06356bSdh142964 pmcs_unlock_phy(pptr); 6434c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE); 6444c06356bSdh142964 return (0); 6454c06356bSdh142964 } 6464c06356bSdh142964 } else { 6474c06356bSdh142964 /* 6484c06356bSdh142964 * XXX: Was the command that was active an 6494c06356bSdh142964 * NCQ I/O command? 6504c06356bSdh142964 */ 6514c06356bSdh142964 pptr->need_rl_ext = 1; 6524c06356bSdh142964 if (pmcs_sata_abort_ncq(pwp, pptr)) { 6534c06356bSdh142964 pptr->abort_pending = 1; 6544c06356bSdh142964 pmcs_unlock_phy(pptr); 6554c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE); 6564c06356bSdh142964 return (0); 6574c06356bSdh142964 } 6584c06356bSdh142964 } 6594c06356bSdh142964 pptr->abort_pending = 1; 6604c06356bSdh142964 pmcs_unlock_phy(pptr); 6614c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE); 6624c06356bSdh142964 return (1); 6634c06356bSdh142964 } 6644c06356bSdh142964 if (pwrk) { 6654c06356bSdh142964 mutex_exit(&pwrk->lock); 6664c06356bSdh142964 } 6674c06356bSdh142964 /* 6684c06356bSdh142964 * Okay, those weren't the droids we were looking for. 6694c06356bSdh142964 * See if the command is on any of the wait queues. 6704c06356bSdh142964 */ 6714c06356bSdh142964 mutex_enter(&xp->wqlock); 6724c06356bSdh142964 sp = NULL; 6734c06356bSdh142964 STAILQ_FOREACH(sp, &xp->wq, cmd_next) { 6744c06356bSdh142964 if (sp == PKT2CMD(pkt)) { 6754c06356bSdh142964 STAILQ_REMOVE(&xp->wq, sp, pmcs_cmd, cmd_next); 6764c06356bSdh142964 break; 6774c06356bSdh142964 } 6784c06356bSdh142964 } 6794c06356bSdh142964 mutex_exit(&xp->wqlock); 6804c06356bSdh142964 if (sp) { 6814c06356bSdh142964 pkt->pkt_reason = CMD_ABORTED; 6824c06356bSdh142964 pkt->pkt_statistics |= STAT_ABORTED; 6834c06356bSdh142964 mutex_enter(&pwp->cq_lock); 6844c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 6854c06356bSdh142964 PMCS_CQ_RUN_LOCKED(pwp); 6864c06356bSdh142964 mutex_exit(&pwp->cq_lock); 6874c06356bSdh142964 return (1); 6884c06356bSdh142964 } 6894c06356bSdh142964 return (0); 6904c06356bSdh142964 } 6914c06356bSdh142964 6924c06356bSdh142964 /* 6934c06356bSdh142964 * SCSA reset functions 6944c06356bSdh142964 */ 6954c06356bSdh142964 static int 6964c06356bSdh142964 pmcs_scsa_reset(struct scsi_address *ap, int level) 6974c06356bSdh142964 { 6984c06356bSdh142964 pmcs_hw_t *pwp = ADDR2PMC(ap); 6994c06356bSdh142964 pmcs_phy_t *pptr; 7004c06356bSdh142964 pmcs_xscsi_t *xp; 7014c06356bSdh142964 uint64_t lun = (uint64_t)-1, *lp = NULL; 7024c06356bSdh142964 int rval; 7034c06356bSdh142964 7044c06356bSdh142964 mutex_enter(&pwp->lock); 7054c06356bSdh142964 if (pwp->state != STATE_RUNNING) { 7064c06356bSdh142964 mutex_exit(&pwp->lock); 707c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 708c3bc407cSdh142964 "%s: hba dead", __func__); 7094c06356bSdh142964 return (0); 7104c06356bSdh142964 } 7114c06356bSdh142964 mutex_exit(&pwp->lock); 7124c06356bSdh142964 7134c06356bSdh142964 switch (level) { 7144c06356bSdh142964 case RESET_ALL: 7154c06356bSdh142964 rval = 0; 7164c06356bSdh142964 break; 7174c06356bSdh142964 case RESET_LUN: 7184c06356bSdh142964 /* 7194c06356bSdh142964 * Point lp at lun so that pmcs_addr2xp 7204c06356bSdh142964 * will fill out the 64 bit lun number. 7214c06356bSdh142964 */ 7224c06356bSdh142964 lp = &lun; 7234c06356bSdh142964 /* FALLTHROUGH */ 7244c06356bSdh142964 case RESET_TARGET: 7254c06356bSdh142964 xp = pmcs_addr2xp(ap, lp, NULL); 7264c06356bSdh142964 if (xp == NULL) { 727c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 7284c06356bSdh142964 "%s: no xp found for this scsi address", __func__); 7294c06356bSdh142964 return (0); 7304c06356bSdh142964 } 7314c06356bSdh142964 732b18a19c2SJesse Butler if (xp->dev_gone) { 7334c06356bSdh142964 mutex_exit(&xp->statlock); 734c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 7354c06356bSdh142964 "%s: Target 0x%p has gone away", __func__, 7364c06356bSdh142964 (void *)xp); 7374c06356bSdh142964 return (0); 7384c06356bSdh142964 } 7394c06356bSdh142964 7404c06356bSdh142964 /* 7414c06356bSdh142964 * If we're already performing this action, or if device 7424c06356bSdh142964 * state recovery is already running, just return failure. 7434c06356bSdh142964 */ 7444c06356bSdh142964 if (xp->resetting || xp->recover_wait) { 7454c06356bSdh142964 mutex_exit(&xp->statlock); 7464c06356bSdh142964 return (0); 7474c06356bSdh142964 } 7484c06356bSdh142964 xp->reset_wait = 0; 7494c06356bSdh142964 xp->reset_success = 0; 7504c06356bSdh142964 xp->resetting = 1; 7514c06356bSdh142964 pptr = xp->phy; 7524c06356bSdh142964 mutex_exit(&xp->statlock); 7534c06356bSdh142964 7544c06356bSdh142964 if (pmcs_reset_dev(pwp, pptr, lun)) { 7554c06356bSdh142964 rval = 0; 7564c06356bSdh142964 } else { 7574c06356bSdh142964 rval = 1; 7584c06356bSdh142964 } 7594c06356bSdh142964 7604c06356bSdh142964 mutex_enter(&xp->statlock); 7614c06356bSdh142964 if (rval == 1) { 7624c06356bSdh142964 xp->reset_success = 1; 7634c06356bSdh142964 } 7644c06356bSdh142964 if (xp->reset_wait) { 7654c06356bSdh142964 xp->reset_wait = 0; 7664c06356bSdh142964 cv_signal(&xp->reset_cv); 7674c06356bSdh142964 } 7684c06356bSdh142964 xp->resetting = 0; 7694c06356bSdh142964 mutex_exit(&xp->statlock); 7704c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 7714c06356bSdh142964 break; 7724c06356bSdh142964 default: 7734c06356bSdh142964 rval = 0; 7744c06356bSdh142964 break; 7754c06356bSdh142964 } 7764c06356bSdh142964 7774c06356bSdh142964 return (rval); 7784c06356bSdh142964 } 7794c06356bSdh142964 7804c06356bSdh142964 static int 7814c06356bSdh142964 pmcs_scsi_reset_notify(struct scsi_address *ap, int flag, 7824c06356bSdh142964 void (*callback)(caddr_t), caddr_t arg) 7834c06356bSdh142964 { 7844c06356bSdh142964 pmcs_hw_t *pwp = ADDR2PMC(ap); 7854c06356bSdh142964 return (scsi_hba_reset_notify_setup(ap, flag, callback, arg, 7864c06356bSdh142964 &pwp->lock, &pwp->reset_notify_listf)); 7874c06356bSdh142964 } 7884c06356bSdh142964 7894c06356bSdh142964 7904c06356bSdh142964 static int 7914c06356bSdh142964 pmcs_cap(struct scsi_address *ap, char *cap, int val, int tonly, int set) 7924c06356bSdh142964 { 7934c06356bSdh142964 _NOTE(ARGUNUSED(val, tonly)); 7944c06356bSdh142964 int cidx, rval = 0; 7954c06356bSdh142964 pmcs_xscsi_t *xp; 7964c06356bSdh142964 7974c06356bSdh142964 cidx = scsi_hba_lookup_capstr(cap); 7984c06356bSdh142964 if (cidx == -1) { 7994c06356bSdh142964 return (-1); 8004c06356bSdh142964 } 8014c06356bSdh142964 8024c06356bSdh142964 xp = pmcs_addr2xp(ap, NULL, NULL); 8034c06356bSdh142964 if (xp == NULL) { 8044c06356bSdh142964 return (-1); 8054c06356bSdh142964 } 8064c06356bSdh142964 8074c06356bSdh142964 switch (cidx) { 8084c06356bSdh142964 case SCSI_CAP_DMA_MAX: 8094c06356bSdh142964 case SCSI_CAP_INITIATOR_ID: 8104c06356bSdh142964 if (set == 0) { 8114c06356bSdh142964 rval = INT_MAX; /* argh */ 8124c06356bSdh142964 } 8134c06356bSdh142964 break; 8144c06356bSdh142964 case SCSI_CAP_DISCONNECT: 8154c06356bSdh142964 case SCSI_CAP_SYNCHRONOUS: 8164c06356bSdh142964 case SCSI_CAP_WIDE_XFER: 8174c06356bSdh142964 case SCSI_CAP_PARITY: 8184c06356bSdh142964 case SCSI_CAP_ARQ: 8194c06356bSdh142964 case SCSI_CAP_UNTAGGED_QING: 8204c06356bSdh142964 if (set == 0) { 8214c06356bSdh142964 rval = 1; 8224c06356bSdh142964 } 8234c06356bSdh142964 break; 8244c06356bSdh142964 8254c06356bSdh142964 case SCSI_CAP_TAGGED_QING: 8264c06356bSdh142964 rval = 1; 8274c06356bSdh142964 break; 8284c06356bSdh142964 8294c06356bSdh142964 case SCSI_CAP_MSG_OUT: 8304c06356bSdh142964 case SCSI_CAP_RESET_NOTIFICATION: 8314c06356bSdh142964 case SCSI_CAP_QFULL_RETRIES: 8324c06356bSdh142964 case SCSI_CAP_QFULL_RETRY_INTERVAL: 8334c06356bSdh142964 break; 8344c06356bSdh142964 case SCSI_CAP_SCSI_VERSION: 8354c06356bSdh142964 if (set == 0) { 8364c06356bSdh142964 rval = SCSI_VERSION_3; 8374c06356bSdh142964 } 8384c06356bSdh142964 break; 8394c06356bSdh142964 case SCSI_CAP_INTERCONNECT_TYPE: 8404c06356bSdh142964 if (set) { 8414c06356bSdh142964 break; 8424c06356bSdh142964 } 8434c06356bSdh142964 if (xp->phy_addressable) { 8444c06356bSdh142964 rval = INTERCONNECT_SATA; 8454c06356bSdh142964 } else { 8464c06356bSdh142964 rval = INTERCONNECT_SAS; 8474c06356bSdh142964 } 8484c06356bSdh142964 break; 8494c06356bSdh142964 case SCSI_CAP_CDB_LEN: 8504c06356bSdh142964 if (set == 0) { 8514c06356bSdh142964 rval = 16; 8524c06356bSdh142964 } 8534c06356bSdh142964 break; 8544c06356bSdh142964 case SCSI_CAP_LUN_RESET: 8554c06356bSdh142964 if (set) { 8564c06356bSdh142964 break; 8574c06356bSdh142964 } 8584c06356bSdh142964 if (xp->dtype == SATA) { 8594c06356bSdh142964 rval = 0; 8604c06356bSdh142964 } else { 8614c06356bSdh142964 rval = 1; 8624c06356bSdh142964 } 8634c06356bSdh142964 break; 8644c06356bSdh142964 default: 8654c06356bSdh142964 rval = -1; 8664c06356bSdh142964 break; 8674c06356bSdh142964 } 8684c06356bSdh142964 mutex_exit(&xp->statlock); 869c3bc407cSdh142964 pmcs_prt(ADDR2PMC(ap), PMCS_PRT_DEBUG3, NULL, NULL, 8704c06356bSdh142964 "%s: cap %s val %d set %d rval %d", 8714c06356bSdh142964 __func__, cap, val, set, rval); 8724c06356bSdh142964 return (rval); 8734c06356bSdh142964 } 8744c06356bSdh142964 8754c06356bSdh142964 /* 8764c06356bSdh142964 * Returns with statlock held if the xp is found. 8774c06356bSdh142964 * Fills in pmcs_cmd_t with values if pmcs_cmd_t pointer non-NULL. 8784c06356bSdh142964 */ 8794c06356bSdh142964 static pmcs_xscsi_t * 8804c06356bSdh142964 pmcs_addr2xp(struct scsi_address *ap, uint64_t *lp, pmcs_cmd_t *sp) 8814c06356bSdh142964 { 8824c06356bSdh142964 pmcs_xscsi_t *xp; 8834c06356bSdh142964 pmcs_lun_t *lun = (pmcs_lun_t *) 8844c06356bSdh142964 scsi_device_hba_private_get(scsi_address_device(ap)); 8854c06356bSdh142964 8864c06356bSdh142964 if ((lun == NULL) || (lun->target == NULL)) { 8874c06356bSdh142964 return (NULL); 8884c06356bSdh142964 } 8894c06356bSdh142964 xp = lun->target; 8904c06356bSdh142964 mutex_enter(&xp->statlock); 8914c06356bSdh142964 892b18a19c2SJesse Butler if (xp->dev_gone || (xp->phy == NULL)) { 893*601c90f1SSrikanth, Ramana /* 894*601c90f1SSrikanth, Ramana * This may be a retried packet, so it's possible cmd_target 895*601c90f1SSrikanth, Ramana * and cmd_lun may still be populated. Clear them. 896*601c90f1SSrikanth, Ramana */ 897*601c90f1SSrikanth, Ramana if (sp != NULL) { 898*601c90f1SSrikanth, Ramana sp->cmd_target = NULL; 899*601c90f1SSrikanth, Ramana sp->cmd_lun = NULL; 900*601c90f1SSrikanth, Ramana } 9014c06356bSdh142964 mutex_exit(&xp->statlock); 9024c06356bSdh142964 return (NULL); 9034c06356bSdh142964 } 9044c06356bSdh142964 9054c06356bSdh142964 if (sp != NULL) { 9064c06356bSdh142964 sp->cmd_target = xp; 9074c06356bSdh142964 sp->cmd_lun = lun; 9084c06356bSdh142964 } 9094c06356bSdh142964 if (lp) { 9104c06356bSdh142964 *lp = lun->lun_num; 9114c06356bSdh142964 } 9124c06356bSdh142964 return (xp); 9134c06356bSdh142964 } 9144c06356bSdh142964 9154c06356bSdh142964 static int 9164c06356bSdh142964 pmcs_scsa_getcap(struct scsi_address *ap, char *cap, int whom) 9174c06356bSdh142964 { 9184c06356bSdh142964 int r; 9194c06356bSdh142964 if (cap == NULL) { 9204c06356bSdh142964 return (-1); 9214c06356bSdh142964 } 9224c06356bSdh142964 r = pmcs_cap(ap, cap, 0, whom, 0); 9234c06356bSdh142964 return (r); 9244c06356bSdh142964 } 9254c06356bSdh142964 9264c06356bSdh142964 static int 9274c06356bSdh142964 pmcs_scsa_setcap(struct scsi_address *ap, char *cap, int value, int whom) 9284c06356bSdh142964 { 9294c06356bSdh142964 int r; 9304c06356bSdh142964 if (cap == NULL) { 9314c06356bSdh142964 return (-1); 9324c06356bSdh142964 } 9334c06356bSdh142964 r = pmcs_cap(ap, cap, value, whom, 1); 9344c06356bSdh142964 return (r); 9354c06356bSdh142964 } 9364c06356bSdh142964 9374c06356bSdh142964 static int 9384c06356bSdh142964 pmcs_scsa_setup_pkt(struct scsi_pkt *pkt, int (*callback)(caddr_t), 9394c06356bSdh142964 caddr_t cbarg) 9404c06356bSdh142964 { 9414c06356bSdh142964 _NOTE(ARGUNUSED(callback, cbarg)); 9424c06356bSdh142964 pmcs_cmd_t *sp = pkt->pkt_ha_private; 9434c06356bSdh142964 9444c06356bSdh142964 bzero(sp, sizeof (pmcs_cmd_t)); 9454c06356bSdh142964 sp->cmd_pkt = pkt; 9464c06356bSdh142964 return (0); 9474c06356bSdh142964 } 9484c06356bSdh142964 9494c06356bSdh142964 static void 9504c06356bSdh142964 pmcs_scsa_teardown_pkt(struct scsi_pkt *pkt) 9514c06356bSdh142964 { 9524c06356bSdh142964 pmcs_cmd_t *sp = pkt->pkt_ha_private; 9534c06356bSdh142964 sp->cmd_target = NULL; 9544c06356bSdh142964 sp->cmd_lun = NULL; 9554c06356bSdh142964 } 9564c06356bSdh142964 9574c06356bSdh142964 static int 95896c4a178SChris Horne pmcs_smp_start(struct smp_pkt *smp_pkt) 9594c06356bSdh142964 { 9604c06356bSdh142964 struct pmcwork *pwrk; 9614c06356bSdh142964 const uint_t rdoff = SAS_SMP_MAX_PAYLOAD; 9624c06356bSdh142964 uint32_t msg[PMCS_MSG_SIZE], *ptr, htag, status; 9634c06356bSdh142964 uint64_t wwn; 96496c4a178SChris Horne pmcs_hw_t *pwp; 9654c06356bSdh142964 pmcs_phy_t *pptr; 9664c06356bSdh142964 pmcs_xscsi_t *xp; 9674c06356bSdh142964 uint_t reqsz, rspsz, will_retry; 9684c06356bSdh142964 int result; 9694c06356bSdh142964 97096c4a178SChris Horne pwp = smp_pkt->smp_pkt_address->smp_a_hba_tran->smp_tran_hba_private; 97196c4a178SChris Horne bcopy(smp_pkt->smp_pkt_address->smp_a_wwn, &wwn, SAS_WWN_BYTE_SIZE); 9724c06356bSdh142964 973c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, NULL, 974c3bc407cSdh142964 "%s: starting for wwn 0x%" PRIx64, __func__, wwn); 9754c06356bSdh142964 97696c4a178SChris Horne will_retry = smp_pkt->smp_pkt_will_retry; 9774c06356bSdh142964 9784c06356bSdh142964 (void) pmcs_acquire_scratch(pwp, B_TRUE); 97996c4a178SChris Horne reqsz = smp_pkt->smp_pkt_reqsize; 9804c06356bSdh142964 if (reqsz > SAS_SMP_MAX_PAYLOAD) { 9814c06356bSdh142964 reqsz = SAS_SMP_MAX_PAYLOAD; 9824c06356bSdh142964 } 98396c4a178SChris Horne (void) memcpy(pwp->scratch, smp_pkt->smp_pkt_req, reqsz); 9844c06356bSdh142964 98596c4a178SChris Horne rspsz = smp_pkt->smp_pkt_rspsize; 9864c06356bSdh142964 if (rspsz > SAS_SMP_MAX_PAYLOAD) { 9874c06356bSdh142964 rspsz = SAS_SMP_MAX_PAYLOAD; 9884c06356bSdh142964 } 9894c06356bSdh142964 9904c06356bSdh142964 /* 9914c06356bSdh142964 * The request size from the SMP driver always includes 4 bytes 9924c06356bSdh142964 * for the CRC. The PMCS chip, however, doesn't want to see those 9934c06356bSdh142964 * counts as part of the transfer size. 9944c06356bSdh142964 */ 9954c06356bSdh142964 reqsz -= 4; 9964c06356bSdh142964 9974c06356bSdh142964 pptr = pmcs_find_phy_by_wwn(pwp, wwn); 9984c06356bSdh142964 /* PHY is now locked */ 9994c06356bSdh142964 if (pptr == NULL || pptr->dtype != EXPANDER) { 10004c06356bSdh142964 if (pptr) { 10014c06356bSdh142964 pmcs_unlock_phy(pptr); 10024c06356bSdh142964 } 10034c06356bSdh142964 pmcs_release_scratch(pwp); 1004c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1005c3bc407cSdh142964 "%s: could not find phy", __func__); 100696c4a178SChris Horne smp_pkt->smp_pkt_reason = ENXIO; 10074c06356bSdh142964 return (DDI_FAILURE); 10084c06356bSdh142964 } 10094c06356bSdh142964 10104c06356bSdh142964 pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, pptr); 10114c06356bSdh142964 if (pwrk == NULL) { 10124c06356bSdh142964 pmcs_unlock_phy(pptr); 10134c06356bSdh142964 pmcs_release_scratch(pwp); 1014c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, 10154c06356bSdh142964 "%s: could not get work structure", __func__); 101696c4a178SChris Horne smp_pkt->smp_pkt_reason = will_retry ? EAGAIN : EBUSY; 10174c06356bSdh142964 return (DDI_FAILURE); 10184c06356bSdh142964 } 10194c06356bSdh142964 10204c06356bSdh142964 pwrk->arg = msg; 10214c06356bSdh142964 pwrk->dtype = EXPANDER; 10224c06356bSdh142964 mutex_enter(&pwp->iqp_lock[PMCS_IQ_OTHER]); 10234c06356bSdh142964 ptr = GET_IQ_ENTRY(pwp, PMCS_IQ_OTHER); 10244c06356bSdh142964 if (ptr == NULL) { 10254c06356bSdh142964 pmcs_pwork(pwp, pwrk); 10264c06356bSdh142964 mutex_exit(&pwp->iqp_lock[PMCS_IQ_OTHER]); 10274c06356bSdh142964 pmcs_unlock_phy(pptr); 10284c06356bSdh142964 pmcs_release_scratch(pwp); 1029c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1030c3bc407cSdh142964 "%s: could not get IQ entry", __func__); 103196c4a178SChris Horne smp_pkt->smp_pkt_reason = will_retry ? EAGAIN :EBUSY; 10324c06356bSdh142964 return (DDI_FAILURE); 10334c06356bSdh142964 } 10344c06356bSdh142964 msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_SMP_REQUEST)); 10354c06356bSdh142964 msg[1] = LE_32(pwrk->htag); 10364c06356bSdh142964 msg[2] = LE_32(pptr->device_id); 10374c06356bSdh142964 msg[3] = LE_32(SMP_INDIRECT_RESPONSE | SMP_INDIRECT_REQUEST); 10384c06356bSdh142964 msg[8] = LE_32(DWORD0(pwp->scratch_dma)); 10394c06356bSdh142964 msg[9] = LE_32(DWORD1(pwp->scratch_dma)); 10404c06356bSdh142964 msg[10] = LE_32(reqsz); 10414c06356bSdh142964 msg[11] = 0; 10424c06356bSdh142964 msg[12] = LE_32(DWORD0(pwp->scratch_dma+rdoff)); 10434c06356bSdh142964 msg[13] = LE_32(DWORD1(pwp->scratch_dma+rdoff)); 10444c06356bSdh142964 msg[14] = LE_32(rspsz); 10454c06356bSdh142964 msg[15] = 0; 10464c06356bSdh142964 10474c06356bSdh142964 COPY_MESSAGE(ptr, msg, PMCS_MSG_SIZE); 10486745c559SJesse Butler /* SMP serialization */ 10496745c559SJesse Butler pmcs_smp_acquire(pptr->iport); 10506745c559SJesse Butler 10514c06356bSdh142964 pwrk->state = PMCS_WORK_STATE_ONCHIP; 10524c06356bSdh142964 htag = pwrk->htag; 10534c06356bSdh142964 INC_IQ_ENTRY(pwp, PMCS_IQ_OTHER); 10544c06356bSdh142964 10554c06356bSdh142964 pmcs_unlock_phy(pptr); 105696c4a178SChris Horne WAIT_FOR(pwrk, smp_pkt->smp_pkt_timeout * 1000, result); 10574c06356bSdh142964 pmcs_pwork(pwp, pwrk); 1058*601c90f1SSrikanth, Ramana /* Release SMP lock before reacquiring PHY lock */ 10596745c559SJesse Butler pmcs_smp_release(pptr->iport); 1060*601c90f1SSrikanth, Ramana pmcs_lock_phy(pptr); 10616745c559SJesse Butler 10624c06356bSdh142964 if (result) { 10634c06356bSdh142964 pmcs_timed_out(pwp, htag, __func__); 10644c06356bSdh142964 if (pmcs_abort(pwp, pptr, htag, 0, 0)) { 1065c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, 10664c06356bSdh142964 "%s: Unable to issue SMP ABORT for htag 0x%08x", 10674c06356bSdh142964 __func__, htag); 10684c06356bSdh142964 } else { 1069c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, 10704c06356bSdh142964 "%s: Issuing SMP ABORT for htag 0x%08x", 10714c06356bSdh142964 __func__, htag); 10724c06356bSdh142964 } 10734c06356bSdh142964 pmcs_unlock_phy(pptr); 10744c06356bSdh142964 pmcs_release_scratch(pwp); 107596c4a178SChris Horne smp_pkt->smp_pkt_reason = ETIMEDOUT; 10764c06356bSdh142964 return (DDI_FAILURE); 10774c06356bSdh142964 } 10784c06356bSdh142964 status = LE_32(msg[2]); 10794c06356bSdh142964 if (status == PMCOUT_STATUS_OVERFLOW) { 10804c06356bSdh142964 status = PMCOUT_STATUS_OK; 108196c4a178SChris Horne smp_pkt->smp_pkt_reason = EOVERFLOW; 10824c06356bSdh142964 } 10834c06356bSdh142964 if (status != PMCOUT_STATUS_OK) { 10844c06356bSdh142964 const char *emsg = pmcs_status_str(status); 10854c06356bSdh142964 if (emsg == NULL) { 1086c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 10874c06356bSdh142964 "SMP operation failed (0x%x)", status); 10884c06356bSdh142964 } else { 1089c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 10904c06356bSdh142964 "SMP operation failed (%s)", emsg); 10914c06356bSdh142964 } 10924c06356bSdh142964 10934c06356bSdh142964 if ((status == PMCOUT_STATUS_ERROR_HW_TIMEOUT) || 10944c06356bSdh142964 (status == PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT)) { 109596c4a178SChris Horne smp_pkt->smp_pkt_reason = 109696c4a178SChris Horne will_retry ? EAGAIN : ETIMEDOUT; 10974c06356bSdh142964 result = DDI_FAILURE; 10984c06356bSdh142964 } else if (status == 10994c06356bSdh142964 PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS) { 11004c06356bSdh142964 xp = pptr->target; 11014c06356bSdh142964 if (xp == NULL) { 110296c4a178SChris Horne smp_pkt->smp_pkt_reason = EIO; 11034c06356bSdh142964 result = DDI_FAILURE; 11044c06356bSdh142964 goto out; 11054c06356bSdh142964 } 11064c06356bSdh142964 if (xp->dev_state != 11074c06356bSdh142964 PMCS_DEVICE_STATE_NON_OPERATIONAL) { 11084c06356bSdh142964 xp->dev_state = 11094c06356bSdh142964 PMCS_DEVICE_STATE_NON_OPERATIONAL; 1110c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, xp, 11114c06356bSdh142964 "%s: Got _IT_NEXUS_LOSS SMP status. " 11124c06356bSdh142964 "Tgt(0x%p) dev_state set to " 11134c06356bSdh142964 "_NON_OPERATIONAL", __func__, 11144c06356bSdh142964 (void *)xp); 11154c06356bSdh142964 } 11164c06356bSdh142964 /* ABORT any pending commands related to this device */ 11174c06356bSdh142964 if (pmcs_abort(pwp, pptr, pptr->device_id, 1, 1) != 0) { 11184c06356bSdh142964 pptr->abort_pending = 1; 111996c4a178SChris Horne smp_pkt->smp_pkt_reason = EIO; 11204c06356bSdh142964 result = DDI_FAILURE; 11214c06356bSdh142964 } 11224c06356bSdh142964 } else { 112396c4a178SChris Horne smp_pkt->smp_pkt_reason = will_retry ? EAGAIN : EIO; 11244c06356bSdh142964 result = DDI_FAILURE; 11254c06356bSdh142964 } 11264c06356bSdh142964 } else { 112796c4a178SChris Horne (void) memcpy(smp_pkt->smp_pkt_rsp, 11284c06356bSdh142964 &((uint8_t *)pwp->scratch)[rdoff], rspsz); 112996c4a178SChris Horne if (smp_pkt->smp_pkt_reason == EOVERFLOW) { 11304c06356bSdh142964 result = DDI_FAILURE; 11314c06356bSdh142964 } else { 11324c06356bSdh142964 result = DDI_SUCCESS; 11334c06356bSdh142964 } 11344c06356bSdh142964 } 11354c06356bSdh142964 out: 11364c06356bSdh142964 pmcs_unlock_phy(pptr); 11374c06356bSdh142964 pmcs_release_scratch(pwp); 11384c06356bSdh142964 return (result); 11394c06356bSdh142964 } 11404c06356bSdh142964 11414c06356bSdh142964 static int 11424c06356bSdh142964 pmcs_smp_init(dev_info_t *self, dev_info_t *child, 114396c4a178SChris Horne smp_hba_tran_t *tran, smp_device_t *smp_sd) 11444c06356bSdh142964 { 114596c4a178SChris Horne _NOTE(ARGUNUSED(tran, smp_sd)); 11464c06356bSdh142964 pmcs_iport_t *iport; 11474c06356bSdh142964 pmcs_hw_t *pwp; 11484c06356bSdh142964 pmcs_xscsi_t *tgt; 11494c06356bSdh142964 pmcs_phy_t *phy, *pphy; 11504c06356bSdh142964 uint64_t wwn; 11514c06356bSdh142964 char *addr, *tgt_port; 11524c06356bSdh142964 int ua_form = 1; 11534c06356bSdh142964 11544c06356bSdh142964 iport = ddi_get_soft_state(pmcs_iport_softstate, 11554c06356bSdh142964 ddi_get_instance(self)); 11564c06356bSdh142964 ASSERT(iport); 11574c06356bSdh142964 if (iport == NULL) 11584c06356bSdh142964 return (DDI_FAILURE); 11594c06356bSdh142964 pwp = iport->pwp; 11604c06356bSdh142964 ASSERT(pwp); 11614c06356bSdh142964 if (pwp == NULL) 11624c06356bSdh142964 return (DDI_FAILURE); 1163c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: %s", __func__, 11644c06356bSdh142964 ddi_get_name(child)); 11654c06356bSdh142964 11664c06356bSdh142964 /* Get "target-port" prop from devinfo node */ 11674c06356bSdh142964 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 11684c06356bSdh142964 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 11694c06356bSdh142964 SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_SUCCESS) { 1170c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: Failed to " 1171c3bc407cSdh142964 "lookup prop ("SCSI_ADDR_PROP_TARGET_PORT")", __func__); 11724c06356bSdh142964 /* Dont fail _smp_init() because we couldnt get/set a prop */ 11734c06356bSdh142964 return (DDI_SUCCESS); 11744c06356bSdh142964 } 11754c06356bSdh142964 11764c06356bSdh142964 /* 11774c06356bSdh142964 * Validate that this tran_tgt_init is for an active iport. 11784c06356bSdh142964 */ 11794c06356bSdh142964 if (iport->ua_state == UA_INACTIVE) { 1180c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1181c3bc407cSdh142964 "%s: Init on inactive iport for '%s'", __func__, tgt_port); 11824c06356bSdh142964 ddi_prop_free(tgt_port); 11834c06356bSdh142964 return (DDI_FAILURE); 11844c06356bSdh142964 } 11854c06356bSdh142964 11864c06356bSdh142964 mutex_enter(&pwp->lock); 11874c06356bSdh142964 11884c06356bSdh142964 /* Retrieve softstate using unit-address */ 11894c06356bSdh142964 tgt = pmcs_get_target(iport, tgt_port); 11904c06356bSdh142964 if (tgt == NULL) { 1191c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1192c3bc407cSdh142964 "%s: tgt softstate not found", __func__); 11934c06356bSdh142964 ddi_prop_free(tgt_port); 11944c06356bSdh142964 mutex_exit(&pwp->lock); 11954c06356bSdh142964 return (DDI_FAILURE); 11964c06356bSdh142964 } 11974c06356bSdh142964 11984c06356bSdh142964 phy = tgt->phy; 11994c06356bSdh142964 ASSERT(mutex_owned(&phy->phy_lock)); 12004c06356bSdh142964 12014c06356bSdh142964 if (IS_ROOT_PHY(phy)) { 12024c06356bSdh142964 /* Expander attached to HBA - don't ref_count it */ 12034c06356bSdh142964 wwn = pwp->sas_wwns[0]; 12044c06356bSdh142964 } else { 12054c06356bSdh142964 pmcs_inc_phy_ref_count(phy); 12064c06356bSdh142964 12074c06356bSdh142964 /* 12084c06356bSdh142964 * Parent (in topology) is also an expander 12094c06356bSdh142964 * Now that we've increased the ref count on phy, it's OK 12104c06356bSdh142964 * to drop the lock so we can acquire the parent's lock. 12114c06356bSdh142964 */ 12124c06356bSdh142964 pphy = phy->parent; 12134c06356bSdh142964 pmcs_unlock_phy(phy); 12144c06356bSdh142964 pmcs_lock_phy(pphy); 12154c06356bSdh142964 wwn = pmcs_barray2wwn(pphy->sas_address); 12164c06356bSdh142964 pmcs_unlock_phy(pphy); 12174c06356bSdh142964 pmcs_lock_phy(phy); 12184c06356bSdh142964 } 12194c06356bSdh142964 12204c06356bSdh142964 /* 12214c06356bSdh142964 * If this is the 1st smp_init, add this to our list. 12224c06356bSdh142964 */ 12234c06356bSdh142964 if (tgt->target_num == PMCS_INVALID_TARGET_NUM) { 12244c06356bSdh142964 int target; 12254c06356bSdh142964 for (target = 0; target < pwp->max_dev; target++) { 12264c06356bSdh142964 if (pwp->targets[target] != NULL) { 12274c06356bSdh142964 continue; 12284c06356bSdh142964 } 12294c06356bSdh142964 12304c06356bSdh142964 pwp->targets[target] = tgt; 12314c06356bSdh142964 tgt->target_num = (uint16_t)target; 12324c06356bSdh142964 tgt->assigned = 1; 12334c06356bSdh142964 tgt->dev_state = PMCS_DEVICE_STATE_OPERATIONAL; 12344c06356bSdh142964 break; 12354c06356bSdh142964 } 12364c06356bSdh142964 12374c06356bSdh142964 if (target == pwp->max_dev) { 1238c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, 12394c06356bSdh142964 "Target list full."); 12404c06356bSdh142964 goto smp_init_fail; 12414c06356bSdh142964 } 12424c06356bSdh142964 } 12434c06356bSdh142964 12444c06356bSdh142964 if (!pmcs_assign_device(pwp, tgt)) { 12454c06356bSdh142964 pwp->targets[tgt->target_num] = NULL; 1246c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, tgt, 12474c06356bSdh142964 "%s: pmcs_assign_device failed for target 0x%p", 12484c06356bSdh142964 __func__, (void *)tgt); 12494c06356bSdh142964 goto smp_init_fail; 12504c06356bSdh142964 } 12514c06356bSdh142964 1252499cfd15SDavid Hollister /* 1253499cfd15SDavid Hollister * Update the attached port and target port pm properties 1254499cfd15SDavid Hollister */ 1255499cfd15SDavid Hollister tgt->smpd = smp_sd; 1256499cfd15SDavid Hollister pmcs_update_phy_pm_props(phy, 0, 0, B_TRUE); 1257499cfd15SDavid Hollister 12584c06356bSdh142964 pmcs_unlock_phy(phy); 12594c06356bSdh142964 mutex_exit(&pwp->lock); 12604c06356bSdh142964 12614c06356bSdh142964 tgt->ref_count++; 12624c06356bSdh142964 tgt->dtype = phy->dtype; 12634c06356bSdh142964 12644c06356bSdh142964 addr = scsi_wwn_to_wwnstr(wwn, ua_form, NULL); 1265499cfd15SDavid Hollister if (smp_device_prop_update_string(smp_sd, SCSI_ADDR_PROP_ATTACHED_PORT, 1266499cfd15SDavid Hollister addr) != DDI_SUCCESS) { 1267c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: Failed to set " 1268c3bc407cSdh142964 "prop ("SCSI_ADDR_PROP_ATTACHED_PORT")", __func__); 12694c06356bSdh142964 } 12704c06356bSdh142964 (void) scsi_free_wwnstr(addr); 12714c06356bSdh142964 ddi_prop_free(tgt_port); 12724c06356bSdh142964 return (DDI_SUCCESS); 12734c06356bSdh142964 12744c06356bSdh142964 smp_init_fail: 12754c06356bSdh142964 tgt->phy = NULL; 12764c06356bSdh142964 tgt->target_num = PMCS_INVALID_TARGET_NUM; 12774c06356bSdh142964 phy->target = NULL; 12784c06356bSdh142964 if (!IS_ROOT_PHY(phy)) { 12794c06356bSdh142964 pmcs_dec_phy_ref_count(phy); 12804c06356bSdh142964 } 12814c06356bSdh142964 pmcs_unlock_phy(phy); 12824c06356bSdh142964 mutex_exit(&pwp->lock); 12834c06356bSdh142964 ddi_soft_state_bystr_free(iport->tgt_sstate, tgt->unit_address); 12844c06356bSdh142964 ddi_prop_free(tgt_port); 12854c06356bSdh142964 return (DDI_FAILURE); 12864c06356bSdh142964 } 12874c06356bSdh142964 12884c06356bSdh142964 static void 12894c06356bSdh142964 pmcs_smp_free(dev_info_t *self, dev_info_t *child, 129096c4a178SChris Horne smp_hba_tran_t *tran, smp_device_t *smp) 12914c06356bSdh142964 { 12924c06356bSdh142964 _NOTE(ARGUNUSED(tran, smp)); 12934c06356bSdh142964 pmcs_iport_t *iport; 12944c06356bSdh142964 pmcs_hw_t *pwp; 12954c06356bSdh142964 pmcs_xscsi_t *tgt; 12964c06356bSdh142964 char *tgt_port; 12974c06356bSdh142964 12984c06356bSdh142964 iport = ddi_get_soft_state(pmcs_iport_softstate, 12994c06356bSdh142964 ddi_get_instance(self)); 13004c06356bSdh142964 ASSERT(iport); 13014c06356bSdh142964 if (iport == NULL) 13024c06356bSdh142964 return; 13034c06356bSdh142964 13044c06356bSdh142964 pwp = iport->pwp; 13054c06356bSdh142964 if (pwp == NULL) 13064c06356bSdh142964 return; 13074c06356bSdh142964 ASSERT(pwp); 1308c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: %s", __func__, 13094c06356bSdh142964 ddi_get_name(child)); 13104c06356bSdh142964 13114c06356bSdh142964 /* Get "target-port" prop from devinfo node */ 13124c06356bSdh142964 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 13134c06356bSdh142964 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 13144c06356bSdh142964 SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_SUCCESS) { 1315c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: Failed to " 1316c3bc407cSdh142964 "lookup prop ("SCSI_ADDR_PROP_TARGET_PORT")", __func__); 13174c06356bSdh142964 return; 13184c06356bSdh142964 } 13194c06356bSdh142964 /* Retrieve softstate using unit-address */ 13204c06356bSdh142964 tgt = ddi_soft_state_bystr_get(iport->tgt_sstate, tgt_port); 13214c06356bSdh142964 ddi_prop_free(tgt_port); 13224c06356bSdh142964 13234c06356bSdh142964 if (tgt == NULL) { 1324c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 1325c3bc407cSdh142964 "%s: tgt softstate not found", __func__); 13264c06356bSdh142964 return; 13274c06356bSdh142964 } 13284c06356bSdh142964 13294c06356bSdh142964 mutex_enter(&pwp->lock); 13304c06356bSdh142964 mutex_enter(&tgt->statlock); 13314c06356bSdh142964 if (tgt->phy) { 13324c06356bSdh142964 if (!IS_ROOT_PHY(tgt->phy)) { 13334c06356bSdh142964 pmcs_dec_phy_ref_count(tgt->phy); 13344c06356bSdh142964 } 13354c06356bSdh142964 } 13364c06356bSdh142964 13374c06356bSdh142964 if (--tgt->ref_count == 0) { 13384c06356bSdh142964 /* 13394c06356bSdh142964 * Remove this target from our list. The softstate 13404c06356bSdh142964 * will remain, and the device will remain registered 13414c06356bSdh142964 * with the hardware unless/until we're told that the 13424c06356bSdh142964 * device physically went away. 13434c06356bSdh142964 */ 1344c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, tgt, 13454c06356bSdh142964 "Removing target 0x%p (vtgt %d) from target list", 13464c06356bSdh142964 (void *)tgt, tgt->target_num); 13474c06356bSdh142964 pwp->targets[tgt->target_num] = NULL; 13484c06356bSdh142964 tgt->target_num = PMCS_INVALID_TARGET_NUM; 13494c06356bSdh142964 tgt->phy->target = NULL; 13504c06356bSdh142964 tgt->phy = NULL; 13514c06356bSdh142964 } 13524c06356bSdh142964 13534c06356bSdh142964 mutex_exit(&tgt->statlock); 13544c06356bSdh142964 mutex_exit(&pwp->lock); 13554c06356bSdh142964 } 13564c06356bSdh142964 13574c06356bSdh142964 static int 13584c06356bSdh142964 pmcs_scsi_quiesce(dev_info_t *dip) 13594c06356bSdh142964 { 13604c06356bSdh142964 pmcs_hw_t *pwp; 13614c06356bSdh142964 int totactive = -1; 13624c06356bSdh142964 pmcs_xscsi_t *xp; 13634c06356bSdh142964 uint16_t target; 13644c06356bSdh142964 13654c06356bSdh142964 if (ddi_get_soft_state(pmcs_iport_softstate, ddi_get_instance(dip))) 13664c06356bSdh142964 return (0); /* iport */ 13674c06356bSdh142964 13684c06356bSdh142964 pwp = ddi_get_soft_state(pmcs_softc_state, ddi_get_instance(dip)); 13694c06356bSdh142964 if (pwp == NULL) { 13704c06356bSdh142964 return (-1); 13714c06356bSdh142964 } 13724c06356bSdh142964 mutex_enter(&pwp->lock); 13734c06356bSdh142964 if (pwp->state != STATE_RUNNING) { 13744c06356bSdh142964 mutex_exit(&pwp->lock); 13754c06356bSdh142964 return (-1); 13764c06356bSdh142964 } 13774c06356bSdh142964 1378c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s called", __func__); 13794c06356bSdh142964 pwp->blocked = 1; 13804c06356bSdh142964 while (totactive) { 13814c06356bSdh142964 totactive = 0; 13824c06356bSdh142964 for (target = 0; target < pwp->max_dev; target++) { 13834c06356bSdh142964 xp = pwp->targets[target]; 13844c06356bSdh142964 if (xp == NULL) { 13854c06356bSdh142964 continue; 13864c06356bSdh142964 } 13874c06356bSdh142964 mutex_enter(&xp->statlock); 13884c06356bSdh142964 if (xp->actv_cnt) { 13894c06356bSdh142964 totactive += xp->actv_cnt; 13904c06356bSdh142964 xp->draining = 1; 13914c06356bSdh142964 } 13924c06356bSdh142964 mutex_exit(&xp->statlock); 13934c06356bSdh142964 } 13944c06356bSdh142964 if (totactive) { 13954c06356bSdh142964 cv_wait(&pwp->drain_cv, &pwp->lock); 13964c06356bSdh142964 } 13974c06356bSdh142964 /* 13984c06356bSdh142964 * The pwp->blocked may have been reset. e.g a SCSI bus reset 13994c06356bSdh142964 */ 14004c06356bSdh142964 pwp->blocked = 1; 14014c06356bSdh142964 } 14024c06356bSdh142964 14034c06356bSdh142964 for (target = 0; target < pwp->max_dev; target++) { 14044c06356bSdh142964 xp = pwp->targets[target]; 14054c06356bSdh142964 if (xp == NULL) { 14064c06356bSdh142964 continue; 14074c06356bSdh142964 } 14084c06356bSdh142964 mutex_enter(&xp->statlock); 14094c06356bSdh142964 xp->draining = 0; 14104c06356bSdh142964 mutex_exit(&xp->statlock); 14114c06356bSdh142964 } 14124c06356bSdh142964 14134c06356bSdh142964 mutex_exit(&pwp->lock); 14144c06356bSdh142964 if (totactive == 0) { 1415c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 1416c3bc407cSdh142964 "%s drain complete", __func__); 14174c06356bSdh142964 } 14184c06356bSdh142964 return (0); 14194c06356bSdh142964 } 14204c06356bSdh142964 14214c06356bSdh142964 static int 14224c06356bSdh142964 pmcs_scsi_unquiesce(dev_info_t *dip) 14234c06356bSdh142964 { 14244c06356bSdh142964 pmcs_hw_t *pwp; 14254c06356bSdh142964 14264c06356bSdh142964 if (ddi_get_soft_state(pmcs_iport_softstate, ddi_get_instance(dip))) 14274c06356bSdh142964 return (0); /* iport */ 14284c06356bSdh142964 14294c06356bSdh142964 pwp = ddi_get_soft_state(pmcs_softc_state, ddi_get_instance(dip)); 14304c06356bSdh142964 if (pwp == NULL) { 14314c06356bSdh142964 return (-1); 14324c06356bSdh142964 } 14334c06356bSdh142964 mutex_enter(&pwp->lock); 14344c06356bSdh142964 if (pwp->state != STATE_RUNNING) { 14354c06356bSdh142964 mutex_exit(&pwp->lock); 14364c06356bSdh142964 return (-1); 14374c06356bSdh142964 } 1438c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s called", __func__); 14394c06356bSdh142964 pwp->blocked = 0; 14404c06356bSdh142964 mutex_exit(&pwp->lock); 14414c06356bSdh142964 14424c06356bSdh142964 /* 14434c06356bSdh142964 * Run all pending commands. 14444c06356bSdh142964 */ 14454c06356bSdh142964 pmcs_scsa_wq_run(pwp); 14464c06356bSdh142964 14474c06356bSdh142964 /* 14484c06356bSdh142964 * Complete all completed commands. 14494c06356bSdh142964 * This also unlocks us. 14504c06356bSdh142964 */ 14514c06356bSdh142964 PMCS_CQ_RUN(pwp); 14524c06356bSdh142964 return (0); 14534c06356bSdh142964 } 14544c06356bSdh142964 14554c06356bSdh142964 /* 14564c06356bSdh142964 * Start commands for a particular device 14574c06356bSdh142964 * If the actual start of a command fails, return B_FALSE. Any other result 14584c06356bSdh142964 * is a B_TRUE return. 14594c06356bSdh142964 */ 14604c06356bSdh142964 boolean_t 14614c06356bSdh142964 pmcs_scsa_wq_run_one(pmcs_hw_t *pwp, pmcs_xscsi_t *xp) 14624c06356bSdh142964 { 14634c06356bSdh142964 pmcs_cmd_t *sp; 14644c06356bSdh142964 pmcs_phy_t *phyp; 14654c06356bSdh142964 pmcwork_t *pwrk; 14664c06356bSdh142964 boolean_t run_one, blocked; 14674c06356bSdh142964 int rval; 14684c06356bSdh142964 14694c06356bSdh142964 /* 14704c06356bSdh142964 * First, check to see if we're blocked or resource limited 14714c06356bSdh142964 */ 14724c06356bSdh142964 mutex_enter(&pwp->lock); 14734c06356bSdh142964 blocked = pwp->blocked; 14744c06356bSdh142964 /* 14754c06356bSdh142964 * If resource_limited is set, we're resource constrained and 14764c06356bSdh142964 * we will run only one work request for this target. 14774c06356bSdh142964 */ 14784c06356bSdh142964 run_one = pwp->resource_limited; 14794c06356bSdh142964 mutex_exit(&pwp->lock); 14804c06356bSdh142964 14814c06356bSdh142964 if (blocked) { 14824c06356bSdh142964 /* Queues will get restarted when we get unblocked */ 14834c06356bSdh142964 return (B_TRUE); 14844c06356bSdh142964 } 14854c06356bSdh142964 14864c06356bSdh142964 /* 14874c06356bSdh142964 * Might as well verify the queue is not empty before moving on 14884c06356bSdh142964 */ 14894c06356bSdh142964 mutex_enter(&xp->wqlock); 14904c06356bSdh142964 if (STAILQ_EMPTY(&xp->wq)) { 14914c06356bSdh142964 mutex_exit(&xp->wqlock); 14924c06356bSdh142964 return (B_TRUE); 14934c06356bSdh142964 } 14944c06356bSdh142964 mutex_exit(&xp->wqlock); 14954c06356bSdh142964 14964c06356bSdh142964 /* 14974c06356bSdh142964 * If we're draining or resetting, just reschedule work queue and bail. 14984c06356bSdh142964 */ 14994c06356bSdh142964 mutex_enter(&xp->statlock); 15004c06356bSdh142964 if (xp->draining || xp->resetting || xp->special_running || 15014c06356bSdh142964 xp->special_needed) { 15024c06356bSdh142964 mutex_exit(&xp->statlock); 15034c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 15044c06356bSdh142964 return (B_TRUE); 15054c06356bSdh142964 } 15064c06356bSdh142964 15074c06356bSdh142964 /* 1508b18a19c2SJesse Butler * Next, check to see if the target is gone. 15094c06356bSdh142964 */ 1510b18a19c2SJesse Butler if (xp->dev_gone) { 1511c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 1512b18a19c2SJesse Butler "%s: Flushing wait queue for dead tgt 0x%p", __func__, 15134c06356bSdh142964 (void *)xp); 15144c06356bSdh142964 pmcs_flush_target_queues(pwp, xp, PMCS_TGT_WAIT_QUEUE); 15154c06356bSdh142964 mutex_exit(&xp->statlock); 15164c06356bSdh142964 return (B_TRUE); 15174c06356bSdh142964 } 15184c06356bSdh142964 15194c06356bSdh142964 /* 15204c06356bSdh142964 * Increment the PHY's ref_count now so we know it won't go away 15214c06356bSdh142964 * after we drop the target lock. Drop it before returning. If the 15224c06356bSdh142964 * PHY dies, the commands we attempt to send will fail, but at least 15234c06356bSdh142964 * we know we have a real PHY pointer. 15244c06356bSdh142964 */ 15254c06356bSdh142964 phyp = xp->phy; 15264c06356bSdh142964 pmcs_inc_phy_ref_count(phyp); 15274c06356bSdh142964 mutex_exit(&xp->statlock); 15284c06356bSdh142964 15294c06356bSdh142964 mutex_enter(&xp->wqlock); 15304c06356bSdh142964 while ((sp = STAILQ_FIRST(&xp->wq)) != NULL) { 15314c06356bSdh142964 pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_CBACK, phyp); 15324c06356bSdh142964 if (pwrk == NULL) { 1533c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 15344c06356bSdh142964 "%s: out of work structures", __func__); 15354c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 15364c06356bSdh142964 break; 15374c06356bSdh142964 } 15384c06356bSdh142964 STAILQ_REMOVE_HEAD(&xp->wq, cmd_next); 15394c06356bSdh142964 mutex_exit(&xp->wqlock); 15404c06356bSdh142964 15414c06356bSdh142964 pwrk->xp = xp; 15424c06356bSdh142964 pwrk->arg = sp; 15434c06356bSdh142964 sp->cmd_tag = pwrk->htag; 15444c06356bSdh142964 pwrk->timer = US2WT(CMD2PKT(sp)->pkt_time * 1000000); 15454c06356bSdh142964 if (pwrk->timer == 0) { 15464c06356bSdh142964 pwrk->timer = US2WT(1000000); 15474c06356bSdh142964 } 15484c06356bSdh142964 15494c06356bSdh142964 pwrk->dtype = xp->dtype; 15504c06356bSdh142964 15514c06356bSdh142964 if (xp->dtype == SAS) { 15524c06356bSdh142964 pwrk->ptr = (void *) pmcs_SAS_done; 15534c06356bSdh142964 if ((rval = pmcs_SAS_run(sp, pwrk)) != 0) { 15544c06356bSdh142964 sp->cmd_tag = NULL; 15554c06356bSdh142964 pmcs_dec_phy_ref_count(phyp); 15564c06356bSdh142964 pmcs_pwork(pwp, pwrk); 15574c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 15584c06356bSdh142964 if (rval == PMCS_WQ_RUN_FAIL_RES) { 15594c06356bSdh142964 return (B_FALSE); 15604c06356bSdh142964 } else { 15614c06356bSdh142964 return (B_TRUE); 15624c06356bSdh142964 } 15634c06356bSdh142964 } 15644c06356bSdh142964 } else { 15654c06356bSdh142964 ASSERT(xp->dtype == SATA); 15664c06356bSdh142964 pwrk->ptr = (void *) pmcs_SATA_done; 15674c06356bSdh142964 if ((rval = pmcs_SATA_run(sp, pwrk)) != 0) { 15684c06356bSdh142964 sp->cmd_tag = NULL; 15694c06356bSdh142964 pmcs_dec_phy_ref_count(phyp); 15704c06356bSdh142964 pmcs_pwork(pwp, pwrk); 15714c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 15724c06356bSdh142964 if (rval == PMCS_WQ_RUN_FAIL_RES) { 15734c06356bSdh142964 return (B_FALSE); 15744c06356bSdh142964 } else { 15754c06356bSdh142964 return (B_TRUE); 15764c06356bSdh142964 } 15774c06356bSdh142964 } 15784c06356bSdh142964 } 15794c06356bSdh142964 15804c06356bSdh142964 if (run_one) { 15814c06356bSdh142964 goto wq_out; 15824c06356bSdh142964 } 15834c06356bSdh142964 mutex_enter(&xp->wqlock); 15844c06356bSdh142964 } 15854c06356bSdh142964 15864c06356bSdh142964 mutex_exit(&xp->wqlock); 15874c06356bSdh142964 15884c06356bSdh142964 wq_out: 15894c06356bSdh142964 pmcs_dec_phy_ref_count(phyp); 15904c06356bSdh142964 return (B_TRUE); 15914c06356bSdh142964 } 15924c06356bSdh142964 15934c06356bSdh142964 /* 15944c06356bSdh142964 * Start commands for all devices. 15954c06356bSdh142964 */ 15964c06356bSdh142964 void 15974c06356bSdh142964 pmcs_scsa_wq_run(pmcs_hw_t *pwp) 15984c06356bSdh142964 { 15994c06356bSdh142964 pmcs_xscsi_t *xp; 16004c06356bSdh142964 uint16_t target_start, target; 16014c06356bSdh142964 boolean_t rval = B_TRUE; 16024c06356bSdh142964 16034c06356bSdh142964 mutex_enter(&pwp->lock); 16044c06356bSdh142964 target_start = pwp->last_wq_dev; 16054c06356bSdh142964 target = target_start; 16064c06356bSdh142964 16074c06356bSdh142964 do { 16084c06356bSdh142964 xp = pwp->targets[target]; 16094c06356bSdh142964 if (xp == NULL) { 16104c06356bSdh142964 if (++target == pwp->max_dev) { 16114c06356bSdh142964 target = 0; 16124c06356bSdh142964 } 16134c06356bSdh142964 continue; 16144c06356bSdh142964 } 16154c06356bSdh142964 16164c06356bSdh142964 mutex_exit(&pwp->lock); 16174c06356bSdh142964 rval = pmcs_scsa_wq_run_one(pwp, xp); 16184c06356bSdh142964 if (rval == B_FALSE) { 16194c06356bSdh142964 mutex_enter(&pwp->lock); 16204c06356bSdh142964 break; 16214c06356bSdh142964 } 16224c06356bSdh142964 mutex_enter(&pwp->lock); 16234c06356bSdh142964 if (++target == pwp->max_dev) { 16244c06356bSdh142964 target = 0; 16254c06356bSdh142964 } 16264c06356bSdh142964 } while (target != target_start); 16274c06356bSdh142964 16284c06356bSdh142964 if (rval) { 16294c06356bSdh142964 pwp->resource_limited = 0; /* Not resource-constrained */ 16304c06356bSdh142964 } else { 16314c06356bSdh142964 pwp->resource_limited = 1; /* Give others a chance */ 16324c06356bSdh142964 } 16334c06356bSdh142964 16344c06356bSdh142964 pwp->last_wq_dev = target; 16354c06356bSdh142964 mutex_exit(&pwp->lock); 16364c06356bSdh142964 } 16374c06356bSdh142964 16384c06356bSdh142964 /* 16394c06356bSdh142964 * Pull the completion queue, drop the lock and complete all elements. 16404c06356bSdh142964 */ 16414c06356bSdh142964 16424c06356bSdh142964 void 16434c06356bSdh142964 pmcs_scsa_cq_run(void *arg) 16444c06356bSdh142964 { 16454c06356bSdh142964 pmcs_cq_thr_info_t *cqti = (pmcs_cq_thr_info_t *)arg; 16464c06356bSdh142964 pmcs_hw_t *pwp = cqti->cq_pwp; 16474c06356bSdh142964 pmcs_cmd_t *sp, *nxt; 16484c06356bSdh142964 struct scsi_pkt *pkt; 1649*601c90f1SSrikanth, Ramana pmcs_xscsi_t *tgt; 16504c06356bSdh142964 pmcs_iocomp_cb_t *ioccb, *ioccb_next; 16514c06356bSdh142964 pmcs_cb_t callback; 16524c06356bSdh142964 uint32_t niodone; 16534c06356bSdh142964 16544c06356bSdh142964 DTRACE_PROBE1(pmcs__scsa__cq__run__start, pmcs_cq_thr_info_t *, cqti); 16554c06356bSdh142964 16564c06356bSdh142964 mutex_enter(&pwp->cq_lock); 16574c06356bSdh142964 16584c06356bSdh142964 while (!pwp->cq_info.cq_stop) { 16594c06356bSdh142964 /* 16604c06356bSdh142964 * First, check the I/O completion callback queue. 16614c06356bSdh142964 */ 16624c06356bSdh142964 16634c06356bSdh142964 ioccb = pwp->iocomp_cb_head; 16644c06356bSdh142964 pwp->iocomp_cb_head = NULL; 16654c06356bSdh142964 pwp->iocomp_cb_tail = NULL; 16664c06356bSdh142964 mutex_exit(&pwp->cq_lock); 16674c06356bSdh142964 16684c06356bSdh142964 niodone = 0; 16694c06356bSdh142964 16704c06356bSdh142964 while (ioccb) { 16714c06356bSdh142964 niodone++; 16724c06356bSdh142964 /* 16734c06356bSdh142964 * Grab the lock on the work structure. The callback 16744c06356bSdh142964 * routine is responsible for clearing it. 16754c06356bSdh142964 */ 16764c06356bSdh142964 mutex_enter(&ioccb->pwrk->lock); 16774c06356bSdh142964 ioccb_next = ioccb->next; 16784c06356bSdh142964 callback = (pmcs_cb_t)ioccb->pwrk->ptr; 16794c06356bSdh142964 (*callback)(pwp, ioccb->pwrk, 16804c06356bSdh142964 (uint32_t *)((void *)ioccb->iomb)); 16814c06356bSdh142964 kmem_cache_free(pwp->iocomp_cb_cache, ioccb); 16824c06356bSdh142964 ioccb = ioccb_next; 16834c06356bSdh142964 } 16844c06356bSdh142964 16854c06356bSdh142964 /* 16864c06356bSdh142964 * Next, run the completion queue 16874c06356bSdh142964 */ 16884c06356bSdh142964 16894c06356bSdh142964 mutex_enter(&pwp->cq_lock); 16904c06356bSdh142964 sp = STAILQ_FIRST(&pwp->cq); 16914c06356bSdh142964 STAILQ_INIT(&pwp->cq); 16924c06356bSdh142964 mutex_exit(&pwp->cq_lock); 16934c06356bSdh142964 16944c06356bSdh142964 DTRACE_PROBE1(pmcs__scsa__cq__run__start__loop, 16954c06356bSdh142964 pmcs_cq_thr_info_t *, cqti); 16964c06356bSdh142964 16974c06356bSdh142964 if (sp && pmcs_check_acc_dma_handle(pwp)) { 16984c06356bSdh142964 ddi_fm_service_impact(pwp->dip, DDI_SERVICE_UNAFFECTED); 16994c06356bSdh142964 } 17004c06356bSdh142964 17014c06356bSdh142964 while (sp) { 17024c06356bSdh142964 nxt = STAILQ_NEXT(sp, cmd_next); 17034c06356bSdh142964 pkt = CMD2PKT(sp); 1704*601c90f1SSrikanth, Ramana tgt = sp->cmd_target; 1705*601c90f1SSrikanth, Ramana pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, tgt, 17064c06356bSdh142964 "%s: calling completion on %p for tgt %p", __func__, 1707*601c90f1SSrikanth, Ramana (void *)sp, (void *)tgt); 1708*601c90f1SSrikanth, Ramana if (tgt) { 1709*601c90f1SSrikanth, Ramana mutex_enter(&tgt->statlock); 1710*601c90f1SSrikanth, Ramana ASSERT(tgt->actv_pkts != 0); 1711*601c90f1SSrikanth, Ramana tgt->actv_pkts--; 1712*601c90f1SSrikanth, Ramana mutex_exit(&tgt->statlock); 1713*601c90f1SSrikanth, Ramana } 17144c06356bSdh142964 scsi_hba_pkt_comp(pkt); 17154c06356bSdh142964 sp = nxt; 17164c06356bSdh142964 } 17174c06356bSdh142964 17184c06356bSdh142964 DTRACE_PROBE1(pmcs__scsa__cq__run__end__loop, 17194c06356bSdh142964 pmcs_cq_thr_info_t *, cqti); 17204c06356bSdh142964 17214c06356bSdh142964 mutex_enter(&cqti->cq_thr_lock); 17224c06356bSdh142964 cv_wait(&cqti->cq_cv, &cqti->cq_thr_lock); 17234c06356bSdh142964 mutex_exit(&cqti->cq_thr_lock); 17244c06356bSdh142964 17254c06356bSdh142964 mutex_enter(&pwp->cq_lock); 17264c06356bSdh142964 } 17274c06356bSdh142964 17284c06356bSdh142964 mutex_exit(&pwp->cq_lock); 17294c06356bSdh142964 DTRACE_PROBE1(pmcs__scsa__cq__run__stop, pmcs_cq_thr_info_t *, cqti); 17304c06356bSdh142964 thread_exit(); 17314c06356bSdh142964 } 17324c06356bSdh142964 17334c06356bSdh142964 /* 17344c06356bSdh142964 * Run a SAS command. Called with pwrk->lock held, returns unlocked. 17354c06356bSdh142964 */ 17364c06356bSdh142964 static int 17374c06356bSdh142964 pmcs_SAS_run(pmcs_cmd_t *sp, pmcwork_t *pwrk) 17384c06356bSdh142964 { 17394c06356bSdh142964 pmcs_hw_t *pwp = CMD2PMC(sp); 17404c06356bSdh142964 struct scsi_pkt *pkt = CMD2PKT(sp); 17414c06356bSdh142964 pmcs_xscsi_t *xp = pwrk->xp; 17424c06356bSdh142964 uint32_t iq, *ptr; 17434c06356bSdh142964 sas_ssp_cmd_iu_t sc; 17444c06356bSdh142964 17454c06356bSdh142964 mutex_enter(&xp->statlock); 1746b18a19c2SJesse Butler if (!xp->assigned) { 17474c06356bSdh142964 mutex_exit(&xp->statlock); 17484c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_OTHER); 17494c06356bSdh142964 } 17504c06356bSdh142964 if ((xp->actv_cnt >= xp->qdepth) || xp->recover_wait) { 17514c06356bSdh142964 mutex_exit(&xp->statlock); 17524c06356bSdh142964 mutex_enter(&xp->wqlock); 17534c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 17544c06356bSdh142964 mutex_exit(&xp->wqlock); 17554c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_OTHER); 17564c06356bSdh142964 } 17574c06356bSdh142964 GET_IO_IQ_ENTRY(pwp, ptr, pwrk->phy->device_id, iq); 17584c06356bSdh142964 if (ptr == NULL) { 17594c06356bSdh142964 mutex_exit(&xp->statlock); 17604c06356bSdh142964 /* 17614c06356bSdh142964 * This is a temporary failure not likely to unblocked by 17624c06356bSdh142964 * commands completing as the test for scheduling the 17634c06356bSdh142964 * restart of work is a per-device test. 17644c06356bSdh142964 */ 17654c06356bSdh142964 mutex_enter(&xp->wqlock); 17664c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 17674c06356bSdh142964 mutex_exit(&xp->wqlock); 1768c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 17694c06356bSdh142964 "%s: Failed to get IO IQ entry for tgt %d", 17704c06356bSdh142964 __func__, xp->target_num); 17714c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_RES); 17724c06356bSdh142964 17734c06356bSdh142964 } 17744c06356bSdh142964 17754c06356bSdh142964 ptr[0] = 17764c06356bSdh142964 LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE, PMCIN_SSP_INI_IO_START)); 17774c06356bSdh142964 ptr[1] = LE_32(pwrk->htag); 17784c06356bSdh142964 ptr[2] = LE_32(pwrk->phy->device_id); 17794c06356bSdh142964 ptr[3] = LE_32(pkt->pkt_dma_len); 17804c06356bSdh142964 if (ptr[3]) { 17814c06356bSdh142964 ASSERT(pkt->pkt_numcookies); 17824c06356bSdh142964 if (pkt->pkt_dma_flags & DDI_DMA_READ) { 17834c06356bSdh142964 ptr[4] = LE_32(PMCIN_DATADIR_2_INI); 17844c06356bSdh142964 } else { 17854c06356bSdh142964 ptr[4] = LE_32(PMCIN_DATADIR_2_DEV); 17864c06356bSdh142964 } 17874c06356bSdh142964 if (pmcs_dma_load(pwp, sp, ptr)) { 17884c06356bSdh142964 mutex_exit(&pwp->iqp_lock[iq]); 17894c06356bSdh142964 mutex_exit(&xp->statlock); 17904c06356bSdh142964 mutex_enter(&xp->wqlock); 17914c06356bSdh142964 if (STAILQ_EMPTY(&xp->wq)) { 17924c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 17934c06356bSdh142964 mutex_exit(&xp->wqlock); 17944c06356bSdh142964 } else { 17954c06356bSdh142964 mutex_exit(&xp->wqlock); 17964c06356bSdh142964 CMD2PKT(sp)->pkt_scbp[0] = STATUS_QFULL; 17974c06356bSdh142964 CMD2PKT(sp)->pkt_reason = CMD_CMPLT; 17984c06356bSdh142964 CMD2PKT(sp)->pkt_state |= STATE_GOT_BUS | 17994c06356bSdh142964 STATE_GOT_TARGET | STATE_SENT_CMD | 18004c06356bSdh142964 STATE_GOT_STATUS; 18014c06356bSdh142964 mutex_enter(&pwp->cq_lock); 18024c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 18034c06356bSdh142964 mutex_exit(&pwp->cq_lock); 1804c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 18054c06356bSdh142964 "%s: Failed to dma_load for tgt %d (QF)", 18064c06356bSdh142964 __func__, xp->target_num); 18074c06356bSdh142964 } 18084c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_RES); 18094c06356bSdh142964 } 18104c06356bSdh142964 } else { 18114c06356bSdh142964 ptr[4] = LE_32(PMCIN_DATADIR_NONE); 18124c06356bSdh142964 CLEAN_MESSAGE(ptr, 12); 18134c06356bSdh142964 } 18144c06356bSdh142964 xp->actv_cnt++; 18154c06356bSdh142964 if (xp->actv_cnt > xp->maxdepth) { 18164c06356bSdh142964 xp->maxdepth = xp->actv_cnt; 1817c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pwrk->phy, xp, "%s: max depth " 1818c3bc407cSdh142964 "now %u", pwrk->phy->path, xp->maxdepth); 18194c06356bSdh142964 } 18204c06356bSdh142964 mutex_exit(&xp->statlock); 18214c06356bSdh142964 18224c06356bSdh142964 18234c06356bSdh142964 #ifdef DEBUG 18244c06356bSdh142964 /* 18254c06356bSdh142964 * Generate a PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED 18264c06356bSdh142964 * event when this goes out on the wire. 18274c06356bSdh142964 */ 18284c06356bSdh142964 ptr[4] |= PMCIN_MESSAGE_REPORT; 18294c06356bSdh142964 #endif 18304c06356bSdh142964 /* 18314c06356bSdh142964 * Fill in the SSP IU 18324c06356bSdh142964 */ 18334c06356bSdh142964 18344c06356bSdh142964 bzero(&sc, sizeof (sas_ssp_cmd_iu_t)); 18354c06356bSdh142964 bcopy((uint8_t *)&sp->cmd_lun->scsi_lun, sc.lun, sizeof (scsi_lun_t)); 18364c06356bSdh142964 18374c06356bSdh142964 switch (pkt->pkt_flags & FLAG_TAGMASK) { 18384c06356bSdh142964 case FLAG_HTAG: 18394c06356bSdh142964 sc.task_attribute = SAS_CMD_TASK_ATTR_HEAD; 18404c06356bSdh142964 break; 18414c06356bSdh142964 case FLAG_OTAG: 18424c06356bSdh142964 sc.task_attribute = SAS_CMD_TASK_ATTR_ORDERED; 18434c06356bSdh142964 break; 18444c06356bSdh142964 case FLAG_STAG: 18454c06356bSdh142964 default: 18464c06356bSdh142964 sc.task_attribute = SAS_CMD_TASK_ATTR_SIMPLE; 18474c06356bSdh142964 break; 18484c06356bSdh142964 } 18494c06356bSdh142964 (void) memcpy(sc.cdb, pkt->pkt_cdbp, 18504c06356bSdh142964 min(SCSA_CDBLEN(sp), sizeof (sc.cdb))); 18514c06356bSdh142964 (void) memcpy(&ptr[5], &sc, sizeof (sas_ssp_cmd_iu_t)); 18524c06356bSdh142964 pwrk->state = PMCS_WORK_STATE_ONCHIP; 18534c06356bSdh142964 mutex_exit(&pwrk->lock); 1854c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, 18554c06356bSdh142964 "%s: giving pkt %p (tag %x) to the hardware", __func__, 18564c06356bSdh142964 (void *)pkt, pwrk->htag); 18574c06356bSdh142964 #ifdef DEBUG 18584c06356bSdh142964 pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "SAS INI Message", ptr); 18594c06356bSdh142964 #endif 18604c06356bSdh142964 mutex_enter(&xp->aqlock); 18614c06356bSdh142964 STAILQ_INSERT_TAIL(&xp->aq, sp, cmd_next); 18624c06356bSdh142964 mutex_exit(&xp->aqlock); 18634c06356bSdh142964 INC_IQ_ENTRY(pwp, iq); 18644c06356bSdh142964 18654c06356bSdh142964 /* 18664c06356bSdh142964 * If we just submitted the last command queued from device state 18674c06356bSdh142964 * recovery, clear the wq_recovery_tail pointer. 18684c06356bSdh142964 */ 18694c06356bSdh142964 mutex_enter(&xp->wqlock); 18704c06356bSdh142964 if (xp->wq_recovery_tail == sp) { 18714c06356bSdh142964 xp->wq_recovery_tail = NULL; 18724c06356bSdh142964 } 18734c06356bSdh142964 mutex_exit(&xp->wqlock); 18744c06356bSdh142964 18754c06356bSdh142964 return (PMCS_WQ_RUN_SUCCESS); 18764c06356bSdh142964 } 18774c06356bSdh142964 18784c06356bSdh142964 /* 18794c06356bSdh142964 * Complete a SAS command 18804c06356bSdh142964 * 18814c06356bSdh142964 * Called with pwrk lock held. 18824c06356bSdh142964 * The free of pwrk releases the lock. 18834c06356bSdh142964 */ 18844c06356bSdh142964 18854c06356bSdh142964 static void 18864c06356bSdh142964 pmcs_SAS_done(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *msg) 18874c06356bSdh142964 { 18884c06356bSdh142964 pmcs_cmd_t *sp = pwrk->arg; 18894c06356bSdh142964 pmcs_phy_t *pptr = pwrk->phy; 18904c06356bSdh142964 pmcs_xscsi_t *xp = pwrk->xp; 18914c06356bSdh142964 struct scsi_pkt *pkt = CMD2PKT(sp); 18924c06356bSdh142964 int dead; 18934c06356bSdh142964 uint32_t sts; 18944c06356bSdh142964 boolean_t aborted = B_FALSE; 18954c06356bSdh142964 boolean_t do_ds_recovery = B_FALSE; 18964c06356bSdh142964 18974c06356bSdh142964 ASSERT(xp != NULL); 18984c06356bSdh142964 ASSERT(sp != NULL); 18994c06356bSdh142964 ASSERT(pptr != NULL); 19004c06356bSdh142964 19014c06356bSdh142964 DTRACE_PROBE4(pmcs__io__done, uint64_t, pkt->pkt_dma_len, int, 19024c06356bSdh142964 (pkt->pkt_dma_flags & DDI_DMA_READ) != 0, hrtime_t, pwrk->start, 19034c06356bSdh142964 hrtime_t, gethrtime()); 19044c06356bSdh142964 19054c06356bSdh142964 dead = pwrk->dead; 19064c06356bSdh142964 19074c06356bSdh142964 if (msg) { 19084c06356bSdh142964 sts = LE_32(msg[2]); 19094c06356bSdh142964 } else { 19104c06356bSdh142964 sts = 0; 19114c06356bSdh142964 } 19124c06356bSdh142964 19134c06356bSdh142964 if (dead != 0) { 1914c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, "%s: dead cmd tag " 1915c3bc407cSdh142964 "0x%x for %s", __func__, pwrk->htag, pptr->path); 19164c06356bSdh142964 goto out; 19174c06356bSdh142964 } 19184c06356bSdh142964 19194c06356bSdh142964 if (sts == PMCOUT_STATUS_ABORTED) { 19204c06356bSdh142964 aborted = B_TRUE; 19214c06356bSdh142964 } 19224c06356bSdh142964 19234c06356bSdh142964 if (pwrk->state == PMCS_WORK_STATE_TIMED_OUT) { 1924c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 19254c06356bSdh142964 "%s: cmd 0x%p (tag 0x%x) timed out for %s", 19264c06356bSdh142964 __func__, (void *)sp, pwrk->htag, pptr->path); 1927*601c90f1SSrikanth, Ramana CMD2PKT(sp)->pkt_scbp[0] = STATUS_GOOD; 1928*601c90f1SSrikanth, Ramana CMD2PKT(sp)->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | 1929*601c90f1SSrikanth, Ramana STATE_SENT_CMD; 1930*601c90f1SSrikanth, Ramana CMD2PKT(sp)->pkt_statistics |= STAT_TIMEOUT; 19314c06356bSdh142964 goto out; 19324c06356bSdh142964 } 19334c06356bSdh142964 19344c06356bSdh142964 /* 19354c06356bSdh142964 * If the status isn't okay but not underflow, 19364c06356bSdh142964 * step to the side and parse the (possible) error. 19374c06356bSdh142964 */ 19384c06356bSdh142964 #ifdef DEBUG 19394c06356bSdh142964 if (msg) { 19404c06356bSdh142964 pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "Outbound Message", msg); 19414c06356bSdh142964 } 19424c06356bSdh142964 #endif 19434c06356bSdh142964 if (!msg) { 19444c06356bSdh142964 goto out; 19454c06356bSdh142964 } 19464c06356bSdh142964 19474c06356bSdh142964 switch (sts) { 19484c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 19494c06356bSdh142964 case PMCOUT_STATUS_IO_DS_NON_OPERATIONAL: 19504c06356bSdh142964 case PMCOUT_STATUS_IO_DS_IN_RECOVERY: 1951c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 1952*601c90f1SSrikanth, Ramana "%s: PHY %s requires DS recovery (status=%d)", 19534c06356bSdh142964 __func__, pptr->path, sts); 19544c06356bSdh142964 do_ds_recovery = B_TRUE; 19554c06356bSdh142964 break; 19564c06356bSdh142964 case PMCOUT_STATUS_UNDERFLOW: 19574c06356bSdh142964 (void) pmcs_set_resid(pkt, pkt->pkt_dma_len, LE_32(msg[3])); 1958c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_UNDERFLOW, NULL, NULL, 19594c06356bSdh142964 "%s: underflow %u for cdb 0x%x", 19604c06356bSdh142964 __func__, LE_32(msg[3]), pkt->pkt_cdbp[0] & 0xff); 19614c06356bSdh142964 sts = PMCOUT_STATUS_OK; 19624c06356bSdh142964 msg[3] = 0; 19634c06356bSdh142964 break; 19644c06356bSdh142964 case PMCOUT_STATUS_OK: 19654c06356bSdh142964 pkt->pkt_resid = 0; 19664c06356bSdh142964 break; 19674c06356bSdh142964 } 19684c06356bSdh142964 19694c06356bSdh142964 if (sts != PMCOUT_STATUS_OK) { 19704c06356bSdh142964 pmcs_ioerror(pwp, SAS, pwrk, msg); 19714c06356bSdh142964 } else { 19724c06356bSdh142964 if (msg[3]) { 19734c06356bSdh142964 uint8_t local[PMCS_QENTRY_SIZE << 1], *xd; 19744c06356bSdh142964 sas_ssp_rsp_iu_t *rptr = (void *)local; 19754c06356bSdh142964 const int lim = 19764c06356bSdh142964 (PMCS_QENTRY_SIZE << 1) - SAS_RSP_HDR_SIZE; 19774c06356bSdh142964 static const uint8_t ssp_rsp_evec[] = { 19784c06356bSdh142964 0x58, 0x61, 0x56, 0x72, 0x00 19794c06356bSdh142964 }; 19804c06356bSdh142964 19814c06356bSdh142964 /* 19824c06356bSdh142964 * Transform the the first part of the response 19834c06356bSdh142964 * to host canonical form. This gives us enough 19844c06356bSdh142964 * information to figure out what to do with the 19854c06356bSdh142964 * rest (which remains unchanged in the incoming 19864c06356bSdh142964 * message which can be up to two queue entries 19874c06356bSdh142964 * in length). 19884c06356bSdh142964 */ 19894c06356bSdh142964 pmcs_endian_transform(pwp, local, &msg[5], 19904c06356bSdh142964 ssp_rsp_evec); 19914c06356bSdh142964 xd = (uint8_t *)(&msg[5]); 19924c06356bSdh142964 xd += SAS_RSP_HDR_SIZE; 19934c06356bSdh142964 19944c06356bSdh142964 if (rptr->datapres == SAS_RSP_DATAPRES_RESPONSE_DATA) { 19954c06356bSdh142964 if (rptr->response_data_length != 4) { 19964c06356bSdh142964 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, 19974c06356bSdh142964 "Bad SAS RESPONSE DATA LENGTH", 19984c06356bSdh142964 msg); 19994c06356bSdh142964 pkt->pkt_reason = CMD_TRAN_ERR; 20004c06356bSdh142964 goto out; 20014c06356bSdh142964 } 20024c06356bSdh142964 (void) memcpy(&sts, xd, sizeof (uint32_t)); 20034c06356bSdh142964 sts = BE_32(sts); 20044c06356bSdh142964 /* 20054c06356bSdh142964 * The only response code we should legally get 20064c06356bSdh142964 * here is an INVALID FRAME response code. 20074c06356bSdh142964 */ 20084c06356bSdh142964 if (sts == SAS_RSP_INVALID_FRAME) { 2009c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 20104c06356bSdh142964 "%s: pkt %p tgt %u path %s " 20114c06356bSdh142964 "completed: INVALID FRAME response", 20124c06356bSdh142964 __func__, (void *)pkt, 20134c06356bSdh142964 xp->target_num, pptr->path); 20144c06356bSdh142964 } else { 2015c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 20164c06356bSdh142964 "%s: pkt %p tgt %u path %s " 20174c06356bSdh142964 "completed: illegal response 0x%x", 20184c06356bSdh142964 __func__, (void *)pkt, 20194c06356bSdh142964 xp->target_num, pptr->path, sts); 20204c06356bSdh142964 } 20214c06356bSdh142964 pkt->pkt_reason = CMD_TRAN_ERR; 20224c06356bSdh142964 goto out; 20234c06356bSdh142964 } 20244c06356bSdh142964 if (rptr->datapres == SAS_RSP_DATAPRES_SENSE_DATA) { 20254c06356bSdh142964 uint32_t slen; 20264c06356bSdh142964 slen = rptr->sense_data_length; 20274c06356bSdh142964 if (slen > lim) { 20284c06356bSdh142964 slen = lim; 20294c06356bSdh142964 } 20304c06356bSdh142964 pmcs_latch_status(pwp, sp, rptr->status, xd, 20314c06356bSdh142964 slen, pptr->path); 20324c06356bSdh142964 } else if (rptr->datapres == SAS_RSP_DATAPRES_NO_DATA) { 20334b456463SDavid Hollister pmcout_ssp_comp_t *sspcp; 20344b456463SDavid Hollister sspcp = (pmcout_ssp_comp_t *)msg; 20354b456463SDavid Hollister uint32_t *residp; 20364c06356bSdh142964 /* 20374c06356bSdh142964 * This is the case for a plain SCSI status. 20384b456463SDavid Hollister * Note: If RESC_V is set and we're here, there 20394b456463SDavid Hollister * is a residual. We need to find it and update 20404b456463SDavid Hollister * the packet accordingly. 20414c06356bSdh142964 */ 20424c06356bSdh142964 pmcs_latch_status(pwp, sp, rptr->status, NULL, 20434c06356bSdh142964 0, pptr->path); 20444b456463SDavid Hollister 20454b456463SDavid Hollister if (sspcp->resc_v) { 20464b456463SDavid Hollister /* 20474b456463SDavid Hollister * Point residual to the SSP_RESP_IU 20484b456463SDavid Hollister */ 20494b456463SDavid Hollister residp = (uint32_t *)(sspcp + 1); 20504b456463SDavid Hollister /* 20514b456463SDavid Hollister * param contains the number of bytes 20524b456463SDavid Hollister * between where the SSP_RESP_IU may 20534b456463SDavid Hollister * or may not be and the residual. 20544b456463SDavid Hollister * Increment residp by the appropriate 20554b456463SDavid Hollister * number of words: (param+resc_pad)/4). 20564b456463SDavid Hollister */ 20574b456463SDavid Hollister residp += (LE_32(sspcp->param) + 20584b456463SDavid Hollister sspcp->resc_pad) / 20594b456463SDavid Hollister sizeof (uint32_t); 20604b456463SDavid Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG_UNDERFLOW, 20614b456463SDavid Hollister pptr, xp, "%s: tgt 0x%p " 20624b456463SDavid Hollister "residual %d for pkt 0x%p", 20634b456463SDavid Hollister __func__, (void *) xp, *residp, 20644b456463SDavid Hollister (void *) pkt); 20654b456463SDavid Hollister ASSERT(LE_32(*residp) <= 20664b456463SDavid Hollister pkt->pkt_dma_len); 20674b456463SDavid Hollister (void) pmcs_set_resid(pkt, 20684b456463SDavid Hollister pkt->pkt_dma_len, LE_32(*residp)); 20694b456463SDavid Hollister } 20704c06356bSdh142964 } else { 20714c06356bSdh142964 pmcs_print_entry(pwp, PMCS_PRT_DEBUG, 20724c06356bSdh142964 "illegal SAS response", msg); 20734c06356bSdh142964 pkt->pkt_reason = CMD_TRAN_ERR; 20744c06356bSdh142964 goto out; 20754c06356bSdh142964 } 20764c06356bSdh142964 } else { 20774c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, 20784c06356bSdh142964 pptr->path); 20794c06356bSdh142964 } 20804c06356bSdh142964 if (pkt->pkt_dma_len) { 20814c06356bSdh142964 pkt->pkt_state |= STATE_XFERRED_DATA; 20824c06356bSdh142964 } 20834c06356bSdh142964 } 2084c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp, 20854c06356bSdh142964 "%s: pkt %p tgt %u done reason=%x state=%x resid=%ld status=%x", 20864c06356bSdh142964 __func__, (void *)pkt, xp->target_num, pkt->pkt_reason, 20874c06356bSdh142964 pkt->pkt_state, pkt->pkt_resid, pkt->pkt_scbp[0]); 20884c06356bSdh142964 20894c06356bSdh142964 if (pwrk->state == PMCS_WORK_STATE_ABORTED) { 2090c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 20914c06356bSdh142964 "%s: scsi_pkt 0x%p aborted for PHY %s; work = 0x%p", 20924c06356bSdh142964 __func__, (void *)pkt, pptr->path, (void *)pwrk); 20934c06356bSdh142964 aborted = B_TRUE; 20944c06356bSdh142964 } 20954c06356bSdh142964 20964c06356bSdh142964 out: 20974c06356bSdh142964 pmcs_pwork(pwp, pwrk); 20984c06356bSdh142964 pmcs_dma_unload(pwp, sp); 20994c06356bSdh142964 21004c06356bSdh142964 mutex_enter(&xp->statlock); 21014c06356bSdh142964 if (xp->dev_gone) { 21024c06356bSdh142964 mutex_exit(&xp->statlock); 2103c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp, 21044c06356bSdh142964 "%s: Completing command for dead target 0x%p", __func__, 21054c06356bSdh142964 (void *)xp); 21064c06356bSdh142964 return; 21074c06356bSdh142964 } 21084c06356bSdh142964 21094c06356bSdh142964 ASSERT(xp->actv_cnt > 0); 21104c06356bSdh142964 if (--(xp->actv_cnt) == 0) { 21114c06356bSdh142964 if (xp->draining) { 2112c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG1, pptr, xp, 21134c06356bSdh142964 "%s: waking up drain waiters", __func__); 21144c06356bSdh142964 cv_signal(&pwp->drain_cv); 21154c06356bSdh142964 } 21164c06356bSdh142964 } 21174c06356bSdh142964 mutex_exit(&xp->statlock); 21184c06356bSdh142964 if (dead == 0) { 21194c06356bSdh142964 #ifdef DEBUG 21204c06356bSdh142964 pmcs_cmd_t *wp; 21214c06356bSdh142964 mutex_enter(&xp->aqlock); 21224c06356bSdh142964 STAILQ_FOREACH(wp, &xp->aq, cmd_next) { 21234c06356bSdh142964 if (wp == sp) { 21244c06356bSdh142964 break; 21254c06356bSdh142964 } 21264c06356bSdh142964 } 21274c06356bSdh142964 ASSERT(wp != NULL); 21284c06356bSdh142964 #else 21294c06356bSdh142964 mutex_enter(&xp->aqlock); 21304c06356bSdh142964 #endif 21314c06356bSdh142964 STAILQ_REMOVE(&xp->aq, sp, pmcs_cmd, cmd_next); 21324c06356bSdh142964 if (aborted) { 2133c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 21344c06356bSdh142964 "%s: Aborted cmd for tgt 0x%p, signaling waiters", 21354c06356bSdh142964 __func__, (void *)xp); 21364c06356bSdh142964 cv_signal(&xp->abort_cv); 21374c06356bSdh142964 } 21384c06356bSdh142964 mutex_exit(&xp->aqlock); 21394c06356bSdh142964 } 21404c06356bSdh142964 21414c06356bSdh142964 /* 21424c06356bSdh142964 * If do_ds_recovery is set, we need to initiate device state 21434c06356bSdh142964 * recovery. In this case, we put this I/O back on the head of 21444c06356bSdh142964 * the wait queue to run again after recovery is complete 21454c06356bSdh142964 */ 21464c06356bSdh142964 if (do_ds_recovery) { 21474c06356bSdh142964 mutex_enter(&xp->statlock); 21484c06356bSdh142964 pmcs_start_dev_state_recovery(xp, pptr); 21494c06356bSdh142964 mutex_exit(&xp->statlock); 2150c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG1, pptr, xp, "%s: Putting cmd 0x%p " 2151c3bc407cSdh142964 "back on wq during recovery for tgt 0x%p", __func__, 2152c3bc407cSdh142964 (void *)sp, (void *)xp); 21534c06356bSdh142964 mutex_enter(&xp->wqlock); 21544c06356bSdh142964 if (xp->wq_recovery_tail == NULL) { 21554c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 21564c06356bSdh142964 } else { 21574c06356bSdh142964 /* 21584c06356bSdh142964 * If there are other I/Os waiting at the head due to 21594c06356bSdh142964 * device state recovery, add this one in the right spot 21604c06356bSdh142964 * to maintain proper order. 21614c06356bSdh142964 */ 21624c06356bSdh142964 STAILQ_INSERT_AFTER(&xp->wq, xp->wq_recovery_tail, sp, 21634c06356bSdh142964 cmd_next); 21644c06356bSdh142964 } 21654c06356bSdh142964 xp->wq_recovery_tail = sp; 21664c06356bSdh142964 mutex_exit(&xp->wqlock); 21674c06356bSdh142964 } else { 21684c06356bSdh142964 /* 21694c06356bSdh142964 * If we're not initiating device state recovery and this 21704c06356bSdh142964 * command was not "dead", put it on the completion queue 21714c06356bSdh142964 */ 21724c06356bSdh142964 if (!dead) { 21734c06356bSdh142964 mutex_enter(&pwp->cq_lock); 21744c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 21754c06356bSdh142964 mutex_exit(&pwp->cq_lock); 21764c06356bSdh142964 } 21774c06356bSdh142964 } 21784c06356bSdh142964 } 21794c06356bSdh142964 21804c06356bSdh142964 /* 21814c06356bSdh142964 * Run a SATA command (normal reads and writes), 21824c06356bSdh142964 * or block and schedule a SATL interpretation 21834c06356bSdh142964 * of the command. 21844c06356bSdh142964 * 21854c06356bSdh142964 * Called with pwrk lock held, returns unlocked. 21864c06356bSdh142964 */ 21874c06356bSdh142964 21884c06356bSdh142964 static int 21894c06356bSdh142964 pmcs_SATA_run(pmcs_cmd_t *sp, pmcwork_t *pwrk) 21904c06356bSdh142964 { 21914c06356bSdh142964 pmcs_hw_t *pwp = CMD2PMC(sp); 21924c06356bSdh142964 struct scsi_pkt *pkt = CMD2PKT(sp); 21934c06356bSdh142964 pmcs_xscsi_t *xp; 21944c06356bSdh142964 uint8_t cdb_base, asc, tag; 21954c06356bSdh142964 uint32_t *ptr, iq, nblk, i, mtype; 21964c06356bSdh142964 fis_t fis; 21974c06356bSdh142964 size_t amt; 21984c06356bSdh142964 uint64_t lba; 21994c06356bSdh142964 22004c06356bSdh142964 xp = pwrk->xp; 22014c06356bSdh142964 22024c06356bSdh142964 /* 22034c06356bSdh142964 * First, see if this is just a plain read/write command. 22044c06356bSdh142964 * If not, we have to queue it up for processing, block 22054c06356bSdh142964 * any additional commands from coming in, and wake up 22064c06356bSdh142964 * the thread that will process this command. 22074c06356bSdh142964 */ 22084c06356bSdh142964 cdb_base = pkt->pkt_cdbp[0] & 0x1f; 22094c06356bSdh142964 if (cdb_base != SCMD_READ && cdb_base != SCMD_WRITE) { 2210c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG1, NULL, NULL, 2211c3bc407cSdh142964 "%s: special SATA cmd %p", __func__, (void *)sp); 22124c06356bSdh142964 22134c06356bSdh142964 ASSERT(xp->phy != NULL); 22144c06356bSdh142964 pmcs_pwork(pwp, pwrk); 22154c06356bSdh142964 pmcs_lock_phy(xp->phy); 22164c06356bSdh142964 mutex_enter(&xp->statlock); 22174c06356bSdh142964 xp->special_needed = 1; /* Set the special_needed flag */ 22184c06356bSdh142964 STAILQ_INSERT_TAIL(&xp->sq, sp, cmd_next); 22194c06356bSdh142964 if (pmcs_run_sata_special(pwp, xp)) { 22204c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_SATA_RUN); 22214c06356bSdh142964 } 22224c06356bSdh142964 mutex_exit(&xp->statlock); 22234c06356bSdh142964 pmcs_unlock_phy(xp->phy); 22244c06356bSdh142964 22254c06356bSdh142964 return (PMCS_WQ_RUN_SUCCESS); 22264c06356bSdh142964 } 22274c06356bSdh142964 2228c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "%s: regular cmd", __func__); 22294c06356bSdh142964 22304c06356bSdh142964 mutex_enter(&xp->statlock); 2231b18a19c2SJesse Butler if (!xp->assigned) { 22324c06356bSdh142964 mutex_exit(&xp->statlock); 22334c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_OTHER); 22344c06356bSdh142964 } 22354c06356bSdh142964 if (xp->special_running || xp->special_needed || xp->recover_wait) { 22364c06356bSdh142964 mutex_exit(&xp->statlock); 22374c06356bSdh142964 mutex_enter(&xp->wqlock); 22384c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 22394c06356bSdh142964 mutex_exit(&xp->wqlock); 22404c06356bSdh142964 /* 22414c06356bSdh142964 * By the time we get here the special 22424c06356bSdh142964 * commands running or waiting to be run 22434c06356bSdh142964 * may have come and gone, so kick our 22444c06356bSdh142964 * worker to run the waiting queues 22454c06356bSdh142964 * just in case. 22464c06356bSdh142964 */ 22474c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 22484c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_OTHER); 22494c06356bSdh142964 } 22504c06356bSdh142964 lba = xp->capacity; 22514c06356bSdh142964 mutex_exit(&xp->statlock); 22524c06356bSdh142964 22534c06356bSdh142964 /* 22544c06356bSdh142964 * Extract data length and lba parameters out of the command. The 22554c06356bSdh142964 * function pmcs_SATA_rwparm returns a non-zero ASC value if the CDB 22564c06356bSdh142964 * values are considered illegal. 22574c06356bSdh142964 */ 22584c06356bSdh142964 asc = pmcs_SATA_rwparm(pkt->pkt_cdbp, &nblk, &lba, lba); 22594c06356bSdh142964 if (asc) { 22604c06356bSdh142964 uint8_t sns[18]; 22614c06356bSdh142964 bzero(sns, sizeof (sns)); 22624c06356bSdh142964 sns[0] = 0xf0; 22634c06356bSdh142964 sns[2] = 0x5; 22644c06356bSdh142964 sns[12] = asc; 22654c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_CHECK, sns, sizeof (sns), 22664c06356bSdh142964 pwrk->phy->path); 22674c06356bSdh142964 pmcs_pwork(pwp, pwrk); 22684c06356bSdh142964 mutex_enter(&pwp->cq_lock); 22694c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 22704c06356bSdh142964 PMCS_CQ_RUN_LOCKED(pwp); 22714c06356bSdh142964 mutex_exit(&pwp->cq_lock); 22724c06356bSdh142964 return (PMCS_WQ_RUN_SUCCESS); 22734c06356bSdh142964 } 22744c06356bSdh142964 22754c06356bSdh142964 /* 22764c06356bSdh142964 * If the command decodes as not moving any data, complete it here. 22774c06356bSdh142964 */ 22784c06356bSdh142964 amt = nblk; 22794c06356bSdh142964 amt <<= 9; 22804c06356bSdh142964 amt = pmcs_set_resid(pkt, amt, nblk << 9); 22814c06356bSdh142964 if (amt == 0) { 22824c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, 22834c06356bSdh142964 pwrk->phy->path); 22844c06356bSdh142964 pmcs_pwork(pwp, pwrk); 22854c06356bSdh142964 mutex_enter(&pwp->cq_lock); 22864c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 22874c06356bSdh142964 PMCS_CQ_RUN_LOCKED(pwp); 22884c06356bSdh142964 mutex_exit(&pwp->cq_lock); 22894c06356bSdh142964 return (PMCS_WQ_RUN_SUCCESS); 22904c06356bSdh142964 } 22914c06356bSdh142964 22924c06356bSdh142964 /* 22934c06356bSdh142964 * Get an inbound queue entry for this I/O 22944c06356bSdh142964 */ 22954c06356bSdh142964 GET_IO_IQ_ENTRY(pwp, ptr, xp->phy->device_id, iq); 22964c06356bSdh142964 if (ptr == NULL) { 22974c06356bSdh142964 /* 22984c06356bSdh142964 * This is a temporary failure not likely to unblocked by 22994c06356bSdh142964 * commands completing as the test for scheduling the 23004c06356bSdh142964 * restart of work is a per-device test. 23014c06356bSdh142964 */ 23024c06356bSdh142964 mutex_enter(&xp->wqlock); 23034c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 23044c06356bSdh142964 mutex_exit(&xp->wqlock); 23054c06356bSdh142964 pmcs_dma_unload(pwp, sp); 23064c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 2307c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 23084c06356bSdh142964 "%s: Failed to get IO IQ entry for tgt %d", 23094c06356bSdh142964 __func__, xp->target_num); 23104c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_RES); 23114c06356bSdh142964 } 23124c06356bSdh142964 23134c06356bSdh142964 /* 23144c06356bSdh142964 * Get a tag. At this point, hold statlock until the tagmap is 23154c06356bSdh142964 * updated (just prior to sending the cmd to the hardware). 23164c06356bSdh142964 */ 23174c06356bSdh142964 mutex_enter(&xp->statlock); 23184c06356bSdh142964 for (tag = 0; tag < xp->qdepth; tag++) { 23194c06356bSdh142964 if ((xp->tagmap & (1 << tag)) == 0) { 23204c06356bSdh142964 break; 23214c06356bSdh142964 } 23224c06356bSdh142964 } 23234c06356bSdh142964 23244c06356bSdh142964 if (tag == xp->qdepth) { 23254c06356bSdh142964 mutex_exit(&xp->statlock); 23264c06356bSdh142964 mutex_exit(&pwp->iqp_lock[iq]); 23274c06356bSdh142964 mutex_enter(&xp->wqlock); 23284c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 23294c06356bSdh142964 mutex_exit(&xp->wqlock); 23304c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_OTHER); 23314c06356bSdh142964 } 23324c06356bSdh142964 23334c06356bSdh142964 sp->cmd_satltag = (uint8_t)tag; 23344c06356bSdh142964 23354c06356bSdh142964 /* 23364c06356bSdh142964 * Set up the command 23374c06356bSdh142964 */ 23384c06356bSdh142964 bzero(fis, sizeof (fis)); 23394c06356bSdh142964 ptr[0] = 23404c06356bSdh142964 LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE, PMCIN_SATA_HOST_IO_START)); 23414c06356bSdh142964 ptr[1] = LE_32(pwrk->htag); 23424c06356bSdh142964 ptr[2] = LE_32(pwrk->phy->device_id); 23434c06356bSdh142964 ptr[3] = LE_32(amt); 23444c06356bSdh142964 23454c06356bSdh142964 if (xp->ncq) { 23464c06356bSdh142964 mtype = SATA_PROTOCOL_FPDMA | (tag << 16); 23474c06356bSdh142964 fis[0] = ((nblk & 0xff) << 24) | (C_BIT << 8) | FIS_REG_H2DEV; 23484c06356bSdh142964 if (cdb_base == SCMD_READ) { 23494c06356bSdh142964 fis[0] |= (READ_FPDMA_QUEUED << 16); 23504c06356bSdh142964 } else { 23514c06356bSdh142964 fis[0] |= (WRITE_FPDMA_QUEUED << 16); 23524c06356bSdh142964 } 23534c06356bSdh142964 fis[1] = (FEATURE_LBA << 24) | (lba & 0xffffff); 23544c06356bSdh142964 fis[2] = ((nblk & 0xff00) << 16) | ((lba >> 24) & 0xffffff); 23554c06356bSdh142964 fis[3] = tag << 3; 23564c06356bSdh142964 } else { 23574c06356bSdh142964 int op; 23584c06356bSdh142964 fis[0] = (C_BIT << 8) | FIS_REG_H2DEV; 23594c06356bSdh142964 if (xp->pio) { 23604c06356bSdh142964 mtype = SATA_PROTOCOL_PIO; 23614c06356bSdh142964 if (cdb_base == SCMD_READ) { 23624c06356bSdh142964 op = READ_SECTORS_EXT; 23634c06356bSdh142964 } else { 23644c06356bSdh142964 op = WRITE_SECTORS_EXT; 23654c06356bSdh142964 } 23664c06356bSdh142964 } else { 23674c06356bSdh142964 mtype = SATA_PROTOCOL_DMA; 23684c06356bSdh142964 if (cdb_base == SCMD_READ) { 23694c06356bSdh142964 op = READ_DMA_EXT; 23704c06356bSdh142964 } else { 23714c06356bSdh142964 op = WRITE_DMA_EXT; 23724c06356bSdh142964 } 23734c06356bSdh142964 } 23744c06356bSdh142964 fis[0] |= (op << 16); 23754c06356bSdh142964 fis[1] = (FEATURE_LBA << 24) | (lba & 0xffffff); 23764c06356bSdh142964 fis[2] = (lba >> 24) & 0xffffff; 23774c06356bSdh142964 fis[3] = nblk; 23784c06356bSdh142964 } 23794c06356bSdh142964 23804c06356bSdh142964 if (cdb_base == SCMD_READ) { 23814c06356bSdh142964 ptr[4] = LE_32(mtype | PMCIN_DATADIR_2_INI); 23824c06356bSdh142964 } else { 23834c06356bSdh142964 ptr[4] = LE_32(mtype | PMCIN_DATADIR_2_DEV); 23844c06356bSdh142964 } 23854c06356bSdh142964 #ifdef DEBUG 23864c06356bSdh142964 /* 23874c06356bSdh142964 * Generate a PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED 23884c06356bSdh142964 * event when this goes out on the wire. 23894c06356bSdh142964 */ 23904c06356bSdh142964 ptr[4] |= PMCIN_MESSAGE_REPORT; 23914c06356bSdh142964 #endif 23924c06356bSdh142964 for (i = 0; i < (sizeof (fis_t))/(sizeof (uint32_t)); i++) { 23934c06356bSdh142964 ptr[i+5] = LE_32(fis[i]); 23944c06356bSdh142964 } 23954c06356bSdh142964 if (pmcs_dma_load(pwp, sp, ptr)) { 23964c06356bSdh142964 mutex_exit(&xp->statlock); 23974c06356bSdh142964 mutex_exit(&pwp->iqp_lock[iq]); 23984c06356bSdh142964 mutex_enter(&xp->wqlock); 23994c06356bSdh142964 STAILQ_INSERT_HEAD(&xp->wq, sp, cmd_next); 24004c06356bSdh142964 mutex_exit(&xp->wqlock); 2401c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, 24024c06356bSdh142964 "%s: Failed to dma_load for tgt %d", 24034c06356bSdh142964 __func__, xp->target_num); 24044c06356bSdh142964 return (PMCS_WQ_RUN_FAIL_RES); 24054c06356bSdh142964 24064c06356bSdh142964 } 24074c06356bSdh142964 24084c06356bSdh142964 pwrk->state = PMCS_WORK_STATE_ONCHIP; 24094c06356bSdh142964 mutex_exit(&pwrk->lock); 24104c06356bSdh142964 xp->tagmap |= (1 << tag); 24114c06356bSdh142964 xp->actv_cnt++; 24124c06356bSdh142964 if (xp->actv_cnt > xp->maxdepth) { 24134c06356bSdh142964 xp->maxdepth = xp->actv_cnt; 2414c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pwrk->phy, xp, 2415c3bc407cSdh142964 "%s: max depth now %u", pwrk->phy->path, xp->maxdepth); 24164c06356bSdh142964 } 24174c06356bSdh142964 mutex_exit(&xp->statlock); 24184c06356bSdh142964 mutex_enter(&xp->aqlock); 24194c06356bSdh142964 STAILQ_INSERT_TAIL(&xp->aq, sp, cmd_next); 24204c06356bSdh142964 mutex_exit(&xp->aqlock); 2421c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, 2422c3bc407cSdh142964 "%s: giving pkt %p to hardware", __func__, (void *)pkt); 24234c06356bSdh142964 #ifdef DEBUG 24244c06356bSdh142964 pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "SATA INI Message", ptr); 24254c06356bSdh142964 #endif 24264c06356bSdh142964 INC_IQ_ENTRY(pwp, iq); 24274c06356bSdh142964 24284c06356bSdh142964 return (PMCS_WQ_RUN_SUCCESS); 24294c06356bSdh142964 } 24304c06356bSdh142964 24314c06356bSdh142964 /* 24324c06356bSdh142964 * Complete a SATA command. Called with pwrk lock held. 24334c06356bSdh142964 */ 24344c06356bSdh142964 void 24354c06356bSdh142964 pmcs_SATA_done(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *msg) 24364c06356bSdh142964 { 24374c06356bSdh142964 pmcs_cmd_t *sp = pwrk->arg; 24384c06356bSdh142964 struct scsi_pkt *pkt = CMD2PKT(sp); 24394c06356bSdh142964 pmcs_phy_t *pptr = pwrk->phy; 24404c06356bSdh142964 int dead; 24414c06356bSdh142964 uint32_t sts; 24424c06356bSdh142964 pmcs_xscsi_t *xp; 24434c06356bSdh142964 boolean_t aborted = B_FALSE; 24444c06356bSdh142964 24454c06356bSdh142964 xp = pwrk->xp; 24464c06356bSdh142964 ASSERT(xp != NULL); 24474c06356bSdh142964 24484c06356bSdh142964 DTRACE_PROBE4(pmcs__io__done, uint64_t, pkt->pkt_dma_len, int, 24494c06356bSdh142964 (pkt->pkt_dma_flags & DDI_DMA_READ) != 0, hrtime_t, pwrk->start, 24504c06356bSdh142964 hrtime_t, gethrtime()); 24514c06356bSdh142964 24524c06356bSdh142964 dead = pwrk->dead; 24534c06356bSdh142964 24544c06356bSdh142964 if (msg) { 24554c06356bSdh142964 sts = LE_32(msg[2]); 24564c06356bSdh142964 } else { 24574c06356bSdh142964 sts = 0; 24584c06356bSdh142964 } 24594c06356bSdh142964 24604c06356bSdh142964 if (dead != 0) { 2461c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, "%s: dead cmd tag " 2462c3bc407cSdh142964 "0x%x for %s", __func__, pwrk->htag, pptr->path); 24634c06356bSdh142964 goto out; 24644c06356bSdh142964 } 24654c06356bSdh142964 if ((pwrk->state == PMCS_WORK_STATE_TIMED_OUT) && 24664c06356bSdh142964 (sts != PMCOUT_STATUS_ABORTED)) { 2467c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 24684c06356bSdh142964 "%s: cmd 0x%p (tag 0x%x) timed out for %s", 24694c06356bSdh142964 __func__, (void *)sp, pwrk->htag, pptr->path); 24704c06356bSdh142964 CMD2PKT(sp)->pkt_scbp[0] = STATUS_GOOD; 24714c06356bSdh142964 /* pkt_reason already set to CMD_TIMEOUT */ 24724c06356bSdh142964 ASSERT(CMD2PKT(sp)->pkt_reason == CMD_TIMEOUT); 24734c06356bSdh142964 CMD2PKT(sp)->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | 24744c06356bSdh142964 STATE_SENT_CMD; 24754c06356bSdh142964 CMD2PKT(sp)->pkt_statistics |= STAT_TIMEOUT; 24764c06356bSdh142964 goto out; 24774c06356bSdh142964 } 24784c06356bSdh142964 2479c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp, "%s: pkt %p tgt %u done", 24804c06356bSdh142964 __func__, (void *)pkt, xp->target_num); 24814c06356bSdh142964 24824c06356bSdh142964 /* 24834c06356bSdh142964 * If the status isn't okay but not underflow, 24844c06356bSdh142964 * step to the side and parse the (possible) error. 24854c06356bSdh142964 */ 24864c06356bSdh142964 #ifdef DEBUG 24874c06356bSdh142964 if (msg) { 24884c06356bSdh142964 pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "Outbound Message", msg); 24894c06356bSdh142964 } 24904c06356bSdh142964 #endif 24914c06356bSdh142964 if (!msg) { 24924c06356bSdh142964 goto out; 24934c06356bSdh142964 } 24944c06356bSdh142964 24954c06356bSdh142964 /* 24964c06356bSdh142964 * If the status isn't okay or we got a FIS response of some kind, 24974c06356bSdh142964 * step to the side and parse the (possible) error. 24984c06356bSdh142964 */ 24994c06356bSdh142964 if ((sts != PMCOUT_STATUS_OK) || (LE_32(msg[3]) != 0)) { 25004c06356bSdh142964 if (sts == PMCOUT_STATUS_IO_DS_NON_OPERATIONAL) { 25014c06356bSdh142964 mutex_exit(&pwrk->lock); 25024c06356bSdh142964 pmcs_lock_phy(pptr); 25034c06356bSdh142964 mutex_enter(&xp->statlock); 25044c06356bSdh142964 if ((xp->resetting == 0) && (xp->reset_success != 0) && 25054c06356bSdh142964 (xp->reset_wait == 0)) { 25064c06356bSdh142964 mutex_exit(&xp->statlock); 25074c06356bSdh142964 if (pmcs_reset_phy(pwp, pptr, 25084c06356bSdh142964 PMCS_PHYOP_LINK_RESET) != 0) { 2509c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 2510c3bc407cSdh142964 "%s: PHY (%s) Local Control/Link " 2511c3bc407cSdh142964 "Reset FAILED as part of error " 2512c3bc407cSdh142964 "recovery", __func__, pptr->path); 25134c06356bSdh142964 } 25144c06356bSdh142964 mutex_enter(&xp->statlock); 25154c06356bSdh142964 } 25164c06356bSdh142964 mutex_exit(&xp->statlock); 25174c06356bSdh142964 pmcs_unlock_phy(pptr); 25184c06356bSdh142964 mutex_enter(&pwrk->lock); 25194c06356bSdh142964 } 25204c06356bSdh142964 pmcs_ioerror(pwp, SATA, pwrk, msg); 25214c06356bSdh142964 } else { 25224c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, 25234c06356bSdh142964 pwrk->phy->path); 25244c06356bSdh142964 pkt->pkt_state |= STATE_XFERRED_DATA; 25254c06356bSdh142964 pkt->pkt_resid = 0; 25264c06356bSdh142964 } 25274c06356bSdh142964 2528c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp, 25294c06356bSdh142964 "%s: pkt %p tgt %u done reason=%x state=%x resid=%ld status=%x", 25304c06356bSdh142964 __func__, (void *)pkt, xp->target_num, pkt->pkt_reason, 25314c06356bSdh142964 pkt->pkt_state, pkt->pkt_resid, pkt->pkt_scbp[0]); 25324c06356bSdh142964 25334c06356bSdh142964 if (pwrk->state == PMCS_WORK_STATE_ABORTED) { 2534c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 25354c06356bSdh142964 "%s: scsi_pkt 0x%p aborted for PHY %s; work = 0x%p", 25364c06356bSdh142964 __func__, (void *)pkt, pptr->path, (void *)pwrk); 25374c06356bSdh142964 aborted = B_TRUE; 25384c06356bSdh142964 } 25394c06356bSdh142964 25404c06356bSdh142964 out: 25414c06356bSdh142964 pmcs_pwork(pwp, pwrk); 25424c06356bSdh142964 pmcs_dma_unload(pwp, sp); 25434c06356bSdh142964 25444c06356bSdh142964 mutex_enter(&xp->statlock); 25454c06356bSdh142964 xp->tagmap &= ~(1 << sp->cmd_satltag); 25464c06356bSdh142964 25474c06356bSdh142964 if (xp->dev_gone) { 25484c06356bSdh142964 mutex_exit(&xp->statlock); 2549c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, xp, 25504c06356bSdh142964 "%s: Completing command for dead target 0x%p", __func__, 25514c06356bSdh142964 (void *)xp); 25524c06356bSdh142964 return; 25534c06356bSdh142964 } 25544c06356bSdh142964 25554c06356bSdh142964 ASSERT(xp->actv_cnt > 0); 25564c06356bSdh142964 if (--(xp->actv_cnt) == 0) { 25574c06356bSdh142964 if (xp->draining) { 2558c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG1, pptr, xp, 25594c06356bSdh142964 "%s: waking up drain waiters", __func__); 25604c06356bSdh142964 cv_signal(&pwp->drain_cv); 25614c06356bSdh142964 } else if (xp->special_needed) { 25624c06356bSdh142964 SCHEDULE_WORK(pwp, PMCS_WORK_SATA_RUN); 25634c06356bSdh142964 } 25644c06356bSdh142964 } 25654c06356bSdh142964 mutex_exit(&xp->statlock); 25664c06356bSdh142964 25674c06356bSdh142964 if (dead == 0) { 25684c06356bSdh142964 #ifdef DEBUG 25694c06356bSdh142964 pmcs_cmd_t *wp; 25704c06356bSdh142964 mutex_enter(&xp->aqlock); 25714c06356bSdh142964 STAILQ_FOREACH(wp, &xp->aq, cmd_next) { 25724c06356bSdh142964 if (wp == sp) { 25734c06356bSdh142964 break; 25744c06356bSdh142964 } 25754c06356bSdh142964 } 25764c06356bSdh142964 ASSERT(wp != NULL); 25774c06356bSdh142964 #else 25784c06356bSdh142964 mutex_enter(&xp->aqlock); 25794c06356bSdh142964 #endif 25804c06356bSdh142964 STAILQ_REMOVE(&xp->aq, sp, pmcs_cmd, cmd_next); 25814c06356bSdh142964 if (aborted) { 2582c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, xp, 25834c06356bSdh142964 "%s: Aborted cmd for tgt 0x%p, signaling waiters", 25844c06356bSdh142964 __func__, (void *)xp); 25854c06356bSdh142964 cv_signal(&xp->abort_cv); 25864c06356bSdh142964 } 25874c06356bSdh142964 mutex_exit(&xp->aqlock); 25884c06356bSdh142964 mutex_enter(&pwp->cq_lock); 25894c06356bSdh142964 STAILQ_INSERT_TAIL(&pwp->cq, sp, cmd_next); 25904c06356bSdh142964 mutex_exit(&pwp->cq_lock); 25914c06356bSdh142964 } 25924c06356bSdh142964 } 25934c06356bSdh142964 25944c06356bSdh142964 static uint8_t 25954c06356bSdh142964 pmcs_SATA_rwparm(uint8_t *cdb, uint32_t *xfr, uint64_t *lba, uint64_t lbamax) 25964c06356bSdh142964 { 25974c06356bSdh142964 uint8_t asc = 0; 25984c06356bSdh142964 switch (cdb[0]) { 25994c06356bSdh142964 case SCMD_READ_G5: 26004c06356bSdh142964 case SCMD_WRITE_G5: 26014c06356bSdh142964 *xfr = 26024c06356bSdh142964 (((uint32_t)cdb[10]) << 24) | 26034c06356bSdh142964 (((uint32_t)cdb[11]) << 16) | 26044c06356bSdh142964 (((uint32_t)cdb[12]) << 8) | 26054c06356bSdh142964 ((uint32_t)cdb[13]); 26064c06356bSdh142964 *lba = 26074c06356bSdh142964 (((uint64_t)cdb[2]) << 56) | 26084c06356bSdh142964 (((uint64_t)cdb[3]) << 48) | 26094c06356bSdh142964 (((uint64_t)cdb[4]) << 40) | 26104c06356bSdh142964 (((uint64_t)cdb[5]) << 32) | 26114c06356bSdh142964 (((uint64_t)cdb[6]) << 24) | 26124c06356bSdh142964 (((uint64_t)cdb[7]) << 16) | 26134c06356bSdh142964 (((uint64_t)cdb[8]) << 8) | 26144c06356bSdh142964 ((uint64_t)cdb[9]); 26154c06356bSdh142964 /* Check for illegal bits */ 26164c06356bSdh142964 if (cdb[15]) { 26174c06356bSdh142964 asc = 0x24; /* invalid field in cdb */ 26184c06356bSdh142964 } 26194c06356bSdh142964 break; 26204c06356bSdh142964 case SCMD_READ_G4: 26214c06356bSdh142964 case SCMD_WRITE_G4: 26224c06356bSdh142964 *xfr = 26234c06356bSdh142964 (((uint32_t)cdb[6]) << 16) | 26244c06356bSdh142964 (((uint32_t)cdb[7]) << 8) | 26254c06356bSdh142964 ((uint32_t)cdb[8]); 26264c06356bSdh142964 *lba = 26274c06356bSdh142964 (((uint32_t)cdb[2]) << 24) | 26284c06356bSdh142964 (((uint32_t)cdb[3]) << 16) | 26294c06356bSdh142964 (((uint32_t)cdb[4]) << 8) | 26304c06356bSdh142964 ((uint32_t)cdb[5]); 26314c06356bSdh142964 /* Check for illegal bits */ 26324c06356bSdh142964 if (cdb[11]) { 26334c06356bSdh142964 asc = 0x24; /* invalid field in cdb */ 26344c06356bSdh142964 } 26354c06356bSdh142964 break; 26364c06356bSdh142964 case SCMD_READ_G1: 26374c06356bSdh142964 case SCMD_WRITE_G1: 26384c06356bSdh142964 *xfr = (((uint32_t)cdb[7]) << 8) | ((uint32_t)cdb[8]); 26394c06356bSdh142964 *lba = 26404c06356bSdh142964 (((uint32_t)cdb[2]) << 24) | 26414c06356bSdh142964 (((uint32_t)cdb[3]) << 16) | 26424c06356bSdh142964 (((uint32_t)cdb[4]) << 8) | 26434c06356bSdh142964 ((uint32_t)cdb[5]); 26444c06356bSdh142964 /* Check for illegal bits */ 26454c06356bSdh142964 if (cdb[9]) { 26464c06356bSdh142964 asc = 0x24; /* invalid field in cdb */ 26474c06356bSdh142964 } 26484c06356bSdh142964 break; 26494c06356bSdh142964 case SCMD_READ: 26504c06356bSdh142964 case SCMD_WRITE: 26514c06356bSdh142964 *xfr = cdb[4]; 26524c06356bSdh142964 if (*xfr == 0) { 26534c06356bSdh142964 *xfr = 256; 26544c06356bSdh142964 } 26554c06356bSdh142964 *lba = 26564c06356bSdh142964 (((uint32_t)cdb[1] & 0x1f) << 16) | 26574c06356bSdh142964 (((uint32_t)cdb[2]) << 8) | 26584c06356bSdh142964 ((uint32_t)cdb[3]); 26594c06356bSdh142964 /* Check for illegal bits */ 26604c06356bSdh142964 if (cdb[5]) { 26614c06356bSdh142964 asc = 0x24; /* invalid field in cdb */ 26624c06356bSdh142964 } 26634c06356bSdh142964 break; 26644c06356bSdh142964 } 26654c06356bSdh142964 26664c06356bSdh142964 if (asc == 0) { 26674c06356bSdh142964 if ((*lba + *xfr) > lbamax) { 26684c06356bSdh142964 asc = 0x21; /* logical block out of range */ 26694c06356bSdh142964 } 26704c06356bSdh142964 } 26714c06356bSdh142964 return (asc); 26724c06356bSdh142964 } 26734c06356bSdh142964 26744c06356bSdh142964 /* 26754c06356bSdh142964 * Called with pwrk lock held. 26764c06356bSdh142964 */ 26774c06356bSdh142964 static void 26784c06356bSdh142964 pmcs_ioerror(pmcs_hw_t *pwp, pmcs_dtype_t t, pmcwork_t *pwrk, uint32_t *w) 26794c06356bSdh142964 { 26804c06356bSdh142964 static uint8_t por[] = { 26814c06356bSdh142964 0xf0, 0x0, 0x6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x28 26824c06356bSdh142964 }; 26834c06356bSdh142964 static uint8_t parity[] = { 26844c06356bSdh142964 0xf0, 0x0, 0xb, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x47, 5 26854c06356bSdh142964 }; 26864c06356bSdh142964 const char *msg; 26874c06356bSdh142964 char buf[20]; 26884c06356bSdh142964 pmcs_cmd_t *sp = pwrk->arg; 26894c06356bSdh142964 pmcs_phy_t *phyp = pwrk->phy; 26904c06356bSdh142964 struct scsi_pkt *pkt = CMD2PKT(sp); 26914c06356bSdh142964 uint32_t status; 26924c06356bSdh142964 uint32_t resid; 26934c06356bSdh142964 26944c06356bSdh142964 ASSERT(w != NULL); 26954c06356bSdh142964 status = LE_32(w[2]); 26964c06356bSdh142964 resid = LE_32(w[3]); 26974c06356bSdh142964 26984c06356bSdh142964 msg = pmcs_status_str(status); 26994c06356bSdh142964 if (msg == NULL) { 27004c06356bSdh142964 (void) snprintf(buf, sizeof (buf), "Error 0x%x", status); 27014c06356bSdh142964 msg = buf; 27024c06356bSdh142964 } 27034c06356bSdh142964 27044c06356bSdh142964 if (status != PMCOUT_STATUS_OK) { 2705c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG2, phyp, NULL, 27064c06356bSdh142964 "%s: device %s tag 0x%x status %s @ %llu", __func__, 27074c06356bSdh142964 phyp->path, pwrk->htag, msg, 27084c06356bSdh142964 (unsigned long long)gethrtime()); 27094c06356bSdh142964 } 27104c06356bSdh142964 27114c06356bSdh142964 pkt->pkt_reason = CMD_CMPLT; /* default reason */ 27124c06356bSdh142964 27134c06356bSdh142964 switch (status) { 27144c06356bSdh142964 case PMCOUT_STATUS_OK: 27154c06356bSdh142964 if (t == SATA) { 27164c06356bSdh142964 int i; 27174c06356bSdh142964 fis_t fis; 27184c06356bSdh142964 for (i = 0; i < sizeof (fis) / sizeof (fis[0]); i++) { 27194c06356bSdh142964 fis[i] = LE_32(w[4+i]); 27204c06356bSdh142964 } 27214c06356bSdh142964 if ((fis[0] & 0xff) != FIS_REG_D2H) { 2722c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, 27234c06356bSdh142964 "unexpected fis code 0x%x", fis[0] & 0xff); 27244c06356bSdh142964 } else { 2725c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, 2726c3bc407cSdh142964 "FIS ERROR"); 27274c06356bSdh142964 pmcs_fis_dump(pwp, fis); 27284c06356bSdh142964 } 27294c06356bSdh142964 pkt->pkt_reason = CMD_TRAN_ERR; 27304c06356bSdh142964 break; 27314c06356bSdh142964 } 27324c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, phyp->path); 27334c06356bSdh142964 break; 27344c06356bSdh142964 27354c06356bSdh142964 case PMCOUT_STATUS_ABORTED: 27364c06356bSdh142964 /* 27374c06356bSdh142964 * Command successfully aborted. 27384c06356bSdh142964 */ 27394c06356bSdh142964 if (phyp->dead) { 27404c06356bSdh142964 pkt->pkt_reason = CMD_DEV_GONE; 27414c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS; 27424c06356bSdh142964 } else if (pwrk->ssp_event != 0) { 27434c06356bSdh142964 pkt->pkt_reason = CMD_TRAN_ERR; 27444c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS; 27454c06356bSdh142964 } else if (pwrk->state == PMCS_WORK_STATE_TIMED_OUT) { 27464c06356bSdh142964 pkt->pkt_reason = CMD_TIMEOUT; 27474c06356bSdh142964 pkt->pkt_statistics |= STAT_TIMEOUT; 27484c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | 27494c06356bSdh142964 STATE_SENT_CMD; 27504c06356bSdh142964 } else { 27514c06356bSdh142964 pkt->pkt_reason = CMD_ABORTED; 27524c06356bSdh142964 pkt->pkt_statistics |= STAT_ABORTED; 27534c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | 27544c06356bSdh142964 STATE_SENT_CMD; 27554c06356bSdh142964 } 27564c06356bSdh142964 27574c06356bSdh142964 /* 27584c06356bSdh142964 * PMCS_WORK_STATE_TIMED_OUT doesn't need to be preserved past 27594c06356bSdh142964 * this point, so go ahead and mark it as aborted. 27604c06356bSdh142964 */ 27614c06356bSdh142964 pwrk->state = PMCS_WORK_STATE_ABORTED; 27624c06356bSdh142964 break; 27634c06356bSdh142964 27644c06356bSdh142964 case PMCOUT_STATUS_UNDERFLOW: 27654c06356bSdh142964 /* 27664c06356bSdh142964 * This will only get called for SATA 27674c06356bSdh142964 */ 27684c06356bSdh142964 pkt->pkt_resid = resid; 27694c06356bSdh142964 if (pkt->pkt_dma_len < pkt->pkt_resid) { 27704c06356bSdh142964 (void) pmcs_set_resid(pkt, pkt->pkt_dma_len, resid); 27714c06356bSdh142964 } 27724c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, phyp->path); 27734c06356bSdh142964 break; 27744c06356bSdh142964 27754c06356bSdh142964 case PMCOUT_STATUS_NO_DEVICE: 27764c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_SATA_LINK_TIMEOUT: 27774c06356bSdh142964 pkt->pkt_reason = CMD_DEV_GONE; 27784c06356bSdh142964 break; 27794c06356bSdh142964 27804c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_WRONG_DESTINATION: 27814c06356bSdh142964 /* 27824c06356bSdh142964 * Need to do rediscovery. We probably have 27834c06356bSdh142964 * the wrong device (disk swap), so kill 27844c06356bSdh142964 * this one. 27854c06356bSdh142964 */ 27864c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_PROTOCOL_NOT_SUPPORTED: 27874c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_ZONE_VIOLATION: 27884c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: 27894c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_EROOR: 27904c06356bSdh142964 /* 27914c06356bSdh142964 * Need to do rediscovery. 27924c06356bSdh142964 */ 27934c06356bSdh142964 if (!phyp->dead) { 27944c06356bSdh142964 mutex_exit(&pwrk->lock); 27954c06356bSdh142964 pmcs_lock_phy(pwrk->phy); 27964c06356bSdh142964 pmcs_kill_changed(pwp, pwrk->phy, 0); 27974c06356bSdh142964 pmcs_unlock_phy(pwrk->phy); 27984c06356bSdh142964 mutex_enter(&pwrk->lock); 27994c06356bSdh142964 pkt->pkt_reason = CMD_INCOMPLETE; 28004c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS; 28014c06356bSdh142964 } else { 28024c06356bSdh142964 pkt->pkt_reason = CMD_DEV_GONE; 28034c06356bSdh142964 } 28044c06356bSdh142964 break; 28054c06356bSdh142964 28064c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_BREAK: 28074c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 28084c06356bSdh142964 case PMCOUT_STATUS_OPENCNX_ERROR_BAD_DESTINATION: 28094c06356bSdh142964 case PMCOUT_STATUS_IO_XFER_ERROR_NAK_RECEIVED: 28104c06356bSdh142964 /* cmd is pending on the target */ 28114c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_OFFSET_MISMATCH: 28124c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_REJECTED_NCQ_MODE: 28134c06356bSdh142964 /* transitory - commands sent while in NCQ failure mode */ 28144c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE: 28154c06356bSdh142964 /* NCQ failure */ 28164c06356bSdh142964 case PMCOUT_STATUS_IO_PORT_IN_RESET: 28174c06356bSdh142964 case PMCOUT_STATUS_XFER_ERR_BREAK: 28184c06356bSdh142964 case PMCOUT_STATUS_XFER_ERR_PHY_NOT_READY: 28194c06356bSdh142964 pkt->pkt_reason = CMD_INCOMPLETE; 28204c06356bSdh142964 pkt->pkt_state = STATE_GOT_BUS; 28214c06356bSdh142964 break; 28224c06356bSdh142964 28234c06356bSdh142964 case PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT: 28244c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_BUSY, NULL, 0, phyp->path); 28254c06356bSdh142964 break; 28264c06356bSdh142964 28274c06356bSdh142964 case PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: 28284c06356bSdh142964 /* synthesize a RESERVATION CONFLICT */ 2829499cfd15SDavid Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, phyp->target, 2830499cfd15SDavid Hollister "%s: Potential affiliation active on 0x%" PRIx64, __func__, 2831499cfd15SDavid Hollister pmcs_barray2wwn(phyp->sas_address)); 28324c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_RESERVATION_CONFLICT, NULL, 28334c06356bSdh142964 0, phyp->path); 28344c06356bSdh142964 break; 28354c06356bSdh142964 28364c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_ABORTED_DUE_TO_SRST: 28374c06356bSdh142964 /* synthesize a power-on/reset */ 28384c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_CHECK, por, sizeof (por), 28394c06356bSdh142964 phyp->path); 28404c06356bSdh142964 break; 28414c06356bSdh142964 28424c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_UNEXPECTED_PHASE: 28434c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_RDY_OVERRUN: 28444c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_RDY_NOT_EXPECTED: 28454c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT: 28464c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK: 28474c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK: 28484c06356bSdh142964 /* synthesize a PARITY ERROR */ 28494c06356bSdh142964 pmcs_latch_status(pwp, sp, STATUS_CHECK, parity, 28504c06356bSdh142964 sizeof (parity), phyp->path); 28514c06356bSdh142964 break; 28524c06356bSdh142964 28534c06356bSdh142964 case PMCOUT_STATUS_IO_XFER_ERROR_DMA: 28544c06356bSdh142964 case PMCOUT_STATUS_IO_NOT_VALID: 28554c06356bSdh142964 case PMCOUT_STATUS_PROG_ERROR: 28564c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_PEER_ABORTED: 28574c06356bSdh142964 case PMCOUT_STATUS_XFER_ERROR_SATA: /* non-NCQ failure */ 28584c06356bSdh142964 default: 28594c06356bSdh142964 pkt->pkt_reason = CMD_TRAN_ERR; 28604c06356bSdh142964 break; 28614c06356bSdh142964 } 28624c06356bSdh142964 } 28634c06356bSdh142964 28644c06356bSdh142964 /* 28654c06356bSdh142964 * Latch up SCSI status 28664c06356bSdh142964 */ 28674c06356bSdh142964 28684c06356bSdh142964 void 28694c06356bSdh142964 pmcs_latch_status(pmcs_hw_t *pwp, pmcs_cmd_t *sp, uint8_t status, 28704c06356bSdh142964 uint8_t *snsp, size_t snslen, char *path) 28714c06356bSdh142964 { 28724c06356bSdh142964 static const char c1[] = 28734c06356bSdh142964 "%s: Status Byte 0x%02x for CDB0=0x%02x (%02x %02x %02x) " 28744c06356bSdh142964 "HTAG 0x%x @ %llu"; 28754c06356bSdh142964 static const char c2[] = 28764c06356bSdh142964 "%s: Status Byte 0x%02x for CDB0=0x%02x HTAG 0x%x @ %llu"; 28774c06356bSdh142964 28784c06356bSdh142964 CMD2PKT(sp)->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | 28794c06356bSdh142964 STATE_SENT_CMD | STATE_GOT_STATUS; 28804c06356bSdh142964 CMD2PKT(sp)->pkt_scbp[0] = status; 28814c06356bSdh142964 28824c06356bSdh142964 if (status == STATUS_CHECK && snsp && 28834c06356bSdh142964 (size_t)SCSA_STSLEN(sp) >= sizeof (struct scsi_arq_status)) { 28844c06356bSdh142964 struct scsi_arq_status *aqp = 28854c06356bSdh142964 (void *) CMD2PKT(sp)->pkt_scbp; 28864c06356bSdh142964 size_t amt = sizeof (struct scsi_extended_sense); 28874c06356bSdh142964 uint8_t key = scsi_sense_key(snsp); 28884c06356bSdh142964 uint8_t asc = scsi_sense_asc(snsp); 28894c06356bSdh142964 uint8_t ascq = scsi_sense_ascq(snsp); 28904c06356bSdh142964 if (amt > snslen) { 28914c06356bSdh142964 amt = snslen; 28924c06356bSdh142964 } 2893c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_SCSI_STATUS, NULL, NULL, c1, path, 2894c3bc407cSdh142964 status, CMD2PKT(sp)->pkt_cdbp[0] & 0xff, key, asc, ascq, 28954c06356bSdh142964 sp->cmd_tag, (unsigned long long)gethrtime()); 28964c06356bSdh142964 CMD2PKT(sp)->pkt_state |= STATE_ARQ_DONE; 28974c06356bSdh142964 (*(uint8_t *)&aqp->sts_rqpkt_status) = STATUS_GOOD; 28984c06356bSdh142964 aqp->sts_rqpkt_statistics = 0; 28994c06356bSdh142964 aqp->sts_rqpkt_reason = CMD_CMPLT; 29004c06356bSdh142964 aqp->sts_rqpkt_state = STATE_GOT_BUS | 29014c06356bSdh142964 STATE_GOT_TARGET | STATE_SENT_CMD | 29024c06356bSdh142964 STATE_XFERRED_DATA | STATE_GOT_STATUS; 29034c06356bSdh142964 (void) memcpy(&aqp->sts_sensedata, snsp, amt); 29044c06356bSdh142964 if (aqp->sts_sensedata.es_class != CLASS_EXTENDED_SENSE) { 29054c06356bSdh142964 aqp->sts_rqpkt_reason = CMD_TRAN_ERR; 29064c06356bSdh142964 aqp->sts_rqpkt_state = 0; 29074c06356bSdh142964 aqp->sts_rqpkt_resid = 29084c06356bSdh142964 sizeof (struct scsi_extended_sense); 29094c06356bSdh142964 } else { 29104c06356bSdh142964 aqp->sts_rqpkt_resid = 29114c06356bSdh142964 sizeof (struct scsi_extended_sense) - amt; 29124c06356bSdh142964 } 29134c06356bSdh142964 } else if (status) { 2914c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_SCSI_STATUS, NULL, NULL, c2, 29154c06356bSdh142964 path, status, CMD2PKT(sp)->pkt_cdbp[0] & 0xff, 29164c06356bSdh142964 sp->cmd_tag, (unsigned long long)gethrtime()); 29174c06356bSdh142964 } 29184c06356bSdh142964 29194c06356bSdh142964 CMD2PKT(sp)->pkt_reason = CMD_CMPLT; 29204c06356bSdh142964 } 29214c06356bSdh142964 29224c06356bSdh142964 /* 29234c06356bSdh142964 * Calculate and set packet residual and return the amount 29244c06356bSdh142964 * left over after applying various filters. 29254c06356bSdh142964 */ 29264c06356bSdh142964 size_t 29274c06356bSdh142964 pmcs_set_resid(struct scsi_pkt *pkt, size_t amt, uint32_t cdbamt) 29284c06356bSdh142964 { 29294c06356bSdh142964 pkt->pkt_resid = cdbamt; 29304c06356bSdh142964 if (amt > pkt->pkt_resid) { 29314c06356bSdh142964 amt = pkt->pkt_resid; 29324c06356bSdh142964 } 29334c06356bSdh142964 if (amt > pkt->pkt_dma_len) { 29344c06356bSdh142964 amt = pkt->pkt_dma_len; 29354c06356bSdh142964 } 29364c06356bSdh142964 return (amt); 29374c06356bSdh142964 } 29384c06356bSdh142964 29394c06356bSdh142964 /* 29404c06356bSdh142964 * Return the existing target softstate if there is one. If there is, 29414c06356bSdh142964 * the PHY is locked as well and that lock must be freed by the caller 29424c06356bSdh142964 * after the target/PHY linkage is established. 29434c06356bSdh142964 */ 29444c06356bSdh142964 pmcs_xscsi_t * 29454c06356bSdh142964 pmcs_get_target(pmcs_iport_t *iport, char *tgt_port) 29464c06356bSdh142964 { 29474c06356bSdh142964 pmcs_hw_t *pwp = iport->pwp; 29484c06356bSdh142964 pmcs_phy_t *phyp; 29494c06356bSdh142964 pmcs_xscsi_t *tgt; 29504c06356bSdh142964 uint64_t wwn; 29514c06356bSdh142964 char unit_address[PMCS_MAX_UA_SIZE]; 29524c06356bSdh142964 int ua_form = 1; 29534c06356bSdh142964 29544c06356bSdh142964 /* 29554c06356bSdh142964 * Find the PHY for this target 29564c06356bSdh142964 */ 29574c06356bSdh142964 phyp = pmcs_find_phy_by_sas_address(pwp, iport, NULL, tgt_port); 29584c06356bSdh142964 if (phyp == NULL) { 2959c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG3, NULL, NULL, 2960c3bc407cSdh142964 "%s: No PHY for target @ %s", __func__, tgt_port); 29614c06356bSdh142964 return (NULL); 29624c06356bSdh142964 } 29634c06356bSdh142964 29644c06356bSdh142964 tgt = ddi_soft_state_bystr_get(iport->tgt_sstate, tgt_port); 29654c06356bSdh142964 29664c06356bSdh142964 if (tgt) { 29674c06356bSdh142964 /* 29684c06356bSdh142964 * There's already a target. Check its PHY pointer to see 29694c06356bSdh142964 * if we need to clear the old linkages 29704c06356bSdh142964 */ 29714c06356bSdh142964 if (tgt->phy && (tgt->phy != phyp)) { 2972c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 29734c06356bSdh142964 "%s: Target PHY updated from %p to %p", __func__, 29744c06356bSdh142964 (void *)tgt->phy, (void *)phyp); 29754c06356bSdh142964 if (!IS_ROOT_PHY(tgt->phy)) { 29764c06356bSdh142964 pmcs_dec_phy_ref_count(tgt->phy); 29774c06356bSdh142964 pmcs_inc_phy_ref_count(phyp); 29784c06356bSdh142964 } 29794c06356bSdh142964 tgt->phy->target = NULL; 29804c06356bSdh142964 } 29814c06356bSdh142964 29824c06356bSdh142964 tgt->phy = phyp; 29834c06356bSdh142964 phyp->target = tgt; 29844c06356bSdh142964 return (tgt); 29854c06356bSdh142964 } 29864c06356bSdh142964 29874c06356bSdh142964 /* 29884c06356bSdh142964 * Make sure the PHY we found is on the correct iport 29894c06356bSdh142964 */ 29904c06356bSdh142964 if (phyp->iport != iport) { 2991c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, 29924c06356bSdh142964 "%s: No target at %s on this iport", __func__, tgt_port); 29934c06356bSdh142964 pmcs_unlock_phy(phyp); 29944c06356bSdh142964 return (NULL); 29954c06356bSdh142964 } 29964c06356bSdh142964 29974c06356bSdh142964 /* 29984c06356bSdh142964 * Allocate the new softstate 29994c06356bSdh142964 */ 30004c06356bSdh142964 wwn = pmcs_barray2wwn(phyp->sas_address); 30014c06356bSdh142964 (void) scsi_wwn_to_wwnstr(wwn, ua_form, unit_address); 30024c06356bSdh142964 30034c06356bSdh142964 if (ddi_soft_state_bystr_zalloc(iport->tgt_sstate, unit_address) != 30044c06356bSdh142964 DDI_SUCCESS) { 3005c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 30064c06356bSdh142964 "%s: Couldn't alloc softstate for device at %s", 30074c06356bSdh142964 __func__, unit_address); 30084c06356bSdh142964 pmcs_unlock_phy(phyp); 30094c06356bSdh142964 return (NULL); 30104c06356bSdh142964 } 30114c06356bSdh142964 30124c06356bSdh142964 tgt = ddi_soft_state_bystr_get(iport->tgt_sstate, unit_address); 30134c06356bSdh142964 STAILQ_INIT(&tgt->wq); 30144c06356bSdh142964 STAILQ_INIT(&tgt->aq); 30154c06356bSdh142964 STAILQ_INIT(&tgt->sq); 30164c06356bSdh142964 mutex_init(&tgt->statlock, NULL, MUTEX_DRIVER, 30174c06356bSdh142964 DDI_INTR_PRI(pwp->intr_pri)); 30184c06356bSdh142964 mutex_init(&tgt->wqlock, NULL, MUTEX_DRIVER, 30194c06356bSdh142964 DDI_INTR_PRI(pwp->intr_pri)); 30204c06356bSdh142964 mutex_init(&tgt->aqlock, NULL, MUTEX_DRIVER, 30214c06356bSdh142964 DDI_INTR_PRI(pwp->intr_pri)); 30224c06356bSdh142964 cv_init(&tgt->reset_cv, NULL, CV_DRIVER, NULL); 30234c06356bSdh142964 cv_init(&tgt->abort_cv, NULL, CV_DRIVER, NULL); 30244c06356bSdh142964 tgt->qdepth = 1; 30254c06356bSdh142964 tgt->target_num = PMCS_INVALID_TARGET_NUM; 30264c06356bSdh142964 bcopy(unit_address, tgt->unit_address, PMCS_MAX_UA_SIZE); 30274c06356bSdh142964 tgt->pwp = pwp; 30284c06356bSdh142964 tgt->ua = strdup(iport->ua); 30294c06356bSdh142964 tgt->phy = phyp; 30304c06356bSdh142964 ASSERT((phyp->target == NULL) || (phyp->target == tgt)); 30314c06356bSdh142964 if (phyp->target == NULL) { 30324c06356bSdh142964 phyp->target = tgt; 30334c06356bSdh142964 } 30344c06356bSdh142964 30354c06356bSdh142964 /* 30364c06356bSdh142964 * Don't allocate LUN softstate for SMP targets 30374c06356bSdh142964 */ 30384c06356bSdh142964 if (phyp->dtype == EXPANDER) { 30394c06356bSdh142964 return (tgt); 30404c06356bSdh142964 } 30414c06356bSdh142964 30424c06356bSdh142964 if (ddi_soft_state_bystr_init(&tgt->lun_sstate, 30434c06356bSdh142964 sizeof (pmcs_lun_t), PMCS_LUN_SSTATE_SZ) != 0) { 3044c3bc407cSdh142964 pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, 30454c06356bSdh142964 "%s: LUN soft_state_bystr_init failed", __func__); 30464c06356bSdh142964 ddi_soft_state_bystr_free(iport->tgt_sstate, tgt_port); 30474c06356bSdh142964 pmcs_unlock_phy(phyp); 30484c06356bSdh142964 return (NULL); 30494c06356bSdh142964 } 30504c06356bSdh142964 30514c06356bSdh142964 return (tgt); 30524c06356bSdh142964 } 3053