diff --git a/qla_isp/common/isp_target.c b/qla_isp/common/isp_target.c index 428a23ae3..41793ebed 100644 --- a/qla_isp/common/isp_target.c +++ b/qla_isp/common/isp_target.c @@ -1,4 +1,4 @@ -/* $Id: isp_target.c,v 1.71 2007/12/02 22:02:04 mjacob Exp $ */ +/* $Id: isp_target.c,v 1.72 2007/12/11 22:19:21 mjacob Exp $ */ /*- * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -1378,7 +1378,7 @@ isp_handle_ctio(ispsoftc_t *isp, ct_entry_t *ct) * Bus Device Reset message received or the SCSI Bus has * been Reset; the firmware has gone to Bus Free. * - * The firmware generates an async mailbox interupt to + * The firmware generates an async mailbox interrupt to * notify us of this and returns outstanding CTIOs with this * status. These CTIOs are handled in that same way as * CT_ABORTED ones, so just fall through here. @@ -1532,7 +1532,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) /* * Target Reset function received. * - * The firmware generates an async mailbox interupt to + * The firmware generates an async mailbox interrupt to * notify us of this and returns outstanding CTIOs with this * status. These CTIOs are handled in that same way as * CT_ABORTED ones, so just fall through here. diff --git a/qla_isp/common/ispvar.h b/qla_isp/common/ispvar.h index a9898da36..daceff939 100644 --- a/qla_isp/common/ispvar.h +++ b/qla_isp/common/ispvar.h @@ -1,4 +1,4 @@ -/* $Id: ispvar.h,v 1.87 2007/12/05 00:42:02 mjacob Exp $ */ +/* $Id: ispvar.h,v 1.88 2007/12/11 07:17:56 mjacob Exp $ */ /*- * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -272,7 +272,9 @@ typedef struct { #define NPH_RESERVED 0x7F0 /* begin of reserved N-port handles */ #define NPH_MGT_ID 0x7FA /* Management Server Special ID */ #define NPH_SNS_ID 0x7FC /* SNS Server Special ID */ -#define NPH_FL_ID 0x7FE /* FL Port Special ID */ +#define NPH_FABRIC_CTLR 0x7FD /* Fabric Controller (0xFFFFFD) */ +#define NPH_FL_ID 0x7FE /* F Port Special ID (0xFFFFFE) */ +#define NPH_IP_BCST 0x7ff /* IP Broadcast Special ID (0xFFFFFF) */ #define NPH_MAX_2K 0x800 /* diff --git a/qla_isp/linux-2.6/Makefile b/qla_isp/linux-2.6/Makefile index 89f57852c..ccdca3d8f 100644 --- a/qla_isp/linux-2.6/Makefile +++ b/qla_isp/linux-2.6/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 2007/03/10 02:27:53 mjacob Exp $ +# $Id: Makefile,v 1.9 2007/12/11 22:19:39 mjacob Exp $ # # Makefile # @@ -47,6 +47,9 @@ clean: install: @$(MAKE) -C ${LINUX} M=${CURDIR}/build modules_install +install_host_progs: + @$(MAKE) -C build $@ + links: @$(MAKE) -C build make_links diff --git a/qla_isp/linux/isp_cb_ops.c b/qla_isp/linux/isp_cb_ops.c index 81d10a41f..b75d55f98 100644 --- a/qla_isp/linux/isp_cb_ops.c +++ b/qla_isp/linux/isp_cb_ops.c @@ -1,4 +1,4 @@ -/* $Id: isp_cb_ops.c,v 1.78 2007/12/02 22:02:06 mjacob Exp $ */ +/* $Id: isp_cb_ops.c,v 1.79 2007/12/11 22:18:05 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -744,7 +744,7 @@ isp_ioctl(struct inode *ip, struct file *fp, unsigned int c, unsigned long arg) case ISP_FC_GETDLIST: { isp_dlist_t *ua; - uint16_t nph, nphs, nphe, count, chan, lim; + uint16_t nph, nphe, count, chan, lim; struct wwnpair pair, *uptr; if (IS_SCSI(isp)) { @@ -770,12 +770,7 @@ isp_ioctl(struct inode *ip, struct file *fp, unsigned int c, unsigned long arg) } else { nphe = NPH_MAX; } - if (IS_24XX(isp)) { - nphs = 1; - } else { - nphs = 0; - } - for (count = 0, nph = nphs; count < lim && nph != nphe; nph++) { + for (count = 0, nph = 0; count < lim && nph != nphe; nph++) { ISP_LOCKU_SOFTC(isp); rv = isp_control(isp, ISPCTL_GET_NAMES, chan, nph, &pair.wwnn, &pair.wwpn); ISP_UNLKU_SOFTC(isp); diff --git a/qla_isp/linux/isp_linux.c b/qla_isp/linux/isp_linux.c index e31e09cfc..a5f732bdd 100644 --- a/qla_isp/linux/isp_linux.c +++ b/qla_isp/linux/isp_linux.c @@ -1,4 +1,4 @@ -/* $Id: isp_linux.c,v 1.212 2007/12/09 00:05:43 mjacob Exp $ */ +/* $Id: isp_linux.c,v 1.213 2007/12/11 22:19:07 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -1918,22 +1918,18 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) } if ((tmd = isp->isp_osinfo.tfreelist) == NULL) { - /* - * We're out of resources. - * - * Because we can't autofeed sense data back with a command for - * parallel SCSI, we can't give back a CHECK CONDITION. We'll give - * back a QUEUE FULL or BUSY status instead. - */ - isp_prt(isp, ISP_LOGWARN, "Chan %d is out of TMDs for command from initiator %d for lun %u", - GET_BUS_VAL(aep->at_iid), GET_IID_VAL(aep->at_iid), aep->at_lun); - if (aep->at_flags & AT_TQAE) { - isp_endcmd(isp, aep, SCSI_QFULL, 0); - } else { - isp_endcmd(isp, aep, SCSI_BUSY, 0); + if (isp->isp_osinfo.out_of_tmds == 0) { + isp_prt(isp, ISP_LOGWARN, "out of TMDs"); + isp->isp_osinfo.out_of_tmds = jiffies; + } + isp_endcmd(isp, aep, SCSI_BUSY, 0); + if (jiffies - isp->isp_osinfo.out_of_tmds > 30 * HZ) { + isp_prt(isp, ISP_LOGERR, "out of TMDs too long: disabling port"); + ISP_THREAD_EVENT(isp, ISP_THREAD_REINIT, NULL, 0, __FUNCTION__, __LINE__); } return; } + isp->isp_osinfo.out_of_tmds = 0; if ((isp->isp_osinfo.tfreelist = tmd->cd_next) == NULL) { isp->isp_osinfo.bfreelist = NULL; } @@ -2014,14 +2010,18 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) * If we're out of resources, just send a QFULL status back. */ if ((tmd = isp->isp_osinfo.tfreelist) == NULL) { - isp_prt(isp, ISP_LOGWARN, "out of TMDs for command from 0x%016llx to lun %u", - (((uint64_t) aep->at_wwpn[0]) << 48) | - (((uint64_t) aep->at_wwpn[1]) << 32) | - (((uint64_t) aep->at_wwpn[2]) << 16) | - (((uint64_t) aep->at_wwpn[3]) << 0), lun); - isp_endcmd(isp, aep, SCSI_QFULL, 0); + if (isp->isp_osinfo.out_of_tmds == 0) { + isp_prt(isp, ISP_LOGWARN, "out of TMDs"); + isp->isp_osinfo.out_of_tmds = jiffies; + } + isp_endcmd(isp, aep, SCSI_BUSY, 0); + if (jiffies - isp->isp_osinfo.out_of_tmds > 30 * HZ) { + isp_prt(isp, ISP_LOGERR, "out of TMDs too long: disabling port"); + ISP_THREAD_EVENT(isp, ISP_THREAD_REINIT, NULL, 0, __FUNCTION__, __LINE__); + } return; } + isp->isp_osinfo.out_of_tmds = 0; if ((isp->isp_osinfo.tfreelist = tmd->cd_next) == NULL) { isp->isp_osinfo.bfreelist = NULL; } @@ -2177,23 +2177,29 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) } /* - * If the f/w is out of resources, just send a QUFLL status back. + * If the f/w is out of resources, just send a BUSY status back. */ if (aep->at_rxid == AT7_NORESRC_RXID) { - isp_prt(isp, ISP_LOGWARN, "%s: Chan %d F/W out of resources for command from 0x%016llxx/0x%06x to lun %u", __FUNCTION__, chan, (unsigned long long)iid, sid, lun); - isp_endcmd(isp, aep, nphdl, chan, SCSI_QFULL, 0); + isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0); return; } /* * If we're out of resources, just send a BUSY status back. */ - if ((tmd = isp->isp_osinfo.tfreelist) == NULL || aep->at_rxid == AT7_NORESRC_RXID) { - isp_prt(isp, ISP_LOGWARN, "%s: [RX_ID 0x%x] Chan %d out of TMDs for command from 0x%016llxx/0x%06x to lun %u", __FUNCTION__, aep->at_rxid, chan, - (unsigned long long)iid, sid, lun); - isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0); + if ((tmd = isp->isp_osinfo.tfreelist) == NULL) { + if (isp->isp_osinfo.out_of_tmds == 0) { + isp_prt(isp, ISP_LOGWARN, "out of TMDs"); + isp->isp_osinfo.out_of_tmds = jiffies; + } + isp_endcmd(isp, aep, chan, SCSI_BUSY, 0); + if (jiffies - isp->isp_osinfo.out_of_tmds > 30 * HZ) { + isp_prt(isp, ISP_LOGERR, "out of TMDs too long: disabling port"); + ISP_THREAD_EVENT(isp, ISP_THREAD_REINIT, NULL, 0, __FUNCTION__, __LINE__); + } return; } + isp->isp_osinfo.out_of_tmds = 0; if ((isp->isp_osinfo.tfreelist = tmd->cd_next) == NULL) { isp->isp_osinfo.bfreelist = NULL; } @@ -2286,7 +2292,16 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); } else { isp_prt(isp, ISP_LOGTDEBUG0, "[0x%llx] asking taskthread to find iid of initiator", (unsigned long long) tmd->cd_tagval); - ISP_THREAD_EVENT(isp, ISP_THREAD_FINDIID, tmd, 0, __FUNCTION__, __LINE__); + if (ISP_THREAD_EVENT(isp, ISP_THREAD_FINDIID, tmd, 0, __FUNCTION__, __LINE__)) { + isp_endcmd(isp, aep, nphdl, chan, SCSI_BUSY, 0); + MEMZERO(tmd, TMD_SIZE); + if (isp->isp_osinfo.tfreelist) { + isp->isp_osinfo.bfreelist->cd_next = tmd; + } else { + isp->isp_osinfo.tfreelist = tmd; + } + isp->isp_osinfo.bfreelist = tmd; + } } } @@ -4337,7 +4352,7 @@ isplinux_reinit(ispsoftc_t *isp) return (0); } -void +int isp_thread_event(ispsoftc_t *isp, int action, void *a, int dowait, const char *file, const int line) { DECLARE_MUTEX_LOCKED(sem); @@ -4349,7 +4364,7 @@ isp_thread_event(ispsoftc_t *isp, int action, void *a, int dowait, const char *f if (isp->isp_osinfo.task_active == 0) { spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); isp_prt(isp, ISP_LOGERR, "thread event %d from %s:%d sent when thread gone", action, file, line); - return; + return (-1); } /* @@ -4361,13 +4376,13 @@ isp_thread_event(ispsoftc_t *isp, int action, void *a, int dowait, const char *f tap->count++; spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); isp_prt(isp, ISP_LOGDEBUG1, "async thread event %d from %s:%d now has count %d", action, file, line, tap->count); - return; + return (0); } } if (isp->isp_osinfo.nt_actions >= MAX_THREAD_ACTION) { spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); isp_prt(isp, ISP_LOGERR, "thread event %d from %s:%d sent with thread overflow", action, file, line); - return; + return (-1); } tap = &isp->isp_osinfo.t_actions[isp->isp_osinfo.nt_actions++]; tap->count = 1; @@ -4388,6 +4403,7 @@ isp_thread_event(ispsoftc_t *isp, int action, void *a, int dowait, const char *f spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); isp_prt(isp, ISP_LOGDEBUG1, "action %d from %s:%d sent", action, file, line); } + return (0); } static int diff --git a/qla_isp/linux/isp_linux.h b/qla_isp/linux/isp_linux.h index fc3ef4756..52a09b44d 100644 --- a/qla_isp/linux/isp_linux.h +++ b/qla_isp/linux/isp_linux.h @@ -1,4 +1,4 @@ -/* $Id: isp_linux.h,v 1.145 2007/12/05 00:41:42 mjacob Exp $ */ +/* $Id: isp_linux.h,v 1.146 2007/12/11 22:19:07 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -361,6 +361,7 @@ struct isposinfo { u64 cmds_started; u64 cmds_completed; + unsigned long out_of_tmds; #endif }; #define mbtimer isp_osinfo.mbtimer @@ -678,7 +679,7 @@ void isplinux_undo_proc(ispsoftc_t *); int isplinux_reinit(ispsoftc_t *); void isplinux_sqd(struct Scsi_Host *, struct scsi_device *); -void isp_thread_event(ispsoftc_t *, int, void *, int, const char *, const int line); +int isp_thread_event(ispsoftc_t *, int, void *, int, const char *, const int line); static inline uint64_t _isp_microtime_sub(struct timeval *, struct timeval *); static inline void _isp_usec_delay(unsigned int); diff --git a/qla_isp/linux/isp_pci.c b/qla_isp/linux/isp_pci.c index 5af3af3d1..1a3bb4c3d 100644 --- a/qla_isp/linux/isp_pci.c +++ b/qla_isp/linux/isp_pci.c @@ -1,4 +1,4 @@ -/* $Id: isp_pci.c,v 1.147 2007/12/09 00:08:24 mjacob Exp $ */ +/* $Id: isp_pci.c,v 1.148 2007/12/11 22:17:34 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -3341,6 +3341,7 @@ isplinux_pci_init(void) } ret = pci_register_driver(&isplinux_pci_driver); if (ret < 0) { + printk(KERN_ERR "%s: unable to register driver (return value %d)", __FUNCTION__, ret); unregister_chrdev_region(isp_dev, MAX_ISP); return (ret); } diff --git a/qla_isp/linux/scsi_target.c b/qla_isp/linux/scsi_target.c index 5267171f1..ef9d26831 100644 --- a/qla_isp/linux/scsi_target.c +++ b/qla_isp/linux/scsi_target.c @@ -1,4 +1,4 @@ -/* $Id: scsi_target.c,v 1.75 2007/12/02 22:02:06 mjacob Exp $ */ +/* $Id: scsi_target.c,v 1.76 2007/12/11 22:16:38 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -413,64 +413,6 @@ static struct file_operations scsi_target_fops = { .owner = THIS_MODULE, }; -static int -scsi_target_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) -{ - int rv = 0; - - switch(cmd) { - case SC_ENABLE_LUN: - case SC_DISABLE_LUN: - { - sc_enable_t local, *sc = &local; - if (COPYIN((void *)arg, (void *)sc, sizeof (*sc))) { - rv = -EFAULT; - break; - } - rv = scsi_target_endis(sc->hba_name_unit, sc->nbytes, sc->channel, sc->lun, (cmd == SC_ENABLE_LUN)? ((sc->flags & SC_EF_OVERCOMMIT)? 2 : 1) : 0); - break; - } - case SC_PUT_IO: - case SC_GET_IO: - { - sc_io_t sc; - - if (COPYIN((void *)arg, (void *)&sc, sizeof (sc))) { - rv = -EFAULT; - break; - } - if (cmd == SC_PUT_IO) { - rv = scsi_target_end_user_io(&sc); - } else { - rv = scsi_target_start_user_io(&sc); - } - if (COPYOUT((void *)&sc, (void *)arg, sizeof (sc))) { - if (rv == 0) { - rv = EFAULT; - } - } - break; - } - case SC_DEBUG: - { - int odebug = scsi_tdebug; - if (COPYIN((void *)arg, (void *)&scsi_tdebug, sizeof (int))) { - rv = EFAULT; - break; - } - if (COPYOUT((void *)&odebug, (void *)arg, sizeof (int))) { - rv = EFAULT; - break; - } - break; - } - default: - rv = -EINVAL; - break; - } - return (rv); -} - static __inline int validate_bus_pointer(bus_t *bp, void *identity) { @@ -542,6 +484,107 @@ bus_from_notify(tmd_notify_t *np) return (NULL); } +static int +scsi_target_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +{ + int rv = 0; + + switch(cmd) { + case SC_ENABLE_LUN: + case SC_DISABLE_LUN: + { + sc_enable_t local, *sc = &local; + if (COPYIN((void *)arg, (void *)sc, sizeof (*sc))) { + rv = -EFAULT; + break; + } + rv = scsi_target_endis(sc->hba_name_unit, sc->nbytes, sc->channel, sc->lun, (cmd == SC_ENABLE_LUN)? ((sc->flags & SC_EF_OVERCOMMIT)? 2 : 1) : 0); + break; + } + case SC_PUT_IO: + case SC_GET_IO: + { + sc_io_t sc; + + if (COPYIN((void *)arg, (void *)&sc, sizeof (sc))) { + rv = -EFAULT; + break; + } + if (cmd == SC_PUT_IO) { + rv = scsi_target_end_user_io(&sc); + } else { + rv = scsi_target_start_user_io(&sc); + } + if (COPYOUT((void *)&sc, (void *)arg, sizeof (sc))) { + if (rv == 0) { + rv = EFAULT; + } + } + break; + } + case SC_DEBUG: + { + int odebug = scsi_tdebug; + if (COPYIN((void *)arg, (void *)&scsi_tdebug, sizeof (int))) { + rv = EFAULT; + break; + } + if (COPYOUT((void *)&odebug, (void *)arg, sizeof (int))) { + rv = EFAULT; + break; + } + break; + } + case SC_INJECT_UA: + { + sc_inject_ua_t local, *sc = &local; + bus_t *bp; + struct bus_chan *bc; + unsigned long flags; + int i, n; + + if (COPYIN((void *)arg, (void *)sc, sizeof (sc))) { + rv = -EFAULT; + break; + } + spin_lock_irqsave(&scsi_target_lock, flags); + bp = bus_from_name(sc->hba_name_unit); + if (bp == NULL) { + spin_unlock_irqrestore(&scsi_target_lock, flags); + rv = -ENXIO; + break; + } + for (rv = n = 0; n < bp->h.r_nchannels && rv == 0; n++) { + bc = &bp->bchan[n]; + for (i = 0; i < HASH_WIDTH && rv == 0; i++) { + ini_t *ini; + for (ini = bc->list[i]; ini; ini = ini->ini_next) { + sdata_t *t = sdp; + if (t == NULL) { + rv = -ENOMEM; + break; + } + sdp = t->next; + t->next = NULL; + memcpy(t->sdata, ua, sizeof (ua)); + if (ini->ini_sdata == NULL) { + ini->ini_sdata = t; + } else { + ini->ini_sdata_tail->next = t; + } + ini->ini_sdata_tail = t; + } + } + } + spin_unlock_irqrestore(&scsi_target_lock, flags); + break; + } + default: + rv = -EINVAL; + break; + } + return (rv); +} /* * Make an initiator structure @@ -1081,8 +1124,14 @@ doit: xact->td_hflags |= TDFH_STSVALID; if (ini && ini->ini_sdata) { memcpy(tmd->cd_sense, ini->ini_sdata->sdata, TMD_SENSELEN); + rem_sdata(ini); } else { - memset(tmd->cd_sense, 0, TMD_SENSELEN); + if (ini == NULL) { + printk("%s%d: no initiator structure for sense data\n", bp->h.r_name, bp->h.r_inst); + } else { + printk("%s%d: no sense data available\n", bp->h.r_name, bp->h.r_inst); + } + memcpy(tmd->cd_sense, nosense, TMD_SENSELEN); } printk("%s%d: INI(%#llx)=>LUN %d: [%llx] cdb0=0x%02x tl=%u CHECK (0x%x 0x%x 0x%x)\n", bp->h.r_name, bp->h.r_inst, tmd->cd_iid, L0LUN_TO_FLATLUN(tmd->cd_lun), tmd->cd_tagval, tmd->cd_cdb[0] & 0xff, tmd->cd_totlen, tmd->cd_sense[2] & 0xf, tmd->cd_sense[12], tmd->cd_sense[13]); @@ -1827,7 +1876,6 @@ scsi_target_handler(qact_e action, void *arg) { tmd_xact_t *xact = arg; tmd_cmd_t *tmd = xact->td_cmd; - ini_t *nptr; bp = bus_from_tmd(tmd); if (bp == NULL) { @@ -1895,13 +1943,8 @@ scsi_target_handler(qact_e action, void *arg) * Did we send sense? If so, remove one sense structure. */ if (xact->td_hflags & TDFH_SNSVALID) { - if (xact->td_lflags & TDFL_SENTSENSE) { - spin_lock_irqsave(&scsi_target_lock, flags); - nptr = ini_from_tmd(bp, tmd); - spin_unlock_irqrestore(&scsi_target_lock, flags); - if (nptr) { - rem_sdata(nptr); - } + if ((xact->td_lflags & TDFL_SENTSENSE) == 0) { + printk(KERN_WARNING "%s: oops, lost sense data\n", __FUNCTION__); } } diff --git a/qla_isp/linux/scsi_target.h b/qla_isp/linux/scsi_target.h index 58e82370f..d3477dcca 100644 --- a/qla_isp/linux/scsi_target.h +++ b/qla_isp/linux/scsi_target.h @@ -1,4 +1,4 @@ -/* $Id: scsi_target.h,v 1.28 2007/12/02 22:02:07 mjacob Exp $ */ +/* $Id: scsi_target.h,v 1.29 2007/12/11 22:16:09 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -105,6 +105,15 @@ typedef struct { } sc_io_t; #define SC_GET_IO (_SI | 3) #define SC_PUT_IO (_SI | 4) + +/* + * Inject a UNIT ATTENTION error on the next command for this device + */ +typedef struct { + char hba_name_unit[16]; +} sc_inject_ua_t; +#define SC_INJECT_UA (_SI | 21) + /* * vim:ts=4:sw=4:expandtab */ diff --git a/qla_isp/linux/scsi_target_ctl.c b/qla_isp/linux/scsi_target_ctl.c index e4ffc0ff3..f9a240192 100644 --- a/qla_isp/linux/scsi_target_ctl.c +++ b/qla_isp/linux/scsi_target_ctl.c @@ -1,4 +1,4 @@ -/* $Id: scsi_target_ctl.c,v 1.20 2007/12/02 22:02:07 mjacob Exp $ */ +/* $Id: scsi_target_ctl.c,v 1.21 2007/12/11 22:16:55 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -76,7 +76,8 @@ const char usage[] = "usage: %s\n\ scsi_target_ctl debug level\n\ scsi_target_ctl enable hba-name-unit channel lun nbytes [ overcommit-file ]\n\ - scsi_target_ctl disable hba-name-unit channel lun\n"; + scsi_target_ctl disable hba-name-unit channel lun\n\ + scsi_target_ctl ua hba-name-unit\n"; static uint64_t szarg(char *); static void ioloop(int, int, char *, uint16_t); @@ -88,6 +89,7 @@ main(int a, char **v) union { sc_enable_t _x; int _y; + sc_inject_ua_t _u; } x; int iofd = -1, fd, action, dd = 0; char *progname; @@ -142,6 +144,12 @@ main(int a, char **v) } action = SC_DEBUG; dd = x._y = atoi(v[2]); + } else if (strcmp(v[1], "ua") == 0) { + if (a != 3) { + goto usage; + } + strncpy(x._u.hba_name_unit, v[2], sizeof (x._u.hba_name_unit)); + action = SC_INJECT_UA; } else { goto usage; }