Print this page
LOCAL: mpt_sas: expose drive ID via ioctl

*** 20,29 **** --- 20,30 ---- */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ /* * Copyright (c) 2000 to 2010, LSI Corporation. * All rights reserved.
*** 67,76 **** --- 68,78 ---- #include <sys/scsi/scsi.h> #include <sys/pci.h> #include <sys/file.h> #include <sys/cpuvar.h> #include <sys/policy.h> + #include <sys/model.h> #include <sys/sysevent.h> #include <sys/sysevent/eventdefs.h> #include <sys/sysevent/dr.h> #include <sys/sata/sata_defs.h> #include <sys/scsi/generic/sas.h>
*** 367,378 **** uint32_t *status, uint8_t cmd); static dev_info_t *mptsas_get_dip_from_dev(dev_t dev, mptsas_phymask_t *phymask); static mptsas_target_t *mptsas_addr_to_ptgt(mptsas_t *mpt, char *addr, mptsas_phymask_t phymask); ! static int mptsas_set_led_status(mptsas_t *mpt, mptsas_target_t *ptgt, ! uint32_t slotstatus); /* * Enumeration / DR functions */ --- 369,379 ---- uint32_t *status, uint8_t cmd); static dev_info_t *mptsas_get_dip_from_dev(dev_t dev, mptsas_phymask_t *phymask); static mptsas_target_t *mptsas_addr_to_ptgt(mptsas_t *mpt, char *addr, mptsas_phymask_t phymask); ! static int mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt); /* * Enumeration / DR functions */
*** 1087,1096 **** --- 1088,1101 ---- mptsas_log(NULL, CE_WARN, "mptsas%d: cannot get soft state", instance); goto fail; } + /* Mark us as a primary ioctl node for an instance. */ + (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "primary-ioctl-node", + instance); + /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */ scsi_size_clean(dip); mpt->m_dip = dip; mpt->m_instance = instance;
*** 6449,6459 **** break; } } mutex_enter(&mpt->m_mutex); ! if (mptsas_set_led_status(mpt, ptgt, 0) != DDI_SUCCESS) { NDBG14(("mptsas: clear LED for tgt %x failed", ptgt->m_slot_num)); } if (rval == DDI_SUCCESS) { mptsas_tgt_free(&mpt->m_active->m_tgttbl, --- 6454,6465 ---- break; } } mutex_enter(&mpt->m_mutex); ! ptgt->m_led_status = 0; ! if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) { NDBG14(("mptsas: clear LED for tgt %x failed", ptgt->m_slot_num)); } if (rval == DDI_SUCCESS) { mptsas_tgt_free(&mpt->m_active->m_tgttbl,
*** 11949,11958 **** --- 11955,12114 ---- mutex_exit(&mpt->m_mutex); return (status); } static int + led_control(mptsas_t *mpt, intptr_t data, int mode) + { + int ret = 0; + mptsas_led_control_t lc; + mptsas_target_t *ptgt; + + if (ddi_copyin((void *)data, &lc, sizeof (lc), mode) != 0) { + return (EFAULT); + } + + if ((lc.Command != MPTSAS_LEDCTL_FLAG_SET && + lc.Command != MPTSAS_LEDCTL_FLAG_GET) || + lc.Led < MPTSAS_LEDCTL_LED_IDENT || + lc.Led > MPTSAS_LEDCTL_LED_OK2RM) { + return (EINVAL); + } + + /* Locate the target we're interrogating... */ + mutex_enter(&mpt->m_mutex); + ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl, + MPTSAS_HASH_FIRST); + while (ptgt != NULL) { + if (ptgt->m_enclosure == lc.Enclosure && + ptgt->m_slot_num == lc.Slot) { + break; + } + ptgt = (mptsas_target_t *)mptsas_hash_traverse( + &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT); + } + if (ptgt == NULL) { + /* We could not find a target for that enclosure/slot. */ + mutex_exit(&mpt->m_mutex); + return (ENOENT); + } + + if (lc.Command == MPTSAS_LEDCTL_FLAG_SET) { + /* Update our internal LED state. */ + ptgt->m_led_status &= ~(1 << (lc.Led - 1)); + ptgt->m_led_status |= (!!lc.LedStatus) << (lc.Led - 1); + + /* Flush it to the controller. */ + ret = mptsas_flush_led_status(mpt, ptgt); + mutex_exit(&mpt->m_mutex); + return (ret); + } + + /* Return our internal LED state. */ + lc.LedStatus = !!(ptgt->m_led_status & (1 << (lc.Led - 1))); + mutex_exit(&mpt->m_mutex); + + if (ddi_copyout(&lc, (void *)data, sizeof (lc), mode) != 0) { + return (EFAULT); + } + + return (0); + } + + static int + get_disk_info(mptsas_t *mpt, intptr_t data, int mode) + { + int i; + int count = 0; + int ret = 0; + mptsas_target_t *ptgt; + mptsas_disk_info_t *di; + STRUCT_DECL(mptsas_get_disk_info, gdi); + + STRUCT_INIT(gdi, get_udatamodel()); + + if (ddi_copyin((void *)data, STRUCT_BUF(gdi), STRUCT_SIZE(gdi), + mode) != 0) { + return (EFAULT); + } + + restart: + /* Find out how many targets there are. */ + mutex_enter(&mpt->m_mutex); + ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl, + MPTSAS_HASH_FIRST); + while (ptgt != NULL) { + count++; + ptgt = (mptsas_target_t *)mptsas_hash_traverse( + &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT); + } + mutex_exit(&mpt->m_mutex); + + /* + * If we haven't been asked to copy out information on each target, + * then just return the count. + */ + STRUCT_FSET(gdi, DiskCount, count); + if (STRUCT_FGETP(gdi, PtrDiskInfoArray) == NULL) + goto copy_out; + + /* + * If we haven't been given a large enough buffer to copy out into, + * let the caller know. + */ + if (STRUCT_FGET(gdi, DiskInfoArraySize) < + count * sizeof (mptsas_disk_info_t)) { + ret = ENOSPC; + goto copy_out; + } + + di = kmem_zalloc(count * sizeof (mptsas_disk_info_t), KM_SLEEP); + + mutex_enter(&mpt->m_mutex); + i = 0; + ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl, + MPTSAS_HASH_FIRST); + while (ptgt != NULL) { + if (i >= count) { + /* + * The number of targets changed while we weren't + * looking. Go again. + */ + mutex_exit(&mpt->m_mutex); + kmem_free(di, count * sizeof (mptsas_disk_info_t)); + goto restart; + } + di[i].Instance = mpt->m_instance; + di[i].Enclosure = ptgt->m_enclosure; + di[i].Slot = ptgt->m_slot_num; + di[i].SasAddress = ptgt->m_sas_wwn; + + ptgt = (mptsas_target_t *)mptsas_hash_traverse( + &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT); + i++; + } + mutex_exit(&mpt->m_mutex); + STRUCT_FSET(gdi, DiskCount, i); + + /* Copy out the disk information to the caller. */ + if (ddi_copyout((void *)di, STRUCT_FGETP(gdi, PtrDiskInfoArray), + i * sizeof (mptsas_disk_info_t), mode) != 0) { + ret = EFAULT; + } + + kmem_free(di, count * sizeof (mptsas_disk_info_t)); + + copy_out: + if (ddi_copyout(STRUCT_BUF(gdi), (void *)data, STRUCT_SIZE(gdi), + mode) != 0) { + ret = EFAULT; + } + + return (ret); + } + + static int mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval) { int status = 0; mptsas_t *mpt;
*** 12035,12078 **** if (cmd == DEVCTL_DEVICE_ONLINE) { ptgt->m_tgt_unconfigured = 0; } else if (cmd == DEVCTL_DEVICE_OFFLINE) { ptgt->m_tgt_unconfigured = 1; } - slotstatus = 0; - #ifdef MPTSAS_GET_LED - /* - * The get led status can't get a valid/reasonable - * state, so ignore the get led status, and write the - * required value directly - */ - if (mptsas_get_led_status(mpt, ptgt, &slotstatus) != - DDI_SUCCESS) { - NDBG14(("mptsas_ioctl: get LED for tgt %s " - "failed %x", addr, slotstatus)); - slotstatus = 0; - } - NDBG14(("mptsas_ioctl: LED status %x for %s", - slotstatus, addr)); - #endif if (cmd == DEVCTL_DEVICE_OFFLINE) { ! slotstatus |= ! MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE; } else { ! slotstatus &= ! ~MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE; } ! if (mptsas_set_led_status(mpt, ptgt, slotstatus) != ! DDI_SUCCESS) { NDBG14(("mptsas_ioctl: set LED for tgt %s " "failed %x", addr, slotstatus)); } mutex_exit(&mpt->m_mutex); ndi_dc_freehdl(dcp); } goto out; } switch (cmd) { case MPTIOCTL_UPDATE_FLASH: if (ddi_copyin((void *)data, &flashdata, sizeof (struct mptsas_update_flash), mode)) { status = EFAULT; break; --- 12191,12223 ---- if (cmd == DEVCTL_DEVICE_ONLINE) { ptgt->m_tgt_unconfigured = 0; } else if (cmd == DEVCTL_DEVICE_OFFLINE) { ptgt->m_tgt_unconfigured = 1; } if (cmd == DEVCTL_DEVICE_OFFLINE) { ! ptgt->m_led_status |= ! (1 << (MPTSAS_LEDCTL_LED_OK2RM - 1)); } else { ! ptgt->m_led_status &= ! ~(1 << (MPTSAS_LEDCTL_LED_OK2RM - 1)); } ! if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) { NDBG14(("mptsas_ioctl: set LED for tgt %s " "failed %x", addr, slotstatus)); } mutex_exit(&mpt->m_mutex); ndi_dc_freehdl(dcp); } goto out; } switch (cmd) { + case MPTIOCTL_GET_DISK_INFO: + status = get_disk_info(mpt, data, mode); + break; + case MPTIOCTL_LED_CONTROL: + status = led_control(mpt, data, mode); + break; case MPTIOCTL_UPDATE_FLASH: if (ddi_copyin((void *)data, &flashdata, sizeof (struct mptsas_update_flash), mode)) { status = EFAULT; break;
*** 14529,14540 **** if ((!MDI_PI_IS_ONLINE(*pip)) && (!MDI_PI_IS_STANDBY(*pip)) && (ptgt->m_tgt_unconfigured == 0)) { rval = mdi_pi_online(*pip, 0); mutex_enter(&mpt->m_mutex); ! (void) mptsas_set_led_status(mpt, ptgt, ! 0); mutex_exit(&mpt->m_mutex); } else { rval = DDI_SUCCESS; } if (rval != DDI_SUCCESS) { --- 14674,14686 ---- if ((!MDI_PI_IS_ONLINE(*pip)) && (!MDI_PI_IS_STANDBY(*pip)) && (ptgt->m_tgt_unconfigured == 0)) { rval = mdi_pi_online(*pip, 0); mutex_enter(&mpt->m_mutex); ! ptgt->m_led_status = 0; ! (void) mptsas_flush_led_status(mpt, ! ptgt); mutex_exit(&mpt->m_mutex); } else { rval = DDI_SUCCESS; } if (rval != DDI_SUCCESS) {
*** 14787,14798 **** } NDBG20(("new path:%s onlining,", MDI_PI(*pip)->pi_addr)); mdi_rtn = mdi_pi_online(*pip, 0); if (mdi_rtn == MDI_SUCCESS) { mutex_enter(&mpt->m_mutex); ! if (mptsas_set_led_status(mpt, ptgt, 0) != ! DDI_SUCCESS) { NDBG14(("mptsas: clear LED for slot %x " "failed", ptgt->m_slot_num)); } mutex_exit(&mpt->m_mutex); } --- 14933,14944 ---- } NDBG20(("new path:%s onlining,", MDI_PI(*pip)->pi_addr)); mdi_rtn = mdi_pi_online(*pip, 0); if (mdi_rtn == MDI_SUCCESS) { mutex_enter(&mpt->m_mutex); ! ptgt->m_led_status = 0; ! if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) { NDBG14(("mptsas: clear LED for slot %x " "failed", ptgt->m_slot_num)); } mutex_exit(&mpt->m_mutex); }
*** 15149,15160 **** */ ndi_rtn = ndi_devi_online(*lun_dip, NDI_ONLINE_ATTACH); } if (ndi_rtn == NDI_SUCCESS) { mutex_enter(&mpt->m_mutex); ! if (mptsas_set_led_status(mpt, ptgt, 0) != ! DDI_SUCCESS) { NDBG14(("mptsas: clear LED for tgt %x " "failed", ptgt->m_slot_num)); } mutex_exit(&mpt->m_mutex); } --- 15295,15306 ---- */ ndi_rtn = ndi_devi_online(*lun_dip, NDI_ONLINE_ATTACH); } if (ndi_rtn == NDI_SUCCESS) { mutex_enter(&mpt->m_mutex); ! ptgt->m_led_status = 0; ! if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) { NDBG14(("mptsas: clear LED for tgt %x " "failed", ptgt->m_slot_num)); } mutex_exit(&mpt->m_mutex); }
*** 16051,16077 **** ptgt = mptsas_phy_to_tgt(mpt, (int)phymask, phynum); } return (ptgt); } - #ifdef MPTSAS_GET_LED static int ! mptsas_get_led_status(mptsas_t *mpt, mptsas_target_t *ptgt, ! uint32_t *slotstatus) { ! return (mptsas_send_sep(mpt, ptgt, slotstatus, ! MPI2_SEP_REQ_ACTION_READ_STATUS)); ! } ! #endif ! static int ! mptsas_set_led_status(mptsas_t *mpt, mptsas_target_t *ptgt, uint32_t slotstatus) ! { NDBG14(("mptsas_ioctl: set LED status %x for slot %x", slotstatus, ptgt->m_slot_num)); return (mptsas_send_sep(mpt, ptgt, &slotstatus, MPI2_SEP_REQ_ACTION_WRITE_STATUS)); } /* * send sep request, use enclosure/slot addressing */ static int mptsas_send_sep(mptsas_t *mpt, mptsas_target_t *ptgt, uint32_t *status, uint8_t act) --- 16197,16226 ---- ptgt = mptsas_phy_to_tgt(mpt, (int)phymask, phynum); } return (ptgt); } static int ! mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt) { ! uint32_t slotstatus = 0; ! ! /* Build an MPI2 Slot Status based on our view of the world */ ! if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_IDENT - 1))) ! slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST; ! if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_FAIL - 1))) ! slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT; ! if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_OK2RM - 1))) ! slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE; ! ! /* Write it to the controller */ NDBG14(("mptsas_ioctl: set LED status %x for slot %x", slotstatus, ptgt->m_slot_num)); return (mptsas_send_sep(mpt, ptgt, &slotstatus, MPI2_SEP_REQ_ACTION_WRITE_STATUS)); } + /* * send sep request, use enclosure/slot addressing */ static int mptsas_send_sep(mptsas_t *mpt, mptsas_target_t *ptgt, uint32_t *status, uint8_t act)