Synchronize with Feral CVS repository:

Add unit attention injection. Fix some ridiculous Sense things.

Say why we couldn't pci register the driver.

Make isp_thread_event return an int if it fails to send the event. If it
fails to send the event, and this was for the 24XX card finding out the
initiator for a command, return the command with a BUSY status.

An N-port handle of zero is legal for a 24XX.

Add some more special N-Port handle definitions for 2K f/w.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@265 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Stanislaw Gruszka
2008-02-12 09:40:40 +00:00
parent 4bfc86256a
commit dc71cd464c
10 changed files with 198 additions and 120 deletions

View File

@@ -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.

View File

@@ -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
/*

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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__);
}
}

View File

@@ -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
*/

View File

@@ -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;
}