diff options
author | Srikanth Suravajhala <srikanth.suravajhala@oracle.com> | 2010-04-26 18:00:24 -0400 |
---|---|---|
committer | Srikanth Suravajhala <srikanth.suravajhala@oracle.com> | 2010-04-26 18:00:24 -0400 |
commit | 978d7443a924cda8208d6a10e72be89383bc7bec (patch) | |
tree | ff805c3a4d727c2b87036de000e0a116adce81c9 | |
parent | 5f1fdc187ec74acfbc49a47e07b89d7f64519f7b (diff) | |
download | illumos-gate-978d7443a924cda8208d6a10e72be89383bc7bec.tar.gz |
6940745 work structures without a pmcs_cmd_t need to be cleaned up after hot reset
6945802 potential null dereference in pmcs_create_one_phy_stats()
8 files changed, 77 insertions, 106 deletions
diff --git a/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c b/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c index 7379c0e470..24785a7445 100644 --- a/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c +++ b/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c @@ -1454,7 +1454,7 @@ inbound_iomb_opcode(uint32_t opcode) case PMCIN_SAS_DIAG_EXECUTE: return ("SAS_DIAG_EXECUTE"); break; - case PMCIN_SAW_HW_EVENT_ACK: + case PMCIN_SAS_HW_EVENT_ACK: return ("SAS_HW_EVENT_ACK"); break; case PMCIN_GET_TIME_STAMP: diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c index 12f3aa4a9c..dadba60f7a 100644 --- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c @@ -918,7 +918,7 @@ pmcs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) } pwp->work = kmem_zalloc(pwp->max_cmd * sizeof (pmcwork_t), KM_SLEEP); - for (i = 0; i < pwp->max_cmd - 1; i++) { + for (i = 0; i < pwp->max_cmd; i++) { pmcwork_t *pwrk = &pwp->work[i]; mutex_init(&pwrk->lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pwp->intr_pri)); @@ -1600,7 +1600,7 @@ pmcs_unattach(pmcs_hw_t *pwp) */ if (pwp->work && pwp->max_cmd) { - for (i = 0; i < pwp->max_cmd - 1; i++) { + for (i = 0; i < pwp->max_cmd; i++) { pmcwork_t *pwrk = &pwp->work[i]; mutex_destroy(&pwrk->lock); cv_destroy(&pwrk->sleep_cv); @@ -3054,6 +3054,7 @@ pmcs_create_one_phy_stats(pmcs_iport_t *iport, pmcs_phy_t *phyp) pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, "%s: Failed to create %s kstats for PHY(0x%p) at %s", __func__, ks_name, (void *)phyp, phyp->path); + return; } ps = (sas_phy_stats_t *)phyp->phy_stats->ks_data; diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c index 90320505f8..ecb51a9fbf 100644 --- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c @@ -166,7 +166,7 @@ pmcs_process_io_completion(pmcs_hw_t *pwp, pmcs_iocomp_cb_t *ioccb, size_t amt) uint32_t tag_type; uint32_t htag = LE_32(((uint32_t *)((void *)ioccb->iomb))[1]); - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_FALSE); if (pwrk == NULL) { pmcs_work_not_found(pwp, htag, (void *)&ioccb->iomb); kmem_cache_free(pwp->iocomp_cb_cache, ioccb); @@ -237,7 +237,7 @@ pmcs_process_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) pmcwork_t *pwrk; uint32_t htag = LE_32(((uint32_t *)iomb)[1]); - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_FALSE); if (pwrk == NULL) { pmcs_work_not_found(pwp, htag, iomb); return; @@ -1061,7 +1061,7 @@ pmcs_process_echo_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) echo_test_t fred; pmcwork_t *pwrk; uint32_t *msg = iomb, htag = LE_32(msg[1]); - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_FALSE); if (pwrk) { (void) memcpy(&fred, &((uint32_t *)iomb)[2], sizeof (fred)); fred.ptr[0]++; @@ -1087,7 +1087,7 @@ pmcs_process_ssp_event(pmcs_hw_t *pwp, void *iomb, size_t amt) status = LE_32(w[2]); - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_FALSE); if (pwrk == NULL) { path = "????"; } else { @@ -1150,25 +1150,12 @@ pmcs_process_sata_event(pmcs_hw_t *pwp, void *iomb, size_t amt) */ path = NULL; if (htag) { - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_TRUE); if (pwrk) { - pmcs_lock_phy(pwrk->phy); pptr = pwrk->phy; path = pptr->path; } } - if (path == NULL) { - mutex_enter(&pwp->lock); - pptr = pmcs_find_phy_by_devid(pwp, LE_32(w[4])); - /* This PHY is now locked */ - mutex_exit(&pwp->lock); - if (pptr) { - path = pptr->path; - } else { - path = "????"; - } - } - if (status != PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED) { char buf[20]; const char *emsg = pmcs_status_str(status); @@ -1209,7 +1196,7 @@ pmcs_process_sata_event(pmcs_hw_t *pwp, void *iomb, size_t amt) } if (pptr) { - pmcs_unlock_phy(pptr); + mutex_exit(&pptr->phy_lock); } } @@ -1223,7 +1210,7 @@ pmcs_process_abort_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) uint32_t scp = LE_32(((uint32_t *)iomb)[3]) & 0x1; char *path; - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_TRUE); if (pwrk == NULL) { pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: cannot find work structure for ABORT", __func__); @@ -1236,7 +1223,6 @@ pmcs_process_abort_completion(pmcs_hw_t *pwp, void *iomb, size_t amt) * Don't use pmcs_lock_phy here since it could potentially lock * other PHYs beneath, which is unnecessary in this context. */ - mutex_enter(&pptr->phy_lock); pptr->abort_pending = 0; pptr->abort_sent = 0; @@ -1327,7 +1313,7 @@ pmcs_process_general_event(pmcs_hw_t *pwp, uint32_t *iomb) iomb[PMCS_MSG_SIZE - 1] = 0; htag = LE_32(iomb[1]); pmcs_print_entry(pwp, PMCS_PRT_DEBUG, local, iomb); - pwrk = pmcs_tag2wp(pwp, htag); + pwrk = pmcs_tag2wp(pwp, htag, B_FALSE); if (pwrk) { pmcs_complete_work(pwp, pwrk, iomb, PMCS_QENTRY_SIZE); } diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c index 8f536bd99f..d6b6c0fa04 100644 --- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c @@ -668,7 +668,7 @@ pmcs_scsa_abort(struct scsi_address *ap, struct scsi_pkt *pkt) /* * See if we have a real work structure associated with this cmd. */ - pwrk = pmcs_tag2wp(pwp, sp->cmd_tag); + pwrk = pmcs_tag2wp(pwp, sp->cmd_tag, B_FALSE); if (pwrk && pwrk->arg == sp) { tag = pwrk->htag; pptr = pwrk->phy; diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c index 6057082bde..fb7898ecaf 100644 --- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c @@ -2324,7 +2324,8 @@ pmcs_phymap_activate(void *arg, char *ua, void **privp) pmcs_iport_t *iport = NULL; mutex_enter(&pwp->lock); - if ((pwp->state == STATE_UNPROBING) || (pwp->state == STATE_DEAD)) { + if ((pwp->state == STATE_UNPROBING) || (pwp->state == STATE_DEAD) || + (pwp->state == STATE_IN_RESET)) { mutex_exit(&pwp->lock); return; } @@ -4163,6 +4164,7 @@ again: (void) memset(pwp->scratch, 0x77, PMCS_SCRATCH_SIZE); pwrk->arg = pwp->scratch; pwrk->dtype = pptr->dtype; + pwrk->htag |= PMCS_TAG_NONIO_CMD; mutex_enter(&pwp->iqp_lock[PMCS_IQ_OTHER]); ptr = GET_IQ_ENTRY(pwp, PMCS_IQ_OTHER); if (ptr == NULL) { @@ -4399,6 +4401,7 @@ pmcs_expander_content_discover(pmcs_hw_t *pwp, pmcs_phy_t *expander, (void) memset(pwp->scratch, 0x77, PMCS_SCRATCH_SIZE); pwrk->arg = pwp->scratch; pwrk->dtype = expander->dtype; + pwrk->htag |= PMCS_TAG_NONIO_CMD; msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_SMP_REQUEST)); msg[1] = LE_32(pwrk->htag); msg[2] = LE_32(expander->device_id); @@ -4806,9 +4809,10 @@ pmcs_pwork(pmcs_hw_t *pwp, pmcwork_t *p) * Find a work structure based upon a tag and make sure that the tag * serial number matches the work structure we've found. * If a structure is found, its lock is held upon return. + * If lock_phy is B_TRUE, then lock the phy also when returning the work struct */ pmcwork_t * -pmcs_tag2wp(pmcs_hw_t *pwp, uint32_t htag) +pmcs_tag2wp(pmcs_hw_t *pwp, uint32_t htag, boolean_t lock_phy) { pmcwork_t *p; uint32_t idx = PMCS_TAG_INDEX(htag); @@ -4817,6 +4821,11 @@ pmcs_tag2wp(pmcs_hw_t *pwp, uint32_t htag) mutex_enter(&p->lock); if (p->htag == htag) { + if (lock_phy) { + mutex_exit(&p->lock); + mutex_enter(&p->phy->phy_lock); + mutex_enter(&p->lock); + } return (p); } mutex_exit(&p->lock); @@ -4872,6 +4881,7 @@ pmcs_abort(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint32_t tag, int all_cmds, } pwrk->dtype = pptr->dtype; + pwrk->htag |= PMCS_TAG_NONIO_CMD; if (wait) { pwrk->arg = msg; } @@ -5039,6 +5049,7 @@ pmcs_ssp_tmf(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint8_t tmf, uint32_t tag, * NB: so as to not get entangled in normal I/O * NB: processing. */ + pwrk->htag |= PMCS_TAG_NONIO_CMD; msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_SSP_INI_TM_START)); msg[1] = LE_32(pwrk->htag); @@ -5254,6 +5265,7 @@ pmcs_sata_abort_ncq(pmcs_hw_t *pwp, pmcs_phy_t *pptr) if (pwrk == NULL) { return (ENOMEM); } + pwrk->htag |= PMCS_TAG_NONIO_CMD; msg[0] = LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE, PMCIN_SATA_HOST_IO_START)); msg[1] = LE_32(pwrk->htag); @@ -5677,69 +5689,6 @@ pmcs_phy_name(pmcs_hw_t *pwp, pmcs_phy_t *pptr, char *obuf, size_t olen) } /* - * Implementation for pmcs_find_phy_by_devid. - * If the PHY is found, it is returned locked. - */ -static pmcs_phy_t * -pmcs_find_phy_by_devid_impl(pmcs_phy_t *phyp, uint32_t device_id) -{ - pmcs_phy_t *match, *cphyp, *nphyp; - - ASSERT(!mutex_owned(&phyp->phy_lock)); - - while (phyp) { - pmcs_lock_phy(phyp); - - if ((phyp->valid_device_id) && (phyp->device_id == device_id)) { - return (phyp); - } - if (phyp->children) { - cphyp = phyp->children; - pmcs_unlock_phy(phyp); - match = pmcs_find_phy_by_devid_impl(cphyp, device_id); - if (match) { - ASSERT(mutex_owned(&match->phy_lock)); - return (match); - } - pmcs_lock_phy(phyp); - } - - if (IS_ROOT_PHY(phyp)) { - pmcs_unlock_phy(phyp); - phyp = NULL; - } else { - nphyp = phyp->sibling; - pmcs_unlock_phy(phyp); - phyp = nphyp; - } - } - - return (NULL); -} - -/* - * If the PHY is found, it is returned locked - */ -pmcs_phy_t * -pmcs_find_phy_by_devid(pmcs_hw_t *pwp, uint32_t device_id) -{ - pmcs_phy_t *phyp, *match = NULL; - - phyp = pwp->root_phys; - - while (phyp) { - match = pmcs_find_phy_by_devid_impl(phyp, device_id); - if (match) { - ASSERT(mutex_owned(&match->phy_lock)); - return (match); - } - phyp = phyp->sibling; - } - - return (NULL); -} - -/* * This function is called as a sanity check to ensure that a newly registered * PHY doesn't have a device_id that exists with another registered PHY. */ @@ -6019,6 +5968,7 @@ pmcs_spinup_release(pmcs_hw_t *pwp, pmcs_phy_t *phyp) phyp->spinup_hold = 0; bzero(msg, PMCS_QENTRY_SIZE); + pwrk->htag |= PMCS_TAG_NONIO_CMD; msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_LOCAL_PHY_CONTROL)); msg[1] = LE_32(pwrk->htag); @@ -6247,7 +6197,7 @@ pmcs_ack_events(pmcs_hw_t *pwp) } msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, - PMCIN_SAW_HW_EVENT_ACK)); + PMCIN_SAS_HW_EVENT_ACK)); msg[1] = LE_32(pwrk->htag); msg[2] = LE_32(pptr->hw_event_ack); @@ -7100,7 +7050,7 @@ pmcs_flush_target_queues(pmcs_hw_t *pwp, pmcs_xscsi_t *tgt, uint8_t queues) sp = STAILQ_FIRST(&tgt->aq); while (sp) { sp_next = STAILQ_NEXT(sp, cmd_next); - pwrk = pmcs_tag2wp(pwp, sp->cmd_tag); + pwrk = pmcs_tag2wp(pwp, sp->cmd_tag, B_FALSE); /* * If we don't find a work structure, it's because @@ -7154,6 +7104,39 @@ pmcs_flush_target_queues(pmcs_hw_t *pwp, pmcs_xscsi_t *tgt, uint8_t queues) mutex_exit(&pwp->cq_lock); } } + + if (queues == PMCS_TGT_ALL_QUEUES) { + mutex_exit(&tgt->statlock); + (void) pmcs_flush_nonio_cmds(pwp); + mutex_enter(&tgt->statlock); + } +} + +/* + * Clean up work structures with no associated pmcs_cmd_t struct + */ +void +pmcs_flush_nonio_cmds(pmcs_hw_t *pwp) +{ + int i; + pmcwork_t *p; + + for (i = 0; i < pwp->max_cmd; i++) { + p = &pwp->work[i]; + mutex_enter(&p->lock); + if (p->htag & PMCS_TAG_NONIO_CMD) { + if (!PMCS_COMMAND_ACTIVE(p) || PMCS_COMMAND_DONE(p)) { + mutex_exit(&p->lock); + continue; + } + pmcs_prt(pwp, PMCS_PRT_DEBUG, p->phy, p->xp, + "%s: Completing non-io cmd with HTAG 0x%x", + __func__, p->htag); + pmcs_complete_work_impl(pwp, p, NULL, 0); + } else { + mutex_exit(&p->lock); + } + } } void @@ -7545,13 +7528,15 @@ pmcs_free_all_phys(pmcs_hw_t *pwp, pmcs_phy_t *phyp) tphyp = nphyp; } + mutex_enter(&pwp->dead_phylist_lock); tphyp = pwp->dead_phys; while (tphyp) { - nphyp = tphyp->sibling; + nphyp = tphyp->dead_next; kmem_cache_free(pwp->phy_cache, tphyp); tphyp = nphyp; } pwp->dead_phys = NULL; + mutex_exit(&pwp->dead_phylist_lock); } /* @@ -7921,6 +7906,7 @@ pmcs_add_phy_to_iport(pmcs_iport_t *iport, pmcs_phy_t *phyp) ASSERT(mutex_owned(&iport->lock)); ASSERT(phyp); ASSERT(!list_link_active(&phyp->list_node)); + iport->nphy++; list_insert_tail(&iport->phys, phyp); pmcs_smhba_add_iport_prop(iport, DATA_TYPE_INT32, PMCS_NUM_PHYS, diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h index 18132eaa85..7b25fccd2a 100644 --- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h @@ -316,7 +316,8 @@ typedef struct { * bits what * ------------------------ * 31 done bit - * 30..28 tag type + * 30 non-io cmd bit + * 29..28 tag type * 27..12 rolling serial number * 11..0 index into work area to get pmcwork structure * @@ -346,7 +347,8 @@ typedef struct { #define PMCS_TAG_TYPE_SHIFT 28 #define PMCS_TAG_SERNO_SHIFT 12 #define PMCS_TAG_INDEX_SHIFT 0 -#define PMCS_TAG_TYPE_MASK 0x70000000 +#define PMCS_TAG_TYPE_MASK 0x30000000 +#define PMCS_TAG_NONIO_CMD 0x40000000 #define PMCS_TAG_DONE 0x80000000 #define PMCS_TAG_SERNO_MASK 0x0ffff000 #define PMCS_TAG_INDEX_MASK 0x00000fff diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h index 0ab8c09c49..c8860b6376 100644 --- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_iomb.h @@ -18,9 +18,9 @@ * * CDDL HEADER END * - * - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + */ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * PMC 8x6G IOMB Definitions @@ -116,7 +116,7 @@ extern "C" { #define PMCIN_GPIO 0x22 #define PMCIN_SAS_DIAG_MODE_START_END 0x23 #define PMCIN_SAS_DIAG_EXECUTE 0x24 -#define PMCIN_SAW_HW_EVENT_ACK 0x25 +#define PMCIN_SAS_HW_EVENT_ACK 0x25 #define PMCIN_GET_TIME_STAMP 0x26 #define PMCIN_PORT_CONTROL 0x27 #define PMCIN_GET_NVMD_DATA 0x28 diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h index 348439d222..6aeeaaf355 100644 --- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h @@ -76,7 +76,7 @@ pmcwork_t *pmcs_gwork(pmcs_hw_t *, uint32_t, pmcs_phy_t *); void pmcs_pwork(pmcs_hw_t *, struct pmcwork *); /* given a tag, find a work structure */ -pmcwork_t *pmcs_tag2wp(pmcs_hw_t *, uint32_t); +pmcwork_t *pmcs_tag2wp(pmcs_hw_t *, uint32_t, boolean_t); /* * Abort function @@ -148,11 +148,6 @@ void pmcs_report_fwversion(pmcs_hw_t *); void pmcs_phy_name(pmcs_hw_t *, pmcs_phy_t *, char *, size_t); /* - * Find a PHY by device_id - */ -pmcs_phy_t *pmcs_find_phy_by_devid(pmcs_hw_t *, uint32_t); - -/* * Find a PHY by wwn */ pmcs_phy_t *pmcs_find_phy_by_wwn(pmcs_hw_t *, uint64_t); @@ -302,6 +297,7 @@ boolean_t pmcs_set_nvmd(pmcs_hw_t *pwp, pmcs_nvmd_type_t nvmd_type, void pmcs_complete_work_impl(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *iomb, size_t amt); void pmcs_flush_target_queues(pmcs_hw_t *, pmcs_xscsi_t *, uint8_t); +void pmcs_flush_nonio_cmds(pmcs_hw_t *); boolean_t pmcs_iport_has_targets(pmcs_hw_t *, pmcs_iport_t *); void pmcs_free_dma_chunklist(pmcs_hw_t *); void pmcs_dev_state_recovery(pmcs_hw_t *, pmcs_phy_t *); |