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)