synchronize with feral cvs repository, this time Matthew fix autosense problems :-)

+ The 24XX code in isp_target_start_ctio was setting the wrong values 
to set SENSE LENGTH VALID for the FCP RSPNS IU.

+ Amusingly enough, this apparently didn't matter. In fact, once sense 
data was being put into the ct7_entry_t there was *still* a problem 
and REQUEST SENSE was being sent by the Linux initiator.

+ What *was* happening is that the 24XX requries the response data to
be 32 bit swapped. This is not obvious from the chip documents.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@215 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Stanislaw Gruszka
2007-11-02 08:43:47 +00:00
parent 71592f2cac
commit 8c1327661b
10 changed files with 1043 additions and 1033 deletions
+14 -4
View File
@@ -1,4 +1,4 @@
/* $Id: isp_library.c,v 1.44 2007/07/07 23:20:56 mjacob Exp $ */
/* $Id: isp_library.c,v 1.46 2007/10/29 18:12:33 mjacob Exp $ */
/*-
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -2049,12 +2049,15 @@ isp_put_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst)
ISP_IOXPUT_32(isp, src->rsp.m0.ds.ds_count,
&dst->rsp.m0.ds.ds_count);
} else if ((dst->ct_flags & CT7_FLAG_MMASK) == CT7_FLAG_MODE1) {
uint32_t *a, *b;
ISP_IOXPUT_16(isp, src->rsp.m1.ct_resplen,
&dst->rsp.m1.ct_resplen);
ISP_IOXPUT_16(isp, src->rsp.m1.reserved, &dst->rsp.m1.reserved);
for (i = 0; i < MAXRESPLEN_24XX; i++) {
ISP_IOXPUT_8(isp, src->rsp.m1.ct_resp[i],
&dst->rsp.m1.ct_resp[i]);
a = (uint32_t *) src->rsp.m1.ct_resp;
b = (uint32_t *) dst->rsp.m1.ct_resp;
for (i = 0; i < (ASIZE(src->rsp.m1.ct_resp) >> 2); i++) {
*b++ = ISP_SWAP32(isp, *a++);
}
} else {
ISP_IOXPUT_32(isp, src->rsp.m2.reserved0,
@@ -2278,13 +2281,20 @@ isp_get_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst)
ISP_IOXGET_32(isp, &src->rsp.m0.ds.ds_count,
dst->rsp.m0.ds.ds_count);
} else if ((dst->ct_flags & CT7_FLAG_MMASK) == CT7_FLAG_MODE1) {
uint32_t *a, *b;
ISP_IOXGET_16(isp, &src->rsp.m1.ct_resplen,
dst->rsp.m1.ct_resplen);
ISP_IOXGET_16(isp, &src->rsp.m1.reserved, dst->rsp.m1.reserved);
a = (uint32_t *) src->rsp.m1.ct_resp;
b = (uint32_t *) dst->rsp.m1.ct_resp;
for (i = 0; i < MAXRESPLEN_24XX; i++) {
ISP_IOXGET_8(isp, &src->rsp.m1.ct_resp[i],
dst->rsp.m1.ct_resp[i]);
}
for (i = 0; i < (ASIZE(src->rsp.m1.ct_resp) >> 2); i++) {
*b++ = ISP_SWAP32(isp, *a++);
}
} else {
ISP_IOXGET_32(isp, &src->rsp.m2.reserved0,
dst->rsp.m2.reserved0);
+12 -2
View File
@@ -1,4 +1,4 @@
/* $Id: isp_stds.h,v 1.11 2007/07/07 23:20:56 mjacob Exp $ */
/* $Id: isp_stds.h,v 1.12 2007/10/29 18:11:08 mjacob Exp $ */
/*-
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -163,9 +163,19 @@ typedef struct {
uint32_t rftid_fc4types[8];
} rft_id_t;
/*
* FCP Response IU Bits of interest
* Source: NCITS T10, Project 1144D, Revision 08 (aka FCP2r08)
*/
#define FCP_CONF_REQ 0x10
#define FCP_RESID_UNDERFLOW 0x08
#define FCP_RESID_OVERFLOW 0x04
#define FCP_SNSLEN_VALID 0x02
#define FCP_RSPLEN_VALID 0x01
/*
* FCP Response Code Definitions
* Source: NCITS T10, Project 1144D, Revision 07a (aka FCP2r07a)
* Source: NCITS T10, Project 1144D, Revision 08 (aka FCP2r08)
*/
#define FCP_RSPNS_CODE_OFFSET 3
+3 -3
View File
@@ -1,4 +1,4 @@
/* $Id: isp_target.h,v 1.53 2007/07/07 23:20:56 mjacob Exp $ */
/* $Id: isp_target.h,v 1.55 2007/10/29 18:12:02 mjacob Exp $ */
/*-
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -788,10 +788,10 @@ typedef struct {
#define CT7_EXPLCT_CONF 0x0020
#define CT7_FLAG_MODE0 0x0000
#define CT7_FLAG_MODE1 0x0040
#define CT7_FLAG_MODE7 0x0080
#define CT7_FLAG_MODE2 0x0080
#define CT7_FLAG_MMASK 0x00C0
#define CT7_FASTPOST 0x0100
#define CT7_ATTR_MASK 0x1e00 /* task attributes from atio7 */
#define CT7_TASK_ATTR_SHIFT 9
#define CT7_CONFIRM 0x2000
#define CT7_TERMINATE 0x4000
#define CT7_SENDSTATUS 0x8000
+63 -64
View File
@@ -1,4 +1,4 @@
/* $Id: isp_tpublic.h,v 1.34 2007/07/07 23:20:56 mjacob Exp $ */
/* $Id: isp_tpublic.h,v 1.36 2007/10/31 05:28:18 mjacob Exp $ */
/*-
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -68,7 +68,7 @@ typedef enum {
QOUT_ENABLE, /* the argument is a pointer to a enadis_t */
QOUT_DISABLE, /* the argument is a pointer to a enadis_t */
QOUT_TMD_START, /* the argument is a pointer to a tmd_cmd_t */
QOUT_TMD_DONE, /* the argument is a pointer to a tmd_cmd_t */
QOUT_TMD_DONE, /* the argument is a pointer to a tmd_xfr_t */
QOUT_NOTIFY, /* the argument is a pointer to a tmd_notify_t */
QOUT_HBA_UNREG /* the argument is a pointer to a hba_register_t */
} tact_e;
@@ -84,7 +84,7 @@ typedef enum {
QIN_GETDLIST, /* the argument is a pointer to a fc_dlist_t */
QIN_ENABLE, /* the argument is a pointer to a enadis_t */
QIN_DISABLE, /* the argument is a pointer to a enadis_t */
QIN_TMD_CONT, /* the argument is a pointer to a tmd_cmd_t */
QIN_TMD_CONT, /* the argument is a pointer to a tmd_xfr_t */
QIN_TMD_FIN, /* the argument is a pointer to a tmd_cmd_t */
QIN_NOTIFY_ACK, /* the argument is a pointer to a tmd_notify_t */
QIN_HBA_UNREG, /* the argument is a pointer to a hba_register_t */
@@ -100,7 +100,7 @@ typedef enum {
* in, and the external module to call back with a QIN_HBA_REG that
* passes back the corresponding information.
*/
#define QR_VERSION 16
#define QR_VERSION 18
typedef struct {
/* NB: tags from here to r_version must never change */
void * r_identity;
@@ -193,7 +193,7 @@ typedef struct tmd_notify {
* with en_hba, en_iid, en_chan, en_tgt and en_lun filled out.
*
* If an error occurs in either enabling or disabling the described lun
* cd_error is set with an appropriate non-zero value.
* en_error is set with an appropriate non-zero value.
*/
typedef struct {
void * en_private; /* for outer layer usage */
@@ -227,13 +227,6 @@ typedef struct {
* but since the handling of thbis is entirely in the MD layer, there is
* no explicit or implicit requirement that it be used.
*
* The cd_private tag should be used by the MD layer to keep a free list
* of these structures. Code outside of this driver can then use this
* to identify it's own unit structures. That is, when not on the MD
* layer's freelist, the MD layer should shove into it the identifier
* that the outer layer has for it- passed in on an initial QIN_HBA_REG
* call (see below).
*
* The cd_hba tag is a tag that uniquely identifies the HBA this target
* mode command is coming from. The outer layer has to pass this back
* unchanged to avoid chaos.
@@ -287,20 +280,19 @@ typedef struct {
* layers set to zero and the CDB indicates data should be moved, the outer
* layer should set it to the amount expected to be moved.
*
* The tag cd_resid should be the total residual of data not transferred.
* The outer layers need to set this at the begining of command processing
* to equal cd_totlen. As data is successfully moved, this value is decreased.
* At the end of a command, any nonzero residual indicates the number of bytes
* requested by the command but not moved.
*
* The tag cd_xfrlen is the length of the currently active data transfer.
* The tag cd_offset is the current offset within the entire command that
* this data transfer starts at (this only makes sense for Fibre Channel).
*
* This allows several interations between any outside software and the
* MD layer to move data.
* MD layer to move data. It is undefined what may occur if the data
* segments are transferred out of order.
*
* The reason that total length and total residual have to be tracked
* is to keep track of relative offset.
* is to make sure that residual is calculated correctly.
*
* The tags cd_sense and cd_scsi_status are pretty obvious.
* The tags cd_sense and cd_scsi_status are pretty obvious and only are
* valid if CDFS_SNSVALID and CDFS_STSVALID are set.
*
* The tag cd_error is to communicate between the MD layer and outer software
* the current error conditions.
@@ -310,43 +302,70 @@ typedef struct {
*
*/
#ifndef TMD_CDBLEN
#define TMD_CDBLEN 16
#ifndef TMD_CDBLEN
#define TMD_CDBLEN 16
#endif
#ifndef TMD_SENSELEN
#define TMD_SENSELEN 18
#ifndef TMD_SENSELEN
#define TMD_SENSELEN 18
#endif
#ifndef QCDS
#define QCDS (sizeof (void *))
#ifndef QCDS
#define QCDS (sizeof (uint64_t))
#endif
typedef struct tmd_cmd {
void * cd_private; /* private data pointer */
typedef struct tmd_cmd tmd_cmd_t;
typedef struct tmd_xfr {
tmd_cmd_t * td_cmd; /* cross-referenced tmd_cmd_t */
void * td_data; /* data descriptor */
void * td_lprivate; /* private for lower layer */
uint32_t td_xfrlen; /* size of this data load */
uint32_t td_offset; /* offset for this data load */
int td_error; /* error with this transfer or zero */
uint8_t td_hflags; /* flags set by caller */
uint8_t td_lflags; /* flags set by callee */
} tmd_xfr_t;
#define TDFL_SENTSTATUS 0x01 /* this action sent status */
#define TDFL_SENTSENSE 0x02 /* this action sent sense data */
#define TDFH_STSVALID 0x01 /* status valid - include it */
#define TDFH_SNSVALID 0x02 /* sense data (from outer layer) good - include it */
#define TDFH_DATA_IN 0x04 /* target (us) -> initiator (them) */
#define TDFH_DATA_OUT 0x08 /* initiator (them) -> target (us) */
#define TDFH_DATA_MASK 0x0C /* mask to cover data direction */
#define TDFH_BUSY 0x40 /* busy */
#define TDFH_PRIMARY 0x80 /* within tmd */
struct tmd_cmd {
void * cd_hba; /* HBA tag */
void * cd_data; /* 'pointer' to data */
uint64_t cd_iid; /* initiator ID */
uint64_t cd_tgt; /* target id */
uint8_t cd_lun[8]; /* logical unit */
uint64_t cd_tagval; /* tag value */
uint32_t cd_channel; /* channel index */
uint32_t cd_lflags; /* flags lower level sets */
uint32_t cd_hflags; /* flags higher level sets */
uint8_t cd_lun[8]; /* logical unit */
uint32_t cd_totlen; /* total data load */
uint32_t cd_resid; /* total data residual */
uint32_t cd_xfrlen; /* current data load */
int32_t cd_error; /* current error */
uint32_t cd_moved; /* total data moved so far */
uint16_t cd_channel; /* channel index */
uint16_t cd_flags; /* flags */
uint16_t cd_req_cnt; /* how many tmd_xfr_t's are active */
uint8_t cd_cdb[TMD_CDBLEN];
uint8_t cd_tagtype; /* tag type */
uint8_t cd_scsi_status;
uint8_t cd_sense[TMD_SENSELEN];
uint8_t cd_cdb[TMD_CDBLEN];
tmd_xfr_t cd_xfr; /* first or only transfer structure */
union {
void * ptrs[QCDS / sizeof (void *)];
uint64_t llongs[QCDS / sizeof (uint64_t)];
uint32_t longs[QCDS / sizeof (uint32_t)];
uint16_t shorts[QCDS / sizeof (uint16_t)];
uint8_t bytes[QCDS];
void * ptrs[QCDS / sizeof (void *)]; /* (assume) one pointer */
uint64_t llongs[QCDS / sizeof (uint64_t)]; /* one long long */
uint32_t longs[QCDS / sizeof (uint32_t)]; /* two longs */
uint16_t shorts[QCDS / sizeof (uint16_t)]; /* four shorts */
uint8_t bytes[QCDS]; /* eight bytes */
} cd_lreserved[4], cd_hreserved[4];
} tmd_cmd_t;
};
#define CDF_NODISC 0x0001 /* disconnects disabled */
#define CDF_DATA_IN 0x0002 /* target (us) -> initiator (them) */
#define CDF_DATA_OUT 0x0004 /* initiator (them) -> target (us) */
#define CDF_BIDIR 0x0006 /* bidirectional data */
#define CDF_SNSVALID 0x0008 /* sense is set on incoming command */
#define CDF_PRIVATE 0xff00 /* available for private use in outer layer */
/* defined tags */
#define CD_UNTAGGED 0
@@ -377,8 +396,6 @@ typedef struct tmd_cmd {
memset(&(lptr)[2], 0, 6)
/*
* Note that NODISC (obviously) doesn't apply to non-SPI transport.
*
* Note that knowing the data direction and lengh at the time of receipt of
* a command from the initiator is a feature only of Fibre Channel.
*
@@ -389,24 +406,6 @@ typedef struct tmd_cmd {
* be transferred in any QOUT_TMD_CONT call is cd_xfrlen- the
* flags CDFH_DATA_IN and CDFH_DATA_OUT define which direction.
*/
#define CDFL_SNSVALID 0x01 /* sense data (from f/w) good */
#define CDFL_SENTSTATUS 0x02 /* last action sent status */
#define CDFL_DATA_IN 0x04 /* target (us) -> initiator (them) */
#define CDFL_DATA_OUT 0x08 /* initiator (them) -> target (us) */
#define CDFL_BIDIR 0x0C /* bidirectional data */
#define CDFL_ERROR 0x10 /* last action ended in error */
#define CDFL_NODISC 0x20 /* disconnects disabled */
#define CDFL_SENTSENSE 0x40 /* last action sent sense data */
#define CDFL_BUSY 0x80 /* this command is not on a free list */
#define CDFL_PRIVATE 0xFF000000 /* private layer flags */
#define CDFH_SNSVALID 0x01 /* sense data (from outer layer) good */
#define CDFH_STSVALID 0x02 /* status valid */
#define CDFH_DATA_IN 0x04 /* target (us) -> initiator (them) */
#define CDFH_DATA_OUT 0x08 /* initiator (them) -> target (us) */
#define CDFH_DATA_MASK 0x0C /* mask to cover data direction */
#define CDFH_PRIVATE 0xFF000000 /* private layer flags */
/*
* A word about the START/CONT/DONE/FIN dance:
+7 -6
View File
@@ -1,4 +1,4 @@
/* $Id: ispvar.h,v 1.84 2007/10/11 22:08:38 mjacob Exp $ */
/* $Id: ispvar.h,v 1.85 2007/10/30 01:54:46 mjacob Exp $ */
/*-
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -490,14 +490,14 @@ struct ispsoftc {
uint32_t isp_maxluns; /* maximum luns supported */
uint32_t isp_clock : 8, /* input clock */
: 5,
: 1,
isp_port : 1, /* 23XX/24XX only */
isp_failed : 1, /* board failed */
isp_open : 1, /* opened (ioctl) */
isp_bustype : 1, /* SBus or PCI */
isp_loaded_fw : 1, /* loaded firmware */
isp_role : 2, /* roles supported */
isp_dblev : 12; /* debug log mask */
isp_dblev : 16; /* debug log mask */
uint32_t isp_confopts; /* config options */
@@ -919,9 +919,10 @@ int isp_async(ispsoftc_t *, ispasync_t, void *);
#define ISP_LOGDEBUG2 0x40 /* log most debug messages */
#define ISP_LOGDEBUG3 0x80 /* log high frequency debug messages */
#define ISP_LOGSANCFG 0x100 /* log SAN configuration */
#define ISP_LOGTDEBUG0 0x200 /* log simple debug messages (target mode) */
#define ISP_LOGTDEBUG1 0x400 /* log intermediate debug messages (target) */
#define ISP_LOGTDEBUG2 0x800 /* log all debug messages (target) */
#define ISP_LOGTINFO 0x1000 /* log informational messages (target mode) */
#define ISP_LOGTDEBUG0 0x2000 /* log simple debug messages (target mode) */
#define ISP_LOGTDEBUG1 0x4000 /* log intermediate debug messages (target) */
#define ISP_LOGTDEBUG2 0x8000 /* log all debug messages (target) */
/*
* Each Platform provides it's own isposinfo substructure of the ispsoftc
+527 -507
View File
File diff suppressed because it is too large Load Diff
+48 -38
View File
@@ -1,4 +1,4 @@
/* $Id: isp_linux.h,v 1.138 2007/10/11 22:08:07 mjacob Exp $ */
/* $Id: isp_linux.h,v 1.139 2007/10/27 18:16:29 mjacob Exp $ */
/*
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -218,6 +218,8 @@ typedef u_long vm_offset_t;
#ifdef ISP_TARGET_MODE
#include "isp_tpublic.h"
#ifndef DEFAULT_DEVICE_TYPE
#define DEFAULT_DEVICE_TYPE 0
#endif
@@ -225,27 +227,43 @@ typedef u_long vm_offset_t;
#define N_NOTIFIES 256
#define DEFAULT_INQSIZE 32
#define _WIX(isp, b, ix) (((b << 6)) | (ix >> 5))
#define _BIX(isp, ix) (1 << (ix & 0x1f))
#define WIX(ix) (ix >> 5)
#define BIX(ix) (1 << (ix & 0x1f))
#define LUN_BTST(isp, b, ix) (((isp)->isp_osinfo.lunbmap[_WIX(isp, b, ix)] & _BIX(isp, ix)) != 0)
#define LUN_BSET(isp, b, ix) isp->isp_osinfo.lunbmap[_WIX(isp, b, ix)] |= _BIX(isp, ix)
#define LUN_BCLR(isp, b, ix) isp->isp_osinfo.lunbmap[_WIX(isp, b, ix)] &= ~_BIX(isp, ix)
#define LUN_BTST(bmap, ix) ((bmap[WIX(ix)] & BIX(ix)) != 0)
#define LUN_BSET(bmap, ix) bmap[WIX(ix)] |= BIX(ix)
#define LUN_BCLR(bmap, ix) bmap[WIX(ix)] &= ~BIX(ix)
typedef struct isp_notify isp_notify_t;
#define cd_action cd_lreserved[0].shorts[0]
#define cd_oxid cd_lreserved[0].shorts[1]
#define cd_next cd_lreserved[1].ptrs[0]
#define cd_nphdl cd_lreserved[2].shorts[0]
#define cd_nseg cd_lreserved[2].shorts[1]
#define cd_portid cd_lreserved[3].longs[0]
#define cd_lflags cd_lreserved[0].shorts[2]
#define cd_nphdl cd_lreserved[0].shorts[3]
#define cd_nseg cd_lreserved[1].longs[0]
#define cd_portid cd_lreserved[1].longs[1]
#define cd_next cd_lreserved[2].ptrs[0]
#define cd_lastoff cd_lreserved[3].longs[0]
#define cd_lastsize cd_lreserved[3].longs[1]
#define CDFL_LCL 0x80000000
#define CDFL_RESRC_FILL 0x40000000
#define CDFL_CALL_CMPLT 0x20000000
#define CDFL_ABORTED 0x10000000
#define CDFL_NEED_CLNUP 0x08000000
#define CDFL_LCL 0x8000
#define CDFL_RESRC_FILL 0x4000
#define CDFL_ABORTED 0x2000
#define CDFL_NEED_CLNUP 0x1000
#define CDFL_BUSY 0x0800
typedef struct enalun tgt_enalun_t;
struct enalun {
tgt_enalun_t * next;
uint16_t lun;
uint16_t bus;
};
typedef struct {
struct scatterlist sg;
tmd_xfr_t xfr;
} tgt_auxcmd_t;
#define N_TGT_AUX 32
#endif /* ISP_TARGET_MODE */
@@ -313,31 +331,14 @@ struct isposinfo {
unsigned int device_id;
isp_thread_action_t t_actions[MAX_THREAD_ACTION];
#ifdef ISP_TARGET_MODE
#define TM_WANTED 0x08
#define TM_BUSY 0x04
#define TM_TMODE_ENABLED 0x03
uint32_t rollinfo : 16,
rstatus : 8,
: 1,
: 6,
isget : 1,
wildcarded : 1,
hcb : 1,
tmflags : 4;
hcb : 1;
struct semaphore tgt_inisem;
struct semaphore * rsemap;
/*
* This is very inefficient, but is in fact big enough
* to cover a complete bitmap for Fibre Channel, as well
* as the dual bus SCSI cards. This works out without
* overflow easily because the most you can enable
* for the SCSI cards is 64 luns (x 2 busses).
*
* For Fibre Channel, we can run the max luns up to 16384
* but we'll default to the minimum we can support here.
*/
#define TM_MAX_LUN_FC 64
#define TM_MAX_LUN_SCSI 64
uint32_t lunbmap[TM_MAX_LUN_FC >> 5];
tgt_enalun_t * luns; /* enabled { lun, port } tuples */
struct tmd_cmd * pending_t; /* pending list of commands going upstream */
struct tmd_cmd * tfreelist; /* freelist head */
struct tmd_cmd * bfreelist; /* freelist tail */
@@ -345,8 +346,16 @@ struct isposinfo {
isp_notify_t * pending_n; /* pending list of notifies going upstream */
isp_notify_t * nfreelist; /* freelist */
isp_notify_t * npool; /* pool itself */
struct scatterlist * dpwrk;
uint8_t * inqdata;
struct tmd_xfr * pending_x; /* pending list of xfrs going upstream */
/*
* When we have inquiry commands that we have to xfer data with
* locally we have to have some aux info (scatterlist, tmd_xfr_t)
* to manage those commands.
*/
tgt_auxcmd_t auxinfo[N_TGT_AUX];
uint32_t auxbmap[N_TGT_AUX >> 5];
uint8_t inqdata[DEFAULT_INQSIZE];
uint64_t cmds_started;
uint64_t cmds_completed;
struct {
@@ -988,7 +997,8 @@ void isp_deinit_target(ispsoftc_t *);
void isp_detach_target(ispsoftc_t *);
int isp_target_async(ispsoftc_t *, int, int);
int isp_target_notify(ispsoftc_t *, void *, uint32_t *);
int isp_en_dis_lun(ispsoftc_t *, int, uint16_t, uint64_t, uint16_t);
int isp_enable_lun(ispsoftc_t *, uint16_t, uint64_t, uint16_t);
int isp_disable_lun(ispsoftc_t *, uint16_t, uint64_t, uint16_t);
struct isp_notify {
tmd_notify_t notify;
+114 -134
View File
@@ -1,4 +1,4 @@
/* $Id: isp_pci.c,v 1.137 2007/10/11 22:08:07 mjacob Exp $ */
/* $Id: isp_pci.c,v 1.139 2007/10/30 01:55:10 mjacob Exp $ */
/*
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -1388,8 +1388,8 @@ bad:
}
#ifdef ISP_TARGET_MODE
static int tdma_mk(ispsoftc_t *, tmd_cmd_t *, ct_entry_t *, uint32_t *, uint32_t);
static int tdma_mkfc(ispsoftc_t *, tmd_cmd_t *, ct2_entry_t *, uint32_t *, uint32_t);
static int tdma_mk(ispsoftc_t *, tmd_xfr_t *, ct_entry_t *, uint32_t *, uint32_t);
static int tdma_mkfc(ispsoftc_t *, tmd_xfr_t *, ct2_entry_t *, uint32_t *, uint32_t);
#define ALLOW_SYNTHETIC_CTIO 1
#ifndef ALLOW_SYNTHETIC_CTIO
@@ -1415,7 +1415,7 @@ static int tdma_mkfc(ispsoftc_t *, tmd_cmd_t *, ct2_entry_t *, uint32_t *, uint3
*/
static int
tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint32_t optr)
tdma_mk(ispsoftc_t *isp, tmd_xfr_t *xfr, ct_entry_t *cto, uint32_t *nxtip, uint32_t optr)
{
static const char ctx[] = "CTIO[%x] lun %d for iid%d flgs 0x%x sts 0x%x ssts 0x%x res %u %s";
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
@@ -1425,8 +1425,10 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
uint32_t curi, nxti, handle;
uint32_t sflags;
int32_t resid;
tmd_cmd_t *tmd;
int nth_ctio, nctios, send_status, nseg, new_seg_cnt;
tmd = xfr->td_cmd;
curi = isp->isp_reqidx;
qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx);
@@ -1435,7 +1437,7 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
cto->ct_header.rqs_entry_count = 1;
MEMZERO(cto->ct_dataseg, sizeof (cto->ct_dataseg));
if (tmd->cd_xfrlen == 0) {
if (xfr->td_xfrlen == 0) {
ISP_TDQE(isp, "tdma_mk[no data]", curi, cto);
isp_prt(isp, ISP_LOGTDEBUG1, ctx, cto->ct_fwhandle, L0LUN_TO_FLATLUN(tmd->cd_lun), (int) cto->ct_iid, cto->ct_flags, cto->ct_status,
cto->ct_scsi_status, cto->ct_resid, "<END>");
@@ -1443,28 +1445,28 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
return (CMD_QUEUED);
}
if (tmd->cd_xfrlen <= 1024) {
if (xfr->td_xfrlen <= 1024) {
nseg = 0;
} else if (tmd->cd_xfrlen <= 4096) {
} else if (xfr->td_xfrlen <= 4096) {
nseg = 1;
} else if (tmd->cd_xfrlen <= 32768) {
} else if (xfr->td_xfrlen <= 32768) {
nseg = 2;
} else if (tmd->cd_xfrlen <= 65536) {
} else if (xfr->td_xfrlen <= 65536) {
nseg = 3;
} else if (tmd->cd_xfrlen <= 131372) {
} else if (xfr->td_xfrlen <= 131372) {
nseg = 4;
} else if (tmd->cd_xfrlen <= 262144) {
} else if (xfr->td_xfrlen <= 262144) {
nseg = 5;
} else if (tmd->cd_xfrlen <= 524288) {
} else if (xfr->td_xfrlen <= 524288) {
nseg = 6;
} else {
nseg = 7;
}
isp->isp_osinfo.bins[nseg]++;
sg = tmd->cd_data;
sg = xfr->td_data;
nseg = 0;
resid = (int32_t) tmd->cd_xfrlen;
resid = (int32_t) xfr->td_xfrlen;
while (resid > 0) {
if (sg->length == 0) {
isp_prt(isp, ISP_LOGWARN, "%s: zero length segment #%d for tag %llx\n", __FUNCTION__, nseg, tmd->cd_tagval);
@@ -1475,7 +1477,7 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
resid -= sg->length;
sg++;
}
sg = tmd->cd_data;
sg = xfr->td_data;
new_seg_cnt = pci_map_sg(pcs->pci_dev, sg, nseg, (cto->ct_flags & CT_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
@@ -1551,7 +1553,7 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
if (ISP_A64 && IS_HIGH_ISP_ADDR(addr)) {
isp_prt(isp, ISP_LOGERR, "%s: 64 bit tgt mode not supported", __FUNCTION__);
cto->ct_resid = -EFAULT;
pci_unmap_sg(pcs->pci_dev, tmd->cd_data, nseg, (cto->ct_flags & CT_DATA_IN)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE);
pci_unmap_sg(pcs->pci_dev, xfr->td_data, nseg, (cto->ct_flags & CT_DATA_IN)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE);
return (CMD_COMPLETE);
}
/*
@@ -1660,7 +1662,7 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
}
}
*nxtip = nxti;
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, tmd->cd_data, cto->ct_syshandle);
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, xfr->td_data, cto->ct_syshandle);
return (CMD_QUEUED);
}
@@ -1691,19 +1693,21 @@ tdma_mk(ispsoftc_t *isp, tmd_cmd_t *tmd, ct_entry_t *cto, uint32_t *nxtip, uint3
* has been left unchanged.
*/
#ifndef ISP_DISABLE_2400_SUPPORT
static int tdma_mk_2400(ispsoftc_t *, tmd_cmd_t *, ct7_entry_t *, uint32_t *, uint32_t);
static int tdma_mk_2400(ispsoftc_t *, tmd_xfr_t *, ct7_entry_t *, uint32_t *, uint32_t);
static int
tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip, uint32_t optr)
tdma_mk_2400(ispsoftc_t *isp, tmd_xfr_t *xfr, ct7_entry_t *cto, uint32_t *nxtip, uint32_t optr)
{
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
static const char ctx[] = "CTIO7[%x] lun %d for nphdl %x flgs 0x%x ssts 0x%x res %d %s";
static const char ctx[] = "CTIO7[%llx] cdb0 0x%02x lun %u nphdl 0x%x flgs 0x%x ssts 0x%x xfr %u moved %u/%u resid %d %s";
XS_DMA_ADDR_T addr, last_synthetic_addr;
tmd_cmd_t *tmd = xfr->td_cmd;
struct scatterlist *sg;
void *qe;
uint32_t swd, curi, nxti;
uint16_t swd;
uint32_t curi, nxti;
uint32_t bc, last_synthetic_count;
long xfcnt; /* must be signed */
int nseg, seg, ovseg, seglim, new_seg_cnt;
int nseg, seg, ovseg, seglim, new_seg_cnt, level;
#ifdef ALLOW_SYNTHETIC_CTIO
ct7_entry_t *cto2 = NULL, ct2;
#endif
@@ -1712,49 +1716,43 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
curi = isp->isp_reqidx;
qe = ISP_QUEUE_ENTRY(isp->isp_rquest, curi);
if (cto->ct_resid || cto->ct_scsi_status) {
level = ISP_LOGTINFO;
} else {
level = ISP_LOGTDEBUG1;
}
isp_prt(isp, level, ctx, (unsigned long long) tmd->cd_tagval, tmd->cd_cdb[0], L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_nphdl, cto->ct_flags,
cto->ct_scsi_status, xfr->td_xfrlen, tmd->cd_moved, tmd->cd_totlen, cto->ct_resid, "<END>");
/*
* Handle commands that transfer no data right away.
*/
if (tmd->cd_xfrlen == 0) {
if (xfr->td_xfrlen == 0) {
cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_seqno = 1;
/* ct_syshandle contains the synchronization handle set by caller */
cto->ct_flags |= CT7_NO_DATA;
if (cto->ct_resid > 0) {
cto->ct_scsi_status |= CT2_DATA_UNDER; /* XXX : should be in isp_stds.h */
}
isp_prt(isp, ISP_LOGTDEBUG1, ctx, cto->ct_rxid, L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_nphdl, cto->ct_flags, cto->ct_scsi_status, cto->ct_resid, "<END>");
isp_put_ctio7(isp, cto, qe);
ISP_TDQE(isp, "tdma_mk_2400[no data]", curi, qe);
return (CMD_QUEUED);
}
if ((cto->ct_flags & CT7_FLAG_MMASK) != CT7_FLAG_MODE0) {
isp_prt(isp, ISP_LOGERR, "%s: a data CTIO7 without MODE0 set (0x%x)", __FUNCTION__, cto->ct_flags);
cto->ct_resid = -EINVAL;
return (CMD_COMPLETE);
}
if (tmd->cd_xfrlen <= 1024) {
if (xfr->td_xfrlen <= 1024) {
nseg = 0;
} else if (tmd->cd_xfrlen <= 4096) {
} else if (xfr->td_xfrlen <= 4096) {
nseg = 1;
} else if (tmd->cd_xfrlen <= 32768) {
} else if (xfr->td_xfrlen <= 32768) {
nseg = 2;
} else if (tmd->cd_xfrlen <= 65536) {
} else if (xfr->td_xfrlen <= 65536) {
nseg = 3;
} else if (tmd->cd_xfrlen <= 131372) {
} else if (xfr->td_xfrlen <= 131372) {
nseg = 4;
} else if (tmd->cd_xfrlen <= 262144) {
} else if (xfr->td_xfrlen <= 262144) {
nseg = 5;
} else if (tmd->cd_xfrlen <= 524288) {
} else if (xfr->td_xfrlen <= 524288) {
nseg = 6;
} else {
nseg = 7;
}
isp->isp_osinfo.bins[nseg]++;
/*
* First, count and map all S/G segments
*
@@ -1762,9 +1760,9 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
* we can have descriptors that are, in fact,
* longer than our data transfer count.
*/
sg = tmd->cd_data;
sg = xfr->td_data;
nseg = 0;
xfcnt = tmd->cd_xfrlen;
xfcnt = xfr->td_xfrlen;
while (xfcnt > 0) {
if (sg->length == 0) {
isp_prt(isp, ISP_LOGWARN, "%s: zero length segment #%d for tag %llx\n", __FUNCTION__, nseg, tmd->cd_tagval);
@@ -1775,7 +1773,7 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
xfcnt -= sg->length;
sg++;
}
sg = tmd->cd_data;
sg = xfr->td_data;
new_seg_cnt = pci_map_sg(pcs->pci_dev, sg, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
if (new_seg_cnt == 0) {
isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __FUNCTION__);
@@ -1784,12 +1782,21 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
}
tmd->cd_nseg = new_seg_cnt;
/*
* Check for sequential ordering of data frames
*/
if (tmd->cd_lastoff + tmd->cd_lastsize != xfr->td_offset) {
isp_prt(isp, ISP_LOGWARN, "%s: [0x%llx] lastoff %u lastsize %u but curoff %u (totlen %u)", __FUNCTION__, (unsigned long long) tmd->cd_tagval, tmd->cd_lastoff, tmd->cd_lastsize, xfr->td_offset, tmd->cd_totlen);
}
tmd->cd_lastsize = xfr->td_xfrlen;
tmd->cd_lastoff = xfr->td_offset;
/*
* Second, figure out whether we'll need to send a separate status CTIO.
*/
swd = cto->ct_scsi_status;
if ((cto->ct_flags & CT7_SENDSTATUS) && ((swd & 0xf) || cto->ct_resid)) {
if ((cto->ct_flags & CT7_SENDSTATUS) && ((swd & 0xff) || cto->ct_resid)) {
#ifdef ALLOW_SYNTHETIC_CTIO
cto2 = &ct2;
/*
@@ -1798,7 +1805,7 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
MEMCPY(cto2, cto, sizeof (ct7_entry_t));
/*
* Clear fields from first CTIO2 that now need to be cleared
* Clear fields from first CTIO7 that now need to be cleared
*/
cto->ct_flags &= ~CT7_SENDSTATUS;
cto->ct_resid = 0;
@@ -1806,17 +1813,23 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
cto->ct_scsi_status = 0;
/*
* Reset fields in the second CTIO2 as appropriate.
* Reset fields in the second CTIO7 as appropriate.
*/
cto2->ct_flags &= ~(CT7_FLAG_MMASK|CT7_DATAMASK);
cto2->ct_flags |= CT7_NO_DATA|CT7_NO_DATA|CT7_FLAG_MODE1;
cto2->ct_seg_count = 0;
MEMZERO(&cto2->rsp, sizeof (cto2->rsp));
cto2->ct_scsi_status = swd;
if ((swd & 0xf) == SCSI_CHECK && (tmd->cd_hflags & CDFH_SNSVALID)) {
if ((swd & 0xff) == SCSI_CHECK && (xfr->td_hflags & TDFH_SNSVALID)) {
swd |= CT2_SNSLEN_VALID;
cto2->rsp.m1.ct_resplen = min(TMD_SENSELEN, MAXRESPLEN_24XX);
MEMCPY(cto2->rsp.m1.ct_resp, tmd->cd_sense, cto2->rsp.m1.ct_resplen);
}
if (cto2->ct_resid > 0) {
swd |= CT2_DATA_UNDER;
} else if (cto2->ct_resid < 0) {
swd |= CT2_DATA_OVER;
}
cto2->ct_scsi_status = swd;
#else
cto->ct_flags &= ~CT7_SENDSTATUS;
cto->ct_resid = 0;
@@ -1828,16 +1841,12 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
* Third, fill in the data segments in the first CTIO2 itself.
* This is also a good place to set the relative offset.
*/
xfcnt = tmd->cd_xfrlen;
xfcnt = xfr->td_xfrlen;
/*
* cd_resid was already decremented by cd_xfrlen in isp_target_start_ctio
*
* We're taking the total amount for the command and backing it off for
* the amounts already known to have transferred. That should get us the
* relative offset to start at for this transfer.
*/
cto->rsp.m0.reloff = tmd->cd_totlen - (tmd->cd_resid + tmd->cd_xfrlen);
cto->rsp.m0.reloff = xfr->td_offset;
seglim = 1;
@@ -1891,7 +1900,7 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curip);
nxti = ISP_NXT_QENTRY((curip), RQUEST_QUEUE_LEN(isp));
if (nxti == optr) {
pci_unmap_sg(pcs->pci_dev, tmd->cd_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
pci_unmap_sg(pcs->pci_dev, xfr->td_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
isp_prt(isp, ISP_LOGTDEBUG0, "%s: out of space for continuations (%d of %d segs done)", __FUNCTION__, cto->ct_seg_count, nseg);
return (CMD_EAGAIN);
}
@@ -1955,7 +1964,7 @@ tdma_mk_2400(ispsoftc_t *isp, tmd_cmd_t *tmd, ct7_entry_t *cto, uint32_t *nxtip,
}
} while (seg < nseg || last_synthetic_count);
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, tmd->cd_data, cto->ct_syshandle);
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, xfr->td_data, cto->ct_syshandle);
mbxsync:
@@ -1969,7 +1978,7 @@ mbxsync:
curi = nxti;
nxti = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp));
if (nxti == optr) {
pci_unmap_sg(pcs->pci_dev, tmd->cd_data, nseg, (cto->ct_flags & CT7_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
pci_unmap_sg(pcs->pci_dev, xfr->td_data, nseg, (cto->ct_flags & CT7_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
isp_prt(isp, ISP_LOGTDEBUG0, "%s: request queue overflow", __FUNCTION__);
cto->ct_resid = -EAGAIN;
return (CMD_COMPLETE);
@@ -1991,14 +2000,16 @@ mbxsync:
#endif
static int
tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, uint32_t optr)
tdma_mkfc(ispsoftc_t *isp, tmd_xfr_t *xfr, ct2_entry_t *cto, uint32_t *nxtip, uint32_t optr)
{
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
static const char ctx[] = "CTIO2[%x] lun %d for iid %d flgs 0x%x sts 0x%x ssts 0x%x res %d %s";
XS_DMA_ADDR_T addr, last_synthetic_addr;
tmd_cmd_t *tmd = xfr->td_cmd;
struct scatterlist *sg;
void *qe;
uint32_t swd, curi, nxti;
uint16_t swd;
uint32_t curi, nxti;
uint32_t bc, last_synthetic_count;
long xfcnt; /* must be signed */
int nseg, seg, ovseg, seglim, new_seg_cnt;
@@ -2010,7 +2021,7 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
curi = isp->isp_reqidx;
qe = ISP_QUEUE_ENTRY(isp->isp_rquest, curi);
if (cto->ct_flags & CT2_FASTPOST) {
if ((tmd->cd_hflags & (CDFH_STSVALID|CDFH_SNSVALID)) != CDFH_STSVALID) {
if ((xfr->td_hflags & (TDFH_STSVALID|TDFH_SNSVALID)) != TDFH_STSVALID) {
cto->ct_flags &= ~CT2_FASTPOST;
}
}
@@ -2018,63 +2029,34 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
/*
* Handle commands that transfer no data right away.
*/
if (tmd->cd_xfrlen == 0) {
if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
isp_prt(isp, ISP_LOGERR, "%s: a status CTIO2 without MODE1 set (0x%x)", __FUNCTION__, cto->ct_flags);
cto->ct_resid = -EINVAL;
return (CMD_COMPLETE);
}
if (xfr->td_xfrlen == 0) {
cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_seqno = 1;
/* ct_syshandle contains the synchronization handle set by caller */
/*
* We preserve ct_lun, ct_iid, ct_rxid. We set the data movement
* flags to NO DATA and clear relative offset flags. We preserve
* ct_resid and the response area. We assume that if there is
* associated sense data that it has been appropriately set by
* the caller.
*/
cto->ct_flags |= CT2_NO_DATA;
if (cto->ct_resid > 0) {
cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
cto->ct_flags &= ~CT2_FASTPOST;
} else if (cto->ct_resid < 0) {
cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER;
cto->ct_flags &= ~CT2_FASTPOST;
}
cto->ct_seg_count = 0;
cto->ct_reloff = 0;
isp_prt(isp, ISP_LOGTDEBUG1, ctx, cto->ct_rxid, L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_iid, cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status,
cto->ct_resid, "<END>");
isp_prt(isp, ISP_LOGTDEBUG1, ctx, cto->ct_rxid, L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_iid, cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status, cto->ct_resid, "<END>");
isp_put_ctio2(isp, cto, qe);
if (cto->ct_flags & CT2_FASTPOST) {
isp_prt(isp, ISP_LOGTDEBUG1, "[%x] nodata (0x%x)", cto->ct_rxid,
tmd->cd_cdb[0]);
isp_prt(isp, ISP_LOGTDEBUG1, "[%x] faspost (0x%x)", cto->ct_rxid, tmd->cd_cdb[0]);
}
ISP_TDQE(isp, "tdma_mkfc[no data]", curi, qe);
return (CMD_QUEUED);
}
if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
isp_prt(isp, ISP_LOGERR, "%s: a data CTIO2 without MODE0 set (0x%x)", __FUNCTION__, cto->ct_flags);
cto->ct_resid = -EINVAL;
return (CMD_COMPLETE);
}
if (tmd->cd_xfrlen <= 1024) {
if (xfr->td_xfrlen <= 1024) {
nseg = 0;
} else if (tmd->cd_xfrlen <= 4096) {
} else if (xfr->td_xfrlen <= 4096) {
nseg = 1;
} else if (tmd->cd_xfrlen <= 32768) {
} else if (xfr->td_xfrlen <= 32768) {
nseg = 2;
} else if (tmd->cd_xfrlen <= 65536) {
} else if (xfr->td_xfrlen <= 65536) {
nseg = 3;
} else if (tmd->cd_xfrlen <= 131372) {
} else if (xfr->td_xfrlen <= 131372) {
nseg = 4;
} else if (tmd->cd_xfrlen <= 262144) {
} else if (xfr->td_xfrlen <= 262144) {
nseg = 5;
} else if (tmd->cd_xfrlen <= 524288) {
} else if (xfr->td_xfrlen <= 524288) {
nseg = 6;
} else {
nseg = 7;
@@ -2089,9 +2071,9 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
* we can have descriptors that are, in fact,
* longer than our data transfer count.
*/
sg = tmd->cd_data;
sg = xfr->td_data;
nseg = 0;
xfcnt = tmd->cd_xfrlen;
xfcnt = xfr->td_xfrlen;
while (xfcnt > 0) {
if (sg->length == 0) {
isp_prt(isp, ISP_LOGWARN, "%s: zero length segment #%d for tag %llx\n", __FUNCTION__, nseg, tmd->cd_tagval);
@@ -2102,7 +2084,7 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
xfcnt -= sg->length;
sg++;
}
sg = tmd->cd_data;
sg = xfr->td_data;
new_seg_cnt = pci_map_sg(pcs->pci_dev, sg, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
if (new_seg_cnt == 0) {
isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __FUNCTION__);
@@ -2116,7 +2098,7 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
*/
swd = cto->rsp.m0.ct_scsi_status;
if ((cto->ct_flags & CT2_SENDSTATUS) && ((swd & 0xf) || cto->ct_resid)) {
if ((cto->ct_flags & CT2_SENDSTATUS) && ((swd & 0xff) || cto->ct_resid)) {
#ifdef ALLOW_SYNTHETIC_CTIO
cto2 = &ct2;
/*
@@ -2140,12 +2122,17 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
cto2->ct_seg_count = 0;
cto2->ct_reloff = 0;
MEMZERO(&cto2->rsp, sizeof (cto2->rsp));
cto2->rsp.m1.ct_scsi_status = swd;
if ((swd & 0xf) == SCSI_CHECK && (swd & CT2_SNSLEN_VALID)) {
if ((swd & 0xff) == SCSI_CHECK && (swd & CT2_SNSLEN_VALID)) {
cto2->rsp.m1.ct_senselen = min(TMD_SENSELEN, MAXRESPLEN);
MEMCPY(cto2->rsp.m1.ct_resp, tmd->cd_sense, cto2->rsp.m1.ct_senselen);
cto2->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
swd |= CT2_SNSLEN_VALID;
}
if (cto2->ct_resid > 0) {
swd |= CT2_DATA_UNDER;
} else if (cto2->ct_resid < 0) {
swd |= CT2_DATA_OVER;
}
cto2->rsp.m1.ct_scsi_status = swd;
#else
cto->ct_flags &= ~(CT2_SENDSTATUS|CT2_CCINCR|CT2_FASTPOST);
cto->ct_resid = 0;
@@ -2157,16 +2144,8 @@ tdma_mkfc(ispsoftc_t *isp, tmd_cmd_t *tmd, ct2_entry_t *cto, uint32_t *nxtip, ui
* Third, fill in the data segments in the first CTIO2 itself.
* This is also a good place to set the relative offset.
*/
xfcnt = tmd->cd_xfrlen;
/*
* cd_resid was already decremented by cd_xfrlen in isp_target_start_ctio
*
* We're taking the total amount for the command and backing it off for
* the amounts already known to have transferred. That should get us the
* relative offset to start at for this transfer.
*/
cto->ct_reloff = tmd->cd_totlen - (tmd->cd_resid + tmd->cd_xfrlen);
xfcnt = xfr->td_xfrlen;
cto->ct_reloff = xfr->td_offset;
/*
* This is a good place to return to if we need to redo this with
@@ -2202,9 +2181,9 @@ again:
if (cto2) {
cto2->ct_header.rqs_entry_type = RQSTYPE_CTIO3;
}
xfcnt = tmd->cd_xfrlen;
xfcnt = xfr->td_xfrlen;
cto->rsp.m0.ct_xfrlen = 0;
sg = tmd->cd_data;
sg = xfr->td_data;
seglim = ISP_RQDSEG_T3;
isp_prt(isp, ISP_LOGTDEBUG2, "%s: found hi page", __FUNCTION__);
goto again;
@@ -2275,7 +2254,7 @@ again:
qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curip);
nxti = ISP_NXT_QENTRY((curip), RQUEST_QUEUE_LEN(isp));
if (nxti == optr) {
pci_unmap_sg(pcs->pci_dev, tmd->cd_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
pci_unmap_sg(pcs->pci_dev, xfr->td_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
isp_prt(isp, ISP_LOGTDEBUG0, "%s: out of space for continuations (%d of %d segs done)", __FUNCTION__, cto->ct_seg_count, nseg);
return (CMD_EAGAIN);
}
@@ -2346,13 +2325,13 @@ again:
if (ISP_A64 && IS_HIGH_ISP_ADDR(addr)) {
nxti = *nxtip;
cto->ct_header.rqs_entry_count = 1;
xfcnt = tmd->cd_xfrlen;
xfcnt = xfr->td_xfrlen;
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3;
if (cto2) {
cto2->ct_header.rqs_entry_type = RQSTYPE_CTIO3;
}
cto->rsp.m0.ct_xfrlen = 0;
sg = tmd->cd_data;
sg = xfr->td_data;
seglim = ISP_RQDSEG_T3;
isp_prt(isp, ISP_LOGTDEBUG1, "%s: found hi page in continuation, restarting", __FUNCTION__);
goto again;
@@ -2371,7 +2350,7 @@ again:
}
} while (seg < nseg || last_synthetic_count);
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, tmd->cd_data, cto->ct_syshandle);
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, xfr->td_data, cto->ct_syshandle);
mbxsync:
@@ -2385,7 +2364,7 @@ mbxsync:
curi = nxti;
nxti = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp));
if (nxti == optr) {
pci_unmap_sg(pcs->pci_dev, tmd->cd_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
pci_unmap_sg(pcs->pci_dev, xfr->td_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
isp_prt(isp, ISP_LOGTDEBUG0, "%s: request queue overflow", __FUNCTION__);
cto->ct_resid = -EAGAIN;
return (CMD_COMPLETE);
@@ -2421,9 +2400,9 @@ isp_pci_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, ispreq_t *rq, uint32_t *nxi,
rq->req_header.rqs_entry_type == RQSTYPE_CTIO3) {
int s;
if (IS_FC(isp)) {
s = tdma_mkfc(isp, (tmd_cmd_t *)Cmnd, (ct2_entry_t *)rq, nxi, optr);
s = tdma_mkfc(isp, (tmd_xfr_t *)Cmnd, (ct2_entry_t *)rq, nxi, optr);
} else {
s = tdma_mk(isp, (tmd_cmd_t *)Cmnd, (ct_entry_t *)rq, nxi, optr);
s = tdma_mk(isp, (tmd_xfr_t *)Cmnd, (ct_entry_t *)rq, nxi, optr);
}
return (s);
}
@@ -2751,7 +2730,7 @@ isp_pci_2400_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, ispreq_t *orig_rq, uint3
#ifdef ISP_TARGET_MODE
if (orig_rq->req_header.rqs_entry_type == RQSTYPE_CTIO7) {
return tdma_mk_2400(isp, (tmd_cmd_t *)Cmnd, (ct7_entry_t *)orig_rq, nxi, optr);
return tdma_mk_2400(isp, (tmd_xfr_t *)Cmnd, (ct7_entry_t *)orig_rq, nxi, optr);
}
#endif
rq = (ispreqt7_t *) orig_rq;
@@ -2943,11 +2922,12 @@ isp_pci_dmateardown(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, uint32_t handle)
* safest way to keep the two w/o redoing our internal apis.
*/
if (IS_TARGET_HANDLE(handle)) {
tmd_cmd_t *tmd = (tmd_cmd_t *) Cmnd;
tmd_xfr_t *xfr = (tmd_xfr_t *) Cmnd;
tmd_cmd_t *tmd = xfr? xfr->td_cmd : NULL;
int nseg = tmd? tmd->cd_nseg : 0;
if (nseg && tmd->cd_data) {
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: pci_unmap %d segments at %p for handle 0x%x", tmd->cd_tagval, nseg, tmd->cd_data, handle);
pci_unmap_sg(pcs->pci_dev, tmd->cd_data, nseg, (tmd->cd_hflags & CDFH_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
if (nseg && xfr->td_data) {
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: pci_unmap %d segments at %p for handle 0x%x", tmd->cd_tagval, nseg, xfr->td_data, handle);
pci_unmap_sg(pcs->pci_dev, xfr->td_data, nseg, (xfr->td_hflags & TDFH_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
}
} else
#endif
+81 -87
View File
@@ -117,6 +117,7 @@
/* usefull pointers when data is processed */
#define cd_scst_cmd cd_hreserved[0].ptrs[0]
#define cd_bus cd_hreserved[1].ptrs[0]
#define cd_hnext cd_hreserved[2].ptrs[0]
#ifndef SCSI_GOOD
#define SCSI_GOOD 0x0
@@ -386,9 +387,9 @@ static __inline void
scsi_cmd_sched_restart_locked(tmd_cmd_t *tmd, int donotify, const char *msg)
{
SDprintk("scsi_cmd_sched_restart[%llx]: %s\n", tmd->cd_tagval, msg);
tmd->cd_private = NULL;
tmd->cd_hnext = NULL;
if (p_front) {
p_last->cd_private = tmd;
p_last->cd_hnext = tmd;
} else {
p_front = tmd;
}
@@ -438,11 +439,11 @@ ca_xmit_response(bus_t *bp, tmd_cmd_t *tmd)
* with all state: status, data, sense. As long we not call scst_tgt_cmd_done()
* scst will keep all data and scst task mgmt functions will work
*/
tmd->cd_private = NULL;
tmd->cd_hnext = NULL;
if (!ini->ini_ca_front) {
ini->ini_ca_front = tmd;
} else {
ini->ini_ca_tail->cd_private = tmd;
ini->ini_ca_tail->cd_hnext = tmd;
}
ini->ini_ca_tail = tmd;
@@ -467,7 +468,7 @@ ca_xmit_response(bus_t *bp, tmd_cmd_t *tmd)
}
}
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return (0);
}
@@ -484,7 +485,7 @@ ca_finish(bus_t *bp, ini_t *ini)
spin_lock_irqsave(&ini->ini_ca_lock, flags);
while (ini->ini_ca_front && !ini->ini_ca_cond) {
tmd = ini->ini_ca_front;
ini->ini_ca_front = tmd->cd_private;
ini->ini_ca_front = tmd->cd_hnext;
spin_unlock_irqrestore(&ini->ini_ca_lock, flags);
ca_xmit_response(bp, tmd);
@@ -515,18 +516,18 @@ ca_abort_task(bus_t *bp, ini_t *ini, uint64_t tagval)
}
if (tmd->cd_tagval == tagval) {
ini->ini_ca_front = tmd->cd_private;
ini->ini_ca_front = tmd->cd_hnext;
goto out;
}
while (1) {
prev_tmd = tmd;
tmd = tmd->cd_private;
tmd = tmd->cd_hnext;
if (!tmd)
goto out;
if (tmd->cd_tagval == tagval) {
prev_tmd->cd_private = tmd->cd_private;
prev_tmd->cd_hnext = tmd->cd_hnext;
goto out;
}
}
@@ -551,8 +552,8 @@ ca_abort_all_tasks(bus_t *bp, ini_t *ini, uint16_t lun)
spin_lock_irqsave(&ini->ini_ca_lock, flags);
tmd = ini->ini_ca_front;
while (tmd && L0LUN_TO_FLATLUN(tmd->cd_lun) == lun) {
ini->ini_ca_front = tmd->cd_private;
tmd->cd_private = NULL;
ini->ini_ca_front = tmd->cd_hnext;
tmd->cd_hnext = NULL;
tmd = ini->ini_ca_front;
}
@@ -560,14 +561,14 @@ ca_abort_all_tasks(bus_t *bp, ini_t *ini, uint16_t lun)
goto out;
}
next_tmd = tmd->cd_private;
next_tmd = tmd->cd_hnext;
while (next_tmd) {
if (L0LUN_TO_FLATLUN(next_tmd->cd_lun) == lun) {
tmd->cd_private = next_tmd->cd_private;
next_tmd->cd_private = NULL;
tmd->cd_hnext = next_tmd->cd_hnext;
next_tmd->cd_hnext = NULL;
} else {
tmd = next_tmd;
next_tmd = tmd->cd_private;
next_tmd = tmd->cd_hnext;
}
}
@@ -583,13 +584,15 @@ out:
static int
ca_xmit_response(bus_t *bp, tmd_cmd_t *tmd)
{
if ((tmd->cd_hflags & CDFH_STSVALID) && (tmd->cd_scsi_status == SCSI_CHECK)) {
tmd->cd_xfrlen = 0;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_hflags |= CDFH_SNSVALID;
tmd_xfr_t *xfr = &tmd->cd_xfr;
if ((xfr->td_hflags & TDFH_STSVALID) && (tmd->cd_scsi_status == SCSI_CHECK)) {
xfr->td_xfrlen = 0;
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_hflags |= TDFH_SNSVALID;
}
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return (0);
}
@@ -635,9 +638,9 @@ scsi_target_rx_cmd(ini_t *ini, tmd_cmd_t *tmd, int from_intr)
}
dir = SCST_DATA_UNKNOWN; // bidirectional or no transfer
if ((tmd->cd_lflags & CDFL_DATA_OUT) && !(tmd->cd_lflags & CDFL_DATA_IN)) {
if ((tmd->cd_flags & CDF_DATA_OUT) && !(tmd->cd_flags & CDF_DATA_IN)) {
dir = SCST_DATA_WRITE;
} else if (tmd->cd_lflags & CDFL_DATA_IN) {
} else if (tmd->cd_flags & CDF_DATA_IN) {
dir = SCST_DATA_READ;
}
scst_cmd_set_expected(scst_cmd, dir, tmd->cd_totlen);
@@ -653,13 +656,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
bus_t *bp;
ini_t *ini;
int ret;
tmd->cd_hflags = 0;
tmd->cd_scsi_status = SCSI_GOOD;
tmd->cd_data = NULL;
tmd->cd_xfrlen = 0;
tmd->cd_resid = tmd->cd_totlen;
tmd->cd_private = NULL;
tmd_xfr_t *xfr = &tmd->cd_xfr;
/*
* First, find the bus.
@@ -734,7 +731,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
tmd->cd_hflags |= CDFH_STSVALID | CDFH_DATA_IN;
tmd->cd_scsi_status = SCSI_GOOD;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return;
} else {
/* we send bussy in CA, this not conform any version of scsi standard */
@@ -758,10 +755,10 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
err:
tmd->cd_scsi_status = SCSI_BUSY;
tmd->cd_hflags |= CDFH_STSVALID;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
xfr->td_hflags |= TDFH_STSVALID;
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return;
}
@@ -770,9 +767,10 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
{
bus_t *bp;
struct scst_cmd *scst_cmd;
tmd_xfr_t *xfr = &tmd->cd_xfr;
SDprintk2("scsi_target: TMD_DONE[%llx] %p hf %x lf %x xfrlen %d resid %d\n",
tmd->cd_tagval, tmd, tmd->cd_hflags, tmd->cd_lflags, tmd->cd_xfrlen, tmd->cd_resid);
SDprintk2("scsi_target: TMD_DONE[%llx] %p hf %x lf %x xfrlen %d\n",
tmd->cd_tagval, tmd, xfr->td_hflags, xfr->td_lflags, xfr->td_xfrlen);
bp = tmd->cd_bus;
@@ -781,7 +779,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
unsigned long flags;
ini_t *ini;
if (tmd->cd_lflags & CDFL_ERROR) {
if (xfr->td_lflags & TDFL_ERROR) {
Eprintk("Transport error when reponse REQUEST_SENSE command");
SDprintk("%s: TMD_FIN[%llx]\n", __FUNCTION__, tmd->cd_tagval);
(*bp->h.r_action)(QIN_TMD_FIN, tmd);
@@ -791,7 +789,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
/* sense was transfered, we may exit now from CA */
ini = ini_from_tmd(bp, tmd);
EXTRACHECKS_BUG_ON(!ini);
EXTRACHECKS_BUG_ON(tmd->cd_data != &ini->ini_sense_sg);
EXTRACHECKS_BUG_ON(xfr->td_data != &ini->ini_sense_sg);
SDprintk("%s: TMD_FIN[%llx]\n", __FUNCTION__, tmd->cd_tagval);
(*bp->h.r_action)(QIN_TMD_FIN, tmd);
@@ -811,33 +809,29 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
return;
}
if (tmd->cd_hflags & CDFH_STSVALID) {
if (tmd->cd_hflags & CDFH_DATA_IN) {
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_xfrlen = 0;
if (xfr->td_hflags & TDFH_STSVALID) {
if (xfr->td_hflags & TDFH_DATA_IN) {
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
}
scst_tgt_cmd_done(scst_cmd);
return;
}
if (tmd->cd_hflags & CDFH_DATA_OUT) {
if (tmd->cd_resid == 0) {
if (tmd->cd_xfrlen) {
int rx_status = SCST_RX_STATUS_SUCCESS;
if (tmd->cd_lflags & CDFL_ERROR) {
rx_status = SCST_RX_STATUS_ERROR;
}
scst_rx_data(scst_cmd, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_TASKLET);
} else {
scst_tgt_cmd_done(scst_cmd);
if (xfr->td_hflags & TDFH_DATA_OUT) {
if (xfr->td_xfrlen) {
int rx_status = SCST_RX_STATUS_SUCCESS;
if (xfr->td_error) {
rx_status = SCST_RX_STATUS_ERROR;
}
scst_rx_data(scst_cmd, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_TASKLET);
} else {
; /* we don't have all data, do nothing */
scst_tgt_cmd_done(scst_cmd);
}
} else if (tmd->cd_hflags & CDFH_DATA_IN) {
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_xfrlen = 0;
} else if (xfr->td_hflags & TDFH_DATA_IN) {
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
scst_tgt_cmd_done(scst_cmd);
}
}
@@ -988,14 +982,18 @@ scsi_target_handler(qact_e action, void *arg)
{
tmd_cmd_t *tmd = arg;
SDprintk2("scsi_target: TMD_START[%llx] %p cdb0=%x\n", tmd->cd_tagval, tmd, tmd->cd_cdb[0] & 0xff);
tmd->cd_xfr.td_cmd = tmd;
scsi_target_start_cmd(arg, 1);
break;
}
case QOUT_TMD_DONE:
{
tmd_cmd_t *tmd = arg;
tmd_xfr_t *xfr = arg;
tmd_cmd_t *tmd = xfr->td_cmd;
SDprintk2("scsi_target: TMD_DONE[%llx] %p cdb0=%x\n", tmd->cd_tagval, tmd, tmd->cd_cdb[0] & 0xff);
scsi_target_done_cmd(arg, 1);
scsi_target_done_cmd(tmd, 1);
break;
}
case QOUT_NOTIFY:
@@ -1068,8 +1066,8 @@ scsi_target_thread(void *arg)
}
spin_unlock_irqrestore(&scsi_target_lock, flags);
while (tp) {
tmd_cmd_t *nxt = tp->cd_private;
tp->cd_private = NULL;
tmd_cmd_t *nxt = tp->cd_hnext;
tp->cd_hnext = NULL;
scsi_target_start_cmd(tp, 0);
tp = nxt;
}
@@ -1148,19 +1146,19 @@ isp_release(struct scst_tgt *tgt)
static int
isp_rdy_to_xfer(struct scst_cmd *scst_cmd)
{
tmd_cmd_t *tmd;
bus_t *bp;
tmd = (tmd_cmd_t *) scst_cmd_get_tgt_priv(scst_cmd);
if (scst_cmd_get_data_direction(scst_cmd) == SCST_DATA_WRITE) {
tmd->cd_hflags |= CDFH_DATA_OUT;
tmd->cd_data = scst_cmd_get_sg(scst_cmd);
tmd->cd_xfrlen = scst_cmd_get_bufflen(scst_cmd);
tmd_cmd_t *tmd = (tmd_cmd_t *) scst_cmd_get_tgt_priv(scst_cmd);
tmd_xfr_t *xfr = &tmd->cd_xfr;
xfr->td_hflags |= TDFH_DATA_OUT;
xfr->td_data = scst_cmd_get_sg(scst_cmd);
xfr->td_xfrlen = scst_cmd_get_bufflen(scst_cmd);
SDprintk("%s: write nbytes %u\n", __FUNCTION__, scst_cmd_get_bufflen(scst_cmd));
bp = tmd->cd_bus;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
}
return (0);
@@ -1181,11 +1179,9 @@ SDprint_sense(const uint8_t *sbuf, uint8_t slen)
static int
isp_xmit_response(struct scst_cmd *scst_cmd)
{
tmd_cmd_t *tmd;
bus_t *bp;
tmd = (tmd_cmd_t *) scst_cmd_get_tgt_priv(scst_cmd);
bp = tmd->cd_bus;
tmd_cmd_t *tmd = (tmd_cmd_t *) scst_cmd_get_tgt_priv(scst_cmd);
bus_t *bp = tmd->cd_bus;
tmd_xfr_t *xfr = &tmd->cd_xfr;
if (scst_cmd_get_data_direction(scst_cmd) == SCST_DATA_READ) {
unsigned int len = scst_cmd_get_resp_data_len(scst_cmd);
@@ -1194,25 +1190,25 @@ isp_xmit_response(struct scst_cmd *scst_cmd)
const uint8_t ifailure[TMD_SENSELEN] = { 0xf0, 0, 0x4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x44 };
Eprintk("data size too big (totlen %u len %u)\n", tmd->cd_totlen, len);
WARN_ON(1);
dump_stack();
memcpy(tmd->cd_sense, ifailure, TMD_SENSELEN);
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
tmd->cd_scsi_status = SCSI_CHECK;
goto out;
} else {
tmd->cd_hflags |= CDFH_DATA_IN;
tmd->cd_xfrlen = len;
tmd->cd_data = scst_cmd_get_sg(scst_cmd);
xfr->td_hflags |= TDFH_DATA_IN;
xfr->td_xfrlen = len;
xfr->td_data = scst_cmd_get_sg(scst_cmd);
}
} else {
/* finished write to target or command with no data */
tmd->cd_xfrlen = 0;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
xfr->td_xfrlen = 0;
xfr->td_hflags &= ~TDFH_DATA_MASK;
}
if (scst_cmd_get_tgt_resp_flags(scst_cmd) & SCST_TSC_FLAG_STATUS) {
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
tmd->cd_scsi_status = scst_cmd_get_status(scst_cmd);
if (tmd->cd_scsi_status == SCSI_CHECK) {
@@ -1236,14 +1232,12 @@ out:
static void
isp_on_free_cmd(struct scst_cmd *scst_cmd)
{
tmd_cmd_t *tmd;
bus_t *bp;
tmd_cmd_t *tmd = (tmd_cmd_t *) scst_cmd_get_tgt_priv(scst_cmd);
bus_t *bp = tmd->cd_bus;
tmd_xfr_t *xfr = &tmd->cd_xfr;
tmd = (tmd_cmd_t *) scst_cmd_get_tgt_priv(scst_cmd);
tmd->cd_data = NULL;
xfr->td_data = NULL;
SDprintk("%s: TMD_FIN[%llx]\n", __FUNCTION__, tmd->cd_tagval);
bp = tmd->cd_bus;
(*bp->h.r_action)(QIN_TMD_FIN, tmd);
}
+174 -188
View File
@@ -1,4 +1,4 @@
/* $Id: scsi_target.c,v 1.67 2007/08/27 07:25:52 mjacob Exp $ */
/* $Id: scsi_target.c,v 1.71 2007/10/31 05:28:28 mjacob Exp $ */
/*
* Copyright (c) 1997-2007 by Matthew Jacob
* All rights reserved.
@@ -56,21 +56,11 @@
* SCSI Target Mode "toy disk" target device for Linux.
*/
#ifdef MODULE
#define EXPORT_SYMTAB
#else
#error "this can only be built as a module"
#endif
#include <linux/version.h>
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
#endif
#include <linux/autoconf.h>
#ifdef CONFIG_SMP
#define __SMP__ 1
#endif
#include <linux/module.h>
#include <linux/autoconf.h>
#include <linux/init.h>
@@ -113,11 +103,12 @@
#define cd_dp cd_hreserved[0].ptrs[0]
#define cd_nsgelems cd_hreserved[1].longs[0]
#define cd_off cd_hreserved[2].llongs[0]
#define cd_next cd_hreserved[3].ptrs[0]
#define CDFH_PRIVATE_0 0x8000000 /* small (non page) data allocation */
#define CDFH_PRIVATE_1 0x4000000 /* page allocation attached */
#define CDFH_PRIVATE_2 0x2000000 /* sent status already */
#define CDFH_PRIVATE_3 0x1000000 /* sg list from sg element cache */
#define CDF_PRIVATE_0 0x8000 /* small (non page) data allocation */
#define CDF_PRIVATE_1 0x4000 /* page allocation attached */
#define CDF_PRIVATE_2 0x2000 /* sent status already */
#define CDF_PRIVATE_3 0x1000 /* sg list from sg element cache */
#ifndef SCSI_GOOD
#define SCSI_GOOD 0x0
#endif
@@ -627,9 +618,9 @@ static __inline void
scsi_cmd_sched_restart_locked(tmd_cmd_t *tmd, int donotify, const char *msg)
{
SDprintk("scsi_cmd_sched_restart[%llx]: %s\n", tmd->cd_tagval, msg);
tmd->cd_private = NULL;
tmd->cd_next = NULL;
if (p_front) {
p_last->cd_private = tmd;
p_last->cd_next = tmd;
} else {
p_front = tmd;
}
@@ -653,19 +644,11 @@ static void
scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
{
unsigned long flags;
tmd_xfr_t *xfr = &tmd->cd_xfr;
bus_t *bp;
void *addr;
ini_t *ini;
tmd->cd_hflags = 0;
tmd->cd_scsi_status = SCSI_GOOD;
tmd->cd_data = NULL;
tmd->cd_xfrlen = 0;
tmd->cd_resid = tmd->cd_totlen;
tmd->cd_dp = 0;
tmd->cd_nsgelems = 0;
tmd->cd_off = 0;
/*
* First, find the bus.
*/
@@ -715,12 +698,11 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
} else {
if (nptr == NULL) {
spin_unlock_irqrestore(&scsi_target_lock, flags);
tmd->cd_xfrlen = 0;
tmd->cd_scsi_status = SCSI_BUSY;
tmd->cd_hflags |= CDFH_STSVALID;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
xfr->td_hflags |= TDFH_STSVALID;
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return;
}
add_ini(bp, tmd->cd_iid, nptr);
@@ -766,10 +748,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
return;
}
if (tmd->cd_totlen == 0) {
tmd->cd_totlen = tmd->cd_cdb[4];
}
if (tmd->cd_totlen == 0) {
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
goto doit;
}
len = min(tmd->cd_totlen, tmd->cd_cdb[4]);
@@ -778,7 +757,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
if (addr == NULL) {
printk(KERN_WARNING "scsi_target_alloc: out of memory for inquiry data\n");
add_sdata(ini, enomem);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
goto doit;
}
buf = addr;
@@ -796,7 +775,8 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
len = min(sizeof(vp80data), len);
if (len) {
memcpy(addr, vp80data, len);
snprintf(&buf[4], sizeof (vp80data) - 4, "FERAL0LUN%06dSER%s", L0LUN_TO_FLATLUN(tmd->cd_lun), SERNO);
snprintf(&buf[4], sizeof (vp80data) - 4, "FERAL_%s%d_LUN%06dSER%s", bp->h.r_name, bp->h.r_inst,
L0LUN_TO_FLATLUN(tmd->cd_lun), SERNO);
for (j = 0, i = 4; i < sizeof (vp80data); i++) {
if (j == 0) {
if (buf[i] == 0) {
@@ -821,7 +801,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
default:
scsi_target_kfree(addr, SGS_SIZE);
add_sdata(ini, invfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
goto doit;
}
} else {
@@ -832,12 +812,13 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
}
if (len == 0) {
scsi_target_kfree(addr, SGS_SIZE);
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
} else {
init_sg_elem(dp, NULL, 0, addr, len);
tmd->cd_xfrlen = dp->length;
tmd->cd_data = dp;
tmd->cd_hflags |= CDFH_DATA_IN|CDFH_STSVALID|CDFH_PRIVATE_0;
xfr->td_xfrlen = dp->length;
xfr->td_data = dp;
xfr->td_hflags |= TDFH_STSVALID|TDFH_DATA_IN;
tmd->cd_flags |= CDF_PRIVATE_0;
/*
* If we're not here, say we aren't here.
*/
@@ -849,14 +830,17 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
} else {
SDprintk2("scsi_target(%s%d): illegal field for inquiry data\n", bp->h.r_name, bp->h.r_inst);
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
}
goto doit;
}
if (tmd->cd_cdb[0] == REQUEST_SENSE) {
struct scatterlist *dp = NULL;
if (tmd->cd_totlen != 0) {
xfr->td_xfrlen = TMD_SENSELEN;
xfr->td_xfrlen = min(tmd->cd_cdb[4], xfr->td_xfrlen);
xfr->td_xfrlen = min(tmd->cd_totlen, xfr->td_xfrlen);
if (xfr->td_xfrlen != 0) {
if (from_intr) {
scsi_cmd_sched_restart(tmd, "REQUEST_SENSE");
return;
@@ -864,24 +848,26 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
addr = scsi_target_kzalloc(SGS_SIZE, GFP_KERNEL|GFP_ATOMIC);
if (addr == NULL) {
printk("scsi_target_alloc: out of memory for sense data\n");
add_sdata(ini, ifailure);
tmd->cd_hflags |= CDFH_SNSVALID;
tmd->cd_scsi_status = SCSI_BUSY;
xfr->td_xfrlen = 0;
} else {
dp = SGS_SGP(addr);
init_sg_elem(dp, NULL, 0, addr, min(TMD_SENSELEN, tmd->cd_totlen));
init_sg_elem(dp, NULL, 0, addr, TMD_SENSELEN);
if (ini->ini_sdata == NULL) {
add_sdata(ini, nosense);
memcpy(addr, nosense, TMD_SENSELEN);
} else {
memcpy(addr, ini->ini_sdata->sdata, TMD_SENSELEN);
rem_sdata(ini);
}
tmd->cd_xfrlen = dp->length;
memcpy(addr, ini->ini_sdata->sdata, TMD_SENSELEN);
tmd->cd_data = dp;
tmd->cd_hflags |= CDFH_DATA_IN|CDFH_PRIVATE_0;
xfr->td_data = dp;
xfr->td_hflags |= TDFH_DATA_IN;
tmd->cd_flags |= CDF_PRIVATE_0;
SDprintk2("sense data in scsi_target for %s%d: %p (%p) len %d, key/asc/ascq 0x%x/0x%x/0x%x\n",
bp->h.r_name, bp->h.r_inst, addr, dp, dp->length,
((u8 *)addr)[2]&0xf, ((u8 *)addr)[12]&0xff, ((u8 *)addr)[13]);
}
}
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
goto doit;
}
@@ -894,7 +880,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
return;
}
add_sdata(ini, nolun);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
goto doit;
}
@@ -902,7 +888,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
* All other commands first check for Contingent Allegiance
*/
if (ini->ini_sdata) {
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
goto doit;
}
@@ -913,7 +899,7 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
case SYNCHRONIZE_CACHE:
case START_STOP:
case TEST_UNIT_READY:
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
break;
case READ_CAPACITY:
if (from_intr) {
@@ -957,14 +943,14 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
return;
}
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
break;
}
doit:
if (tmd->cd_hflags & CDFH_SNSVALID) {
if (xfr->td_hflags & TDFH_SNSVALID) {
tmd->cd_scsi_status = SCSI_CHECK;
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
if (ini && ini->ini_sdata) {
memcpy(tmd->cd_sense, ini->ini_sdata->sdata, TMD_SENSELEN);
} else {
@@ -974,9 +960,9 @@ doit:
tmd->cd_tagval, tmd->cd_cdb[0] & 0xff, tmd->cd_totlen, tmd->cd_sense[2] & 0xf, tmd->cd_sense[12], tmd->cd_sense[13]);
} else {
SDprintk("INI(%#llx)=>LUN %d: [%llx] cdb0=0x%02x tl=%u ssts=%x hf 0x%x\n", tmd->cd_iid, L0LUN_TO_FLATLUN(tmd->cd_lun),
tmd->cd_tagval, tmd->cd_cdb[0] & 0xff, tmd->cd_totlen, tmd->cd_scsi_status, tmd->cd_hflags);
tmd->cd_tagval, tmd->cd_cdb[0] & 0xff, tmd->cd_totlen, tmd->cd_scsi_status, xfr->td_hflags);
}
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
}
static void
@@ -985,6 +971,7 @@ scsi_target_read_capacity_16(tmd_cmd_t *tmd, ini_t *ini)
bus_t *bp;
void *addr;
struct scatterlist *dp;
tmd_xfr_t *xfr = &tmd->cd_xfr;
lun_t *lp;
bp = ini->ini_bus;
@@ -993,7 +980,7 @@ scsi_target_read_capacity_16(tmd_cmd_t *tmd, ini_t *ini)
if (addr == NULL) {
printk(KERN_WARNING "scsi_target_read_capacity: alloc failed\n");
tmd->cd_scsi_status = SCSI_BUSY;
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
return;
}
@@ -1015,7 +1002,7 @@ scsi_target_read_capacity_16(tmd_cmd_t *tmd, ini_t *ini)
tmd->cd_cdb[6] || tmd->cd_cdb[7] || tmd->cd_cdb[8] || tmd->cd_cdb[9]) {
scsi_target_kfree(addr, SGS_SIZE);
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
return;
}
((u8 *)addr)[0] = (blks >> 56) & 0xff;
@@ -1032,9 +1019,10 @@ scsi_target_read_capacity_16(tmd_cmd_t *tmd, ini_t *ini)
((u8 *)addr)[10] = ((1 << LUN_BLOCK_SHIFT) >> 8) & 0xff;
((u8 *)addr)[11] = ((1 << LUN_BLOCK_SHIFT)) & 0xff;
init_sg_elem(dp, NULL, 0, addr, min(32, tmd->cd_totlen));
tmd->cd_xfrlen = dp->length;
tmd->cd_data = dp;
tmd->cd_hflags |= CDFH_DATA_IN|CDFH_PRIVATE_0|CDFH_STSVALID;
xfr->td_xfrlen = dp->length;
xfr->td_data = dp;
xfr->td_hflags |= TDFH_DATA_IN|TDFH_STSVALID;
tmd->cd_flags |= CDF_PRIVATE_0;
}
static void
@@ -1043,6 +1031,7 @@ scsi_target_read_capacity(tmd_cmd_t *tmd, ini_t *ini)
bus_t *bp;
void *addr;
struct scatterlist *dp;
tmd_xfr_t *xfr = &tmd->cd_xfr;
lun_t *lp;
bp = ini->ini_bus;
@@ -1051,7 +1040,7 @@ scsi_target_read_capacity(tmd_cmd_t *tmd, ini_t *ini)
if (addr == NULL) {
printk(KERN_WARNING "scsi_target_read_capacity: alloc failed\n");
tmd->cd_scsi_status = SCSI_BUSY;
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
return;
}
@@ -1068,7 +1057,7 @@ scsi_target_read_capacity(tmd_cmd_t *tmd, ini_t *ini)
if (tmd->cd_cdb[2] || tmd->cd_cdb[3] || tmd->cd_cdb[4] || tmd->cd_cdb[5]) {
scsi_target_kfree(addr, SGS_SIZE);
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
return;
}
if (blks < 0xffffffffull) {
@@ -1088,9 +1077,10 @@ scsi_target_read_capacity(tmd_cmd_t *tmd, ini_t *ini)
((u8 *)addr)[6] = ((1 << LUN_BLOCK_SHIFT) >> 8) & 0xff;
((u8 *)addr)[7] = ((1 << LUN_BLOCK_SHIFT)) & 0xff;
init_sg_elem(dp, NULL, 0, addr, min(8, tmd->cd_totlen));
tmd->cd_xfrlen = dp->length;
tmd->cd_data = dp;
tmd->cd_hflags |= CDFH_DATA_IN|CDFH_PRIVATE_0|CDFH_STSVALID;
xfr->td_xfrlen = dp->length;
xfr->td_data = dp;
xfr->td_hflags |= TDFH_DATA_IN|TDFH_STSVALID;
tmd->cd_flags |= CDF_PRIVATE_0;
}
static void
@@ -1099,6 +1089,7 @@ scsi_target_modesense(tmd_cmd_t *tmd, ini_t *ini)
bus_t *bp;
lun_t *lp;
int dlen, pgctl, page;
tmd_xfr_t *xfr = &tmd->cd_xfr;
struct scatterlist *dp;
uint8_t *pgdata;
uint32_t nblks;
@@ -1121,7 +1112,7 @@ scsi_target_modesense(tmd_cmd_t *tmd, ini_t *ini)
break;
default:
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
return;
}
@@ -1129,7 +1120,7 @@ scsi_target_modesense(tmd_cmd_t *tmd, ini_t *ini)
if (addr == NULL) {
printk(KERN_WARNING "scsi_target_modesense: alloc failure\n");
tmd->cd_scsi_status = SCSI_BUSY;
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
return;
}
dp = SGS_SGP(addr);
@@ -1256,9 +1247,10 @@ scsi_target_modesense(tmd_cmd_t *tmd, ini_t *ini)
dlen = min(tmd->cd_cdb[4], tmd->cd_totlen);
dlen = min(dlen, SGS_PAYLOAD_SIZE);
init_sg_elem(dp, NULL, 0, addr, dlen);
tmd->cd_xfrlen = dp->length;
tmd->cd_data = dp;
tmd->cd_hflags |= CDFH_DATA_IN|CDFH_PRIVATE_0|CDFH_STSVALID;
xfr->td_xfrlen = dp->length;
xfr->td_data = dp;
xfr->td_hflags |= TDFH_DATA_IN|TDFH_STSVALID;
tmd->cd_flags |= CDF_PRIVATE_0;
}
static int
@@ -1270,6 +1262,7 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
uint64_t lba, devoff;
uint32_t transfer_count, byte_count, count, first_offset;
struct scatterlist *dp;
tmd_xfr_t *xfr = &tmd->cd_xfr;
int iswrite, page_idx, list_idx, sgidx;
unsigned long flags;
@@ -1341,7 +1334,7 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
return (-1);
}
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
return (0);
}
@@ -1353,13 +1346,13 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
printk(KERN_WARNING "scsi_target: overflow devoff (0x%llx) + count (0x%llx) > limit (0x%llx)\n", (unsigned long long) devoff,
(unsigned long long)(((uint64_t)transfer_count) << LUN_BLOCK_SHIFT), (unsigned long long) lp->nbytes);
add_sdata(ini, illfld);
tmd->cd_hflags |= CDFH_SNSVALID;
xfr->td_hflags |= TDFH_SNSVALID;
return (0);
}
if (unlikely(transfer_count == 0)) {
printk(KERN_WARNING "%s: zero length transfer count\n", __FUNCTION__);
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
return (0);
}
@@ -1371,7 +1364,8 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
byte_count = tmd->cd_totlen;
byte_count &= ~((1 << LUN_BLOCK_SHIFT) - 1);
if (byte_count == 0) {
tmd->cd_hflags |= CDFH_STSVALID;
printk(KERN_WARNING "%s: byte count less than a block\n", __FUNCTION__);
xfr->td_hflags |= TDFH_STSVALID;
return (0);
}
transfer_count = byte_count >> LUN_BLOCK_SHIFT;
@@ -1399,20 +1393,23 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
if (dp) {
sg_cache = (struct scatterlist *) dp->page;
dp->page = NULL;
tmd->cd_hflags |= CDFH_PRIVATE_3;
tmd->cd_flags |= CDF_PRIVATE_3;
}
spin_unlock_irqrestore(&scsi_target_lock, flags);
}
if (unlikely(dp == NULL)) {
if (from_intr) {
scsi_cmd_sched_restart(tmd, "no scatterlist");
if (tmd->cd_nsgelems < SGELEM_CACHE_SIZE)
scsi_cmd_sched_restart(tmd, "scatterlist restart: none available");
else
scsi_cmd_sched_restart(tmd, "scatterlist restart: large_xfr");
return (-1);
}
dp = scsi_target_kzalloc(tmd->cd_nsgelems * sizeof (struct scatterlist), GFP_KERNEL|GFP_ATOMIC);
if (dp == NULL) {
printk(KERN_WARNING "unable to allocate %d entry scatterlist\n", tmd->cd_nsgelems);
tmd->cd_scsi_status = SCSI_BUSY;
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
return (0);
}
}
@@ -1436,11 +1433,11 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
NextPage(pp) = (NextPageType) lp->pagelists;
lp->pagelists = (struct page ***) pp;
}
if (tmd->cd_hflags & CDFH_PRIVATE_3) {
if (tmd->cd_flags & CDF_PRIVATE_3) {
dp->page = (struct page *) sg_cache;
sg_cache = (struct scatterlist *) dp;
spin_unlock_irqrestore(&scsi_target_lock, flags);
tmd->cd_hflags ^= CDFH_PRIVATE_3;
tmd->cd_flags ^= CDF_PRIVATE_3;
} else {
spin_unlock_irqrestore(&scsi_target_lock, flags);
scsi_target_kfree(dp, tmd->cd_nsgelems * sizeof (struct scatterlist));
@@ -1488,11 +1485,12 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
page_idx = 0;
if (++list_idx >= lp->npglists) {
printk(KERN_WARNING "bad list_idx for block %lld\n", lba);
tmd->cd_data = dp;
xfr->td_data = dp;
tmd->cd_dp = dp;
tmd->cd_xfrlen = 0;
xfr->td_xfrlen = 0;
add_sdata(ini, ifailure);
tmd->cd_hflags |= CDFH_PRIVATE_1|CDFH_SNSVALID|CDFH_STSVALID;
xfr->td_hflags |= TDFH_SNSVALID|TDFH_STSVALID;
tmd->cd_flags |= CDF_PRIVATE_1;
return (0);
}
pglist = lp->pagelists[list_idx];
@@ -1501,28 +1499,28 @@ scsi_target_rdwr(tmd_cmd_t *tmd, ini_t *ini, int from_intr)
}
out:
tmd->cd_xfrlen = byte_count;
tmd->cd_data = dp;
xfr->td_xfrlen = byte_count;
xfr->td_data = dp;
tmd->cd_dp = dp;
tmd->cd_hflags |= CDFH_PRIVATE_1;
tmd->cd_flags |= CDF_PRIVATE_1;
if (iswrite) {
tmd->cd_hflags |= CDFH_DATA_OUT;
xfr->td_hflags |= TDFH_DATA_OUT;
/*
* WCE is set, or we're *not* an overcommit disk,
* the command is done as soon as data lands
* in memory.
*/
if (/* lp->wce || */ lp->overcommit == 0) {
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
}
} else {
tmd->cd_hflags |= CDFH_DATA_IN;
xfr->td_hflags |= TDFH_DATA_IN;
/*
* If we're an overcommit disk, then we don't do
* anything with this command yet- we put it on
* a queue for a user agent to fill. The amount
* to fill by the user agent is known by the
* tmd->cd_xfrlen.
* tmd->cd_totlen;
*
* When the user agent is done, the command is
* then released back to move the fetched data
@@ -1530,9 +1528,9 @@ out:
*/
if (lp->overcommit) {
spin_lock_irqsave(&scsi_target_lock, flags);
tmd->cd_private = NULL;
tmd->cd_next = NULL;
if (lp->u_front) {
lp->u_tail->cd_private = tmd;
lp->u_tail->cd_next = tmd;
} else {
lp->u_front = tmd;
}
@@ -1541,33 +1539,34 @@ out:
spin_unlock_irqrestore(&scsi_target_lock, flags);
return (1);
} else {
tmd->cd_hflags |= CDFH_STSVALID;
xfr->td_hflags |= TDFH_STSVALID;
}
}
return (0);
}
static int
scsi_target_ldfree(bus_t *bp, tmd_cmd_t *tmd, int from_intr)
scsi_target_ldfree(bus_t *bp, tmd_xfr_t *xfr, int from_intr)
{
int i;
unsigned long flags;
tmd_cmd_t *tmd = xfr->td_cmd;
if (tmd->cd_hflags & CDFH_PRIVATE_0) {
struct scatterlist *dp = tmd->cd_data;
if (tmd->cd_flags & CDF_PRIVATE_0) {
struct scatterlist *dp = xfr->td_data;
if (from_intr) {
goto resched;
}
SDprintk("scsi_target: LDFREE[%llx] %p tmd->cd_data %p\n", tmd->cd_tagval, tmd, dp);
SDprintk("scsi_target: LDFREE[%llx] %p xfr->td_data %p\n", tmd->cd_tagval, tmd, dp);
if (dp) {
scsi_target_kfree(page_address(dp->page) + dp->offset, SGS_SIZE);
} else {
printk(KERN_ERR "scsi_target: LDFREE[%llx] null dp @ line %d\n", tmd->cd_tagval, __LINE__);
return (0);
}
tmd->cd_data = NULL;
tmd->cd_hflags &= ~CDFH_PRIVATE_0;
} else if (tmd->cd_hflags & CDFH_PRIVATE_1) {
xfr->td_data = NULL;
tmd->cd_flags &= ~CDF_PRIVATE_0;
} else if (tmd->cd_flags & CDF_PRIVATE_1) {
struct scatterlist *dp = tmd->cd_dp;
lun_t *lp = &bp->luns[L0LUN_TO_FLATLUN(tmd->cd_lun)];
@@ -1576,7 +1575,7 @@ scsi_target_ldfree(bus_t *bp, tmd_cmd_t *tmd, int from_intr)
return (0);
}
if ((tmd->cd_hflags & CDFH_PRIVATE_3) == 0 && from_intr) {
if ((tmd->cd_flags & CDF_PRIVATE_3) == 0 && from_intr) {
goto resched;
}
spin_lock_irqsave(&scsi_target_lock, flags);
@@ -1599,25 +1598,25 @@ scsi_target_ldfree(bus_t *bp, tmd_cmd_t *tmd, int from_intr)
} else {
SDprintk("scsi_target: LDFREE[%llx] %s freeing nsgelems %d\n", tmd->cd_tagval, from_intr? "intr" : "task", tmd->cd_nsgelems);
}
if (tmd->cd_hflags & CDFH_PRIVATE_3) {
if (tmd->cd_flags & CDF_PRIVATE_3) {
memset(dp, 0, tmd->cd_nsgelems * sizeof (struct scatterlist));
dp->page = (struct page *) sg_cache;
sg_cache = dp;
spin_unlock_irqrestore(&scsi_target_lock, flags);
tmd->cd_hflags &= ~CDFH_PRIVATE_3;
tmd->cd_flags &= ~CDF_PRIVATE_3;
} else {
spin_unlock_irqrestore(&scsi_target_lock, flags);
scsi_target_kfree(dp, tmd->cd_nsgelems * sizeof (struct scatterlist));
}
tmd->cd_data = NULL;
tmd->cd_hflags &= ~CDFH_PRIVATE_1;
xfr->td_data = NULL;
tmd->cd_flags &= ~CDF_PRIVATE_1;
}
return (1);
resched:
tmd->cd_private = NULL;
tmd->cd_next = NULL;
spin_lock_irqsave(&scsi_target_lock, flags);
if (q_front) {
q_last->cd_private = tmd;
q_last->cd_next = tmd;
} else {
q_front = tmd;
}
@@ -1680,13 +1679,17 @@ scsi_target_handler(qact_e action, void *arg)
case QOUT_TMD_START:
{
tmd_cmd_t *tmd = arg;
SDprintk2("scsi_target: TMD_START[%llx] %p cdb0=%x\n", tmd->cd_tagval, tmd, tmd->cd_cdb[0] & 0xff);
scsi_target_start_cmd(arg, 1);
tmd->cd_xfr.td_cmd = tmd;
scsi_target_start_cmd(tmd, 1);
break;
}
case QOUT_TMD_DONE:
{
tmd_cmd_t *tmd = arg;
tmd_xfr_t *xfr = arg;
tmd_cmd_t *tmd = xfr->td_cmd;
ini_t *nptr;
bp = bus_from_tmd(tmd);
@@ -1695,31 +1698,31 @@ scsi_target_handler(qact_e action, void *arg)
break;
}
SDprintk2("scsi_target: TMD_DONE[%llx] %p hf %x lf %x\n", tmd->cd_tagval, tmd, tmd->cd_hflags, tmd->cd_lflags);
SDprintk2("scsi_target: TMD_DONE[%llx] %p hf %x lf %x\n", tmd->cd_tagval, tmd, xfr->td_hflags, xfr->td_lflags);
/*
* Okay- were we moving data? If so, deal with the result.
*
* If so, check to see if we sent it.
*/
if (tmd->cd_hflags & CDFH_DATA_OUT) {
if (xfr->td_hflags & TDFH_DATA_OUT) {
lun_t *lp;
SDprintk("scsi_target: [%llx] data receive done resid now %d\n", tmd->cd_tagval, tmd->cd_resid);
SDprintk("scsi_target: [%llx] data receive done\n", tmd->cd_tagval);
spin_lock_irqsave(&scsi_target_lock, flags);
lp = &bp->luns[L0LUN_TO_FLATLUN(tmd->cd_lun)];
/*
* If we're an overcommit disk we don't complete the command here.
*
* Instead, we give the data to a user agent. It knows how much
* to write based upon tmd->cd_xfrlen.
* to write based upon tmd->cd_totlen.
*
* When the user agent is done, it will clear the cd_xfrlen field and the
* CDFH_DATA_OUT flags and send back status for the command.
* TDFH_DATA_OUT flags and send back status for the command.
*/
if (lp->enabled && lp->overcommit) {
tmd->cd_private = NULL;
tmd->cd_next = NULL;
if (lp->u_front) {
lp->u_tail->cd_private = tmd;
lp->u_tail->cd_next = tmd;
} else {
lp->u_front = tmd;
}
@@ -1729,27 +1732,24 @@ scsi_target_handler(qact_e action, void *arg)
break;
}
spin_unlock_irqrestore(&scsi_target_lock, flags);
} else if (tmd->cd_hflags & CDFH_DATA_IN) {
SDprintk("scsi_target: [%llx] data transmit done resid %d\n", tmd->cd_tagval, tmd->cd_resid);
} else if (xfr->td_hflags & TDFH_DATA_IN) {
SDprintk("scsi_target: [%llx] data transmit done\n", tmd->cd_tagval);
}
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_xfrlen = 0;
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
spin_lock_irqsave(&scsi_target_lock, flags);
nptr = ini_from_tmd(bp, tmd);
spin_unlock_irqrestore(&scsi_target_lock, flags);
/*
* Did we send status already?
*/
if (tmd->cd_hflags & CDFH_STSVALID) {
if ((tmd->cd_lflags & CDFL_SENTSTATUS) == 0) {
if (tmd->cd_hflags & CDFH_PRIVATE_2) {
if (xfr->td_hflags & TDFH_STSVALID) {
if ((xfr->td_lflags & TDFL_SENTSTATUS) == 0) {
if (tmd->cd_flags & CDF_PRIVATE_2) {
printk(KERN_ERR "[%llx] already tried to send status\n", tmd->cd_tagval);
} else {
tmd->cd_hflags |= CDFH_PRIVATE_2;
tmd->cd_flags |= CDF_PRIVATE_2;
SDprintk("[%llx] sending status\n", tmd->cd_tagval);
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
break;
}
}
@@ -1758,27 +1758,20 @@ scsi_target_handler(qact_e action, void *arg)
/*
* Did we send sense? If so, remove one sense structure.
*/
if (tmd->cd_hflags & CDFH_SNSVALID) {
if (tmd->cd_lflags & CDFL_SENTSENSE) {
if (xfr->td_hflags & TDFH_SNSVALID) {
if (xfr->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);
}
}
}
/*
* Was this a REQUEST SENSE command? If so,
* remove any sense data for this initiator
* which we might have sent.
*/
if (tmd->cd_cdb[0] == REQUEST_SENSE) {
if (nptr) {
rem_sdata(nptr);
}
}
if (scsi_target_ldfree(bp, tmd, 1)) {
if (scsi_target_ldfree(bp, xfr, 1)) {
SDprintk("%s: TMD_FIN[%llx]\n", __FUNCTION__, tmd->cd_tagval);
(*bp->h.r_action)(QIN_TMD_FIN, arg);
(*bp->h.r_action)(QIN_TMD_FIN, tmd);
}
break;
}
@@ -1797,14 +1790,14 @@ scsi_target_handler(qact_e action, void *arg)
lun_t *lp = &bp->luns[np->nt_lun];
int i;
for (i = 0, tmd = p_front; tmd; tmd = tmd->cd_private, i++) {
for (i = 0, tmd = p_front; tmd; tmd = tmd->cd_next, i++) {
if (tmd->cd_tagval == np->nt_tagval) {
printk(KERN_WARNING "scsi_target: ABORT_TASK[%llx] found %d into global waitq\n", tmd->cd_tagval, i);
break;
}
}
if (tmd == NULL) {
for (i = 0, tmd = lp->u_front; tmd; tmd = tmd->cd_private, i++) {
for (i = 0, tmd = lp->u_front; tmd; tmd = tmd->cd_next, i++) {
if (tmd->cd_tagval == np->nt_tagval) {
printk(KERN_WARNING "scsi_target: ABORT_TASK[%llx] found %d into waitq for lun %d\n", tmd->cd_tagval, i, np->nt_lun);
break;
@@ -1883,7 +1876,7 @@ scsi_target_thread(void *arg)
tmd_cmd_t *tp;
SDprintk3("scsi_task_thread sleeping\n");
down(&scsi_thread_sleep_semaphore);
down_interruptible(&scsi_thread_sleep_semaphore);
SDprintk3("scsi_task_thread running\n");
spin_lock_irqsave(&scsi_target_lock, flags);
@@ -1892,8 +1885,8 @@ scsi_target_thread(void *arg)
}
spin_unlock_irqrestore(&scsi_target_lock, flags);
while (tp) {
tmd_cmd_t *nxt = tp->cd_private;
tp->cd_private = NULL;
tmd_cmd_t *nxt = tp->cd_next;
tp->cd_next = NULL;
scsi_target_start_cmd(tp, 0);
tp = nxt;
}
@@ -1907,13 +1900,13 @@ scsi_target_thread(void *arg)
tmd_cmd_t *tmd;
tmd = tp;
tp = tmd->cd_private;
tmd->cd_private = NULL;
tp = tmd->cd_next;
tmd->cd_next = NULL;
bp = bus_from_tmd(tmd);
if (bp == NULL) {
printk(KERN_WARNING "lost bus when tring to call TMD_FIN\n");
} else {
if (scsi_target_ldfree(bp, tmd, 0)) {
if (scsi_target_ldfree(bp, &tmd->cd_xfr, 0)) {
SDprintk("%s: TMD_FIN[%llx]\n", __FUNCTION__, tmd->cd_tagval);
(*bp->h.r_action)(QIN_TMD_FIN, tmd);
}
@@ -2102,7 +2095,7 @@ scsi_target_start_user_io(sc_io_t *sc)
}
spin_lock_irqsave(&scsi_target_lock, flags);
if ((tmd = lp->u_front) != NULL) {
if ((lp->u_front = tmd->cd_private) == NULL) {
if ((lp->u_front = tmd->cd_next) == NULL) {
lp->u_tail = NULL;
}
}
@@ -2117,32 +2110,23 @@ scsi_target_start_user_io(sc_io_t *sc)
/*
* If data is coming to us, copy it out to user space first.
*/
if (tmd->cd_hflags & CDFH_DATA_OUT) {
if (tmd->cd_flags & CDF_DATA_OUT) {
int r;
/*
* We subtract resid here because this is *after* the I/O has happened so resid will have been set to the amount *not* transferred.
*/
sc->amt = tmd->cd_xfrlen - tmd->cd_resid;
sc->amt = tmd->cd_totlen;
if (sc->amt > sc->len) {
printk(KERN_ERR "scsi_target: A write to us (%u bytes) that is bigger than the user supplied buffer (%u bytes). Fix!\n", sc->amt, sc->len);
memcpy(tmd->cd_sense, ifailure, TMD_SENSELEN);
tmd->cd_scsi_status = CHECK_CONDITION;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_hflags |= CDFH_SNSVALID|CDFH_STSVALID;
tmd->cd_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
return (-ERANGE);
sc->amt = sc->len;
printk(KERN_WARNING "scsi_target: A write to us (%u bytes) that is bigger than the user supplied buffer (%u bytes)\n", sc->amt, sc->len);
}
r = scsi_target_copydata(tmd->cd_dp, sc->addr, sc->amt, 0);
if (r) {
printk(KERN_ERR "scsi_target: failed to copy data to user space\n");
memcpy(tmd->cd_sense, ifailure, TMD_SENSELEN);
tmd->cd_scsi_status = CHECK_CONDITION;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_hflags |= CDFH_SNSVALID|CDFH_STSVALID;
tmd->cd_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
tmd->cd_xfr.td_hflags &= ~TDFH_DATA_MASK;
tmd->cd_xfr.td_hflags |= TDFH_SNSVALID|TDFH_STSVALID;
tmd->cd_xfr.td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, &tmd->cd_xfr);
return (r);
}
sc->read = 0;
@@ -2151,10 +2135,7 @@ scsi_target_start_user_io(sc_io_t *sc)
}
SDprintk2("scsi_target: WR->USER [%llx] %p amt %u \n", tmd->cd_tagval, tmd, sc->amt);
} else {
/*
* We *don't* subtract resid here because this is *before* the I/O has happened.
*/
sc->amt = tmd->cd_xfrlen;
sc->amt = tmd->cd_totlen;
sc->read = 1;
SDprintk2("scsi_target: RD->USER [%llx] %p amt %u\n", tmd->cd_tagval, tmd, sc->amt);
}
@@ -2167,6 +2148,7 @@ scsi_target_end_user_io(sc_io_t *sc)
bus_t *bp;
lun_t *lp;
tmd_cmd_t *tmd;
tmd_xfr_t *xfr;
bp = bus_from_name(sc->hba_name_unit);
if (bp == NULL) {
@@ -2180,30 +2162,32 @@ scsi_target_end_user_io(sc_io_t *sc)
}
lp = &bp->luns[sc->lun];
tmd = sc->tag;
xfr = &tmd->cd_xfr;
SDprintk2("scsi_target: USER->KERN [%llx] %p err %d len %u\n", tmd->cd_tagval, tmd, sc->err, sc->len);
/*
* If we had an error, stop right here and return something to the initiator.
*/
if (sc->err) {
printk(KERN_ERR "err %d from user app\n", sc->err);
memcpy(tmd->cd_sense, mediaerr, TMD_SENSELEN);
barf:
tmd->cd_scsi_status = CHECK_CONDITION;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
tmd->cd_hflags |= CDFH_SNSVALID|CDFH_STSVALID;
tmd->cd_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_hflags |= TDFH_SNSVALID|TDFH_STSVALID;
xfr->td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return (0);
}
/*
* If we were reading from us to the initiator, copy the data in and set it up for transmit back to the initiator.
*/
if (tmd->cd_hflags & CDFH_DATA_IN) {
if (tmd->cd_flags & CDF_DATA_IN) {
/*
* In this context, a user buffer length that is not equal to what the amount we told the user agent to move is not legal.
*/
if (sc->len != tmd->cd_xfrlen) {
printk(KERN_ERR "scsi_target: user read length %u not equal to required amount of %u\n", sc->len, tmd->cd_xfrlen);
if (sc->len != tmd->cd_totlen) {
printk(KERN_ERR "scsi_target: user read length %u not equal to required amount of %u\n", sc->len, tmd->cd_totlen);
memcpy(tmd->cd_sense, ifailure, TMD_SENSELEN);
goto barf;
}
@@ -2212,12 +2196,14 @@ scsi_target_end_user_io(sc_io_t *sc)
memcpy(tmd->cd_sense, ifailure, TMD_SENSELEN);
goto barf;
}
xfr->td_xfrlen = sc->len;
xfr->td_hflags |= TDFH_DATA_IN;
} else {
tmd->cd_xfrlen = 0;
tmd->cd_hflags &= ~CDFH_DATA_MASK;
xfr->td_xfrlen = 0;
xfr->td_hflags &= ~TDFH_DATA_MASK;
}
tmd->cd_hflags |= CDFH_STSVALID;
(*bp->h.r_action)(QIN_TMD_CONT, tmd);
xfr->td_hflags |= TDFH_STSVALID;
(*bp->h.r_action)(QIN_TMD_CONT, xfr);
return (0);
}