diff --git a/qla_isp/common/isp_library.c b/qla_isp/common/isp_library.c index b7f97ef13..d010e3fe8 100644 --- a/qla_isp/common/isp_library.c +++ b/qla_isp/common/isp_library.c @@ -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); diff --git a/qla_isp/common/isp_stds.h b/qla_isp/common/isp_stds.h index 55db9ddfe..ad4c567d6 100644 --- a/qla_isp/common/isp_stds.h +++ b/qla_isp/common/isp_stds.h @@ -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 diff --git a/qla_isp/common/isp_target.h b/qla_isp/common/isp_target.h index 32b7ca217..33016cbff 100644 --- a/qla_isp/common/isp_target.h +++ b/qla_isp/common/isp_target.h @@ -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 diff --git a/qla_isp/common/isp_tpublic.h b/qla_isp/common/isp_tpublic.h index f0d856118..e682cda18 100644 --- a/qla_isp/common/isp_tpublic.h +++ b/qla_isp/common/isp_tpublic.h @@ -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: diff --git a/qla_isp/common/ispvar.h b/qla_isp/common/ispvar.h index 350334e3d..12e7b10be 100644 --- a/qla_isp/common/ispvar.h +++ b/qla_isp/common/ispvar.h @@ -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 diff --git a/qla_isp/linux/isp_linux.c b/qla_isp/linux/isp_linux.c index 308dce505..f05824723 100644 --- a/qla_isp/linux/isp_linux.c +++ b/qla_isp/linux/isp_linux.c @@ -1,4 +1,4 @@ -/* $Id: isp_linux.c,v 1.203 2007/10/11 22:08:07 mjacob Exp $ */ +/* $Id: isp_linux.c,v 1.206 2007/10/30 01:55:32 mjacob Exp $ */ /* * Copyright (c) 1997-2007 by Matthew Jacob * All rights reserved. @@ -95,34 +95,38 @@ static char *isp_roles; static char *isp_wwpns; static char *isp_wwnns; + #ifdef ISP_TARGET_MODE #ifndef ISP_PARENT_TARGET #define ISP_PARENT_TARGET scsi_target_handler #endif -#define CALL_PARENT_TARGET(hba, cmd, action) \ - cmd->cd_action = action; \ - cmd->cd_next = hba->isp_osinfo.pending_t; \ - hba->isp_osinfo.pending_t = cmd +#define CALL_PARENT_TMD(hba, tmd, action) \ + tmd->cd_action = action; \ + tmd->cd_next = hba->isp_osinfo.pending_t; \ + hba->isp_osinfo.pending_t = tmd #define CALL_PARENT_NOTIFY(hba, ins) \ ins->notify.nt_lreserved = hba->isp_osinfo.pending_n; \ hba->isp_osinfo.pending_n = ins +#define CALL_PARENT_XFR(hba, xfr) \ + xfr->td_lprivate = hba->isp_osinfo.pending_x; \ + hba->isp_osinfo.pending_x = xfr + extern void ISP_PARENT_TARGET (qact_e, void *); static __inline tmd_cmd_t *isp_find_tmd(ispsoftc_t *, uint64_t); static __inline int isp_find_iid_wwn(ispsoftc_t *, uint32_t, uint64_t *); static __inline void isp_clear_iid_wwn(ispsoftc_t *, uint32_t, uint64_t); static void isp_taction(qact_e, void *); -static __inline int nolunsenabled(ispsoftc_t *, int); -static void isp_target_start_ctio(ispsoftc_t *, tmd_cmd_t *); +static void isp_target_start_ctio(ispsoftc_t *, tmd_xfr_t *); static void isp_handle_platform_atio(ispsoftc_t *, at_entry_t *); static void isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *); static void isp_handle_platform_atio7(ispsoftc_t *, at7_entry_t *); static int isp_terminate_cmd(ispsoftc_t *, tmd_cmd_t *); static void isp_handle_platform_ctio(ispsoftc_t *, void *); static int isp_target_putback_atio(ispsoftc_t *, tmd_cmd_t *); -static void isp_complete_ctio(ispsoftc_t *, tmd_cmd_t *); +static void isp_complete_ctio(ispsoftc_t *, tmd_xfr_t *); static void isp_tgt_tq(ispsoftc_t *); #endif @@ -823,7 +827,7 @@ int isp_init_target(ispsoftc_t *isp) { int i; - void *pool, *npool, *inqdata, *dpwrk; + void *pool, *npool; unsigned long flags; static const uint8_t inqdsd[DEFAULT_INQSIZE] = { 0x7f, 0x00, 0x03, 0x02, 0x1c, 0x00, 0x00, 0x00, @@ -844,21 +848,6 @@ isp_init_target(ispsoftc_t *isp) isp_kfree(pool, NTGT_CMDS * TMD_SIZE); return (-ENOMEM); } - inqdata = isp_kalloc(DEFAULT_INQSIZE, GFP_KERNEL|GFP_DMA); - if (inqdata == NULL) { - isp_prt(isp, ISP_LOGERR, "cannot allocate static Inquiry Data"); - isp_kfree(pool, NTGT_CMDS * TMD_SIZE); - isp_kfree(npool, N_NOTIFIES * sizeof (isp_notify_t)); - return (-ENOMEM); - } - dpwrk = isp_kzalloc(NTGT_CMDS * sizeof (struct scatterlist), GFP_KERNEL); - if (dpwrk == NULL) { - isp_prt(isp, ISP_LOGERR, "cannot allocate static scatterlists"); - isp_kfree(pool, NTGT_CMDS * TMD_SIZE); - isp_kfree(npool, N_NOTIFIES * sizeof (isp_notify_t)); - isp_kfree(inqdata, DEFAULT_INQSIZE); - return (-ENOMEM); - } sema_init(&isp->isp_osinfo.tgt_inisem, 1); @@ -871,9 +860,10 @@ isp_init_target(ispsoftc_t *isp) for (i = 0; i < N_NOTIFIES-1; i++) { isp->isp_osinfo.npool[i].notify.nt_lreserved = &isp->isp_osinfo.npool[i+1]; } - isp->isp_osinfo.inqdata = inqdata; + for (i = 0; i < (N_TGT_AUX >> 5); i++) { + isp->isp_osinfo.auxbmap[i] = 0; + } MEMCPY(isp->isp_osinfo.inqdata, inqdsd, DEFAULT_INQSIZE); - isp->isp_osinfo.dpwrk = dpwrk; isp->isp_osinfo.pending_t = NULL; isp->isp_osinfo.tfreelist = isp->isp_osinfo.pool; isp->isp_osinfo.bfreelist = &isp->isp_osinfo.pool[NTGT_CMDS-1]; @@ -887,7 +877,7 @@ isp_attach_target(ispsoftc_t *isp) { hba_register_t hba; hba.r_identity = isp; - snprintf(hba.r_name, sizeof (hba.r_name), ISP_NAME); + snprintf(hba.r_name, sizeof (hba.r_name), "isp"); hba.r_inst = isp->isp_unit; hba.r_version = QR_VERSION; hba.r_action = isp_taction; @@ -906,7 +896,7 @@ isp_attach_target(ispsoftc_t *isp) void isp_deinit_target(ispsoftc_t *isp) { - void *pool, *npool, *inqdata, *dpwrk; + void *pool, *npool; unsigned long flags; ISP_LOCK_SOFTC(isp); @@ -914,10 +904,6 @@ isp_deinit_target(ispsoftc_t *isp) isp->isp_osinfo.pool = NULL; npool = isp->isp_osinfo.npool; isp->isp_osinfo.npool = NULL; - inqdata = isp->isp_osinfo.inqdata; - isp->isp_osinfo.inqdata = NULL; - dpwrk = isp->isp_osinfo.dpwrk; - isp->isp_osinfo.dpwrk = NULL; ISP_UNLK_SOFTC(isp); if (pool) { isp_kfree(pool, NTGT_CMDS * TMD_SIZE); @@ -925,12 +911,6 @@ isp_deinit_target(ispsoftc_t *isp) if (npool) { isp_kfree(npool, N_NOTIFIES * sizeof (isp_notify_t)); } - if (inqdata) { - isp_kfree(inqdata, DEFAULT_INQSIZE); - } - if (dpwrk) { - isp_kfree(dpwrk, NTGT_CMDS * sizeof (struct scatterlist)); - } } void @@ -959,6 +939,7 @@ isp_tgt_tq(ispsoftc_t *isp) { isp_notify_t *ins; tmd_cmd_t *tmd; + tmd_xfr_t *xfr; unsigned long flags; ISP_LOCK_SOFTC(isp); @@ -970,6 +951,10 @@ isp_tgt_tq(ispsoftc_t *isp) if (tmd) { isp->isp_osinfo.pending_t = NULL; } + xfr = isp->isp_osinfo.pending_x; + if (xfr) { + isp->isp_osinfo.pending_x = NULL; + } ISP_UNLK_SOFTC(isp); while (ins != NULL) { isp_notify_t *next = ins->notify.nt_lreserved; @@ -982,9 +967,15 @@ isp_tgt_tq(ispsoftc_t *isp) tmd_cmd_t *next = tmd->cd_next; tmd->cd_next = NULL; isp_prt(isp, ISP_LOGTDEBUG2, "isp_tgt_tq[%llx] -> code 0x%x", tmd->cd_tagval, tmd->cd_action); - ISP_PARENT_TARGET(tmd->cd_action, tmd); + ISP_PARENT_TARGET(tmd->cd_action, tmd); tmd = next; } + while (xfr != NULL) { + tmd_xfr_t *next = xfr->td_lprivate; + xfr->td_lprivate = NULL; + ISP_PARENT_TARGET(QOUT_TMD_DONE, xfr); + xfr = next; + } } static __inline tmd_cmd_t * @@ -997,7 +988,7 @@ isp_find_tmd(ispsoftc_t *isp, uint64_t tagval) return (NULL); } for (i = 0; i < NTGT_CMDS; i++) { - if (tmd->cd_lflags && tmd->cd_tagval == tagval) { + if ((tmd->cd_lflags & CDFL_BUSY) && tmd->cd_tagval == tagval) { return (tmd); } tmd++; @@ -1181,7 +1172,7 @@ isp_taction(qact_e action, void *arg) printk(KERN_ERR "null isp @ %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); break; } - ep->en_error = isp_en_dis_lun(isp, 1, ep->en_chan, ep->en_tgt, ep->en_lun); + ep->en_error = isp_enable_lun(isp, ep->en_chan, ep->en_tgt, ep->en_lun); ISP_PARENT_TARGET(QOUT_ENABLE, ep); break; @@ -1192,7 +1183,7 @@ isp_taction(qact_e action, void *arg) printk(KERN_ERR "null isp @ %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); break; } - ep->en_error = isp_en_dis_lun(isp, 0, ep->en_chan, ep->en_tgt, ep->en_lun); + ep->en_error = isp_disable_lun(isp, ep->en_chan, ep->en_tgt, ep->en_lun); ISP_PARENT_TARGET(QOUT_DISABLE, ep); ISP_LOCK_SOFTC(isp); (void) isp_target_async(isp, 0, ASYNC_LOOP_DOWN); @@ -1200,15 +1191,13 @@ isp_taction(qact_e action, void *arg) break; case QIN_TMD_CONT: - tmd = (tmd_cmd_t *) arg; + { + tmd_xfr_t *xfr = arg; + tmd = xfr->td_cmd; isp = tmd->cd_hba; - if (isp == NULL) { - printk(KERN_ERR "null isp @ %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); - break; - } - isp_target_start_ctio(isp, tmd); + isp_target_start_ctio(isp, arg); break; - + } case QIN_TMD_FIN: tmd = (tmd_cmd_t *) arg; isp = tmd->cd_hba; @@ -1217,18 +1206,7 @@ isp_taction(qact_e action, void *arg) break; } ISP_LOCK_SOFTC(isp); -#if 0 isp_prt(isp, ISP_LOGTDEBUG1, "freeing tmd %p [%llx]", tmd, tmd->cd_tagval); - if ((isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { - isp_prt(isp, ISP_LOGTDEBUG1, "FIN with tm disabled"); - ISP_UNLK_SOFTC(isp); - break; - } -#endif - if (tmd->cd_lflags & CDFL_CALL_CMPLT) { - isp_prt(isp, ISP_LOGWARN, "CALL_CMPLT set for %llx, LFLAGS 0x%x", tmd->cd_tagval, tmd->cd_lflags); - tmd->cd_lflags ^= CDFL_CALL_CMPLT; - } if (tmd->cd_lflags & CDFL_RESRC_FILL) { if (isp_target_putback_atio(isp, tmd)) { SEND_THREAD_EVENT(isp, ISP_THREAD_FC_PUTBACK, tmd, 0, __FUNCTION__, __LINE__); @@ -1240,10 +1218,7 @@ isp_taction(qact_e action, void *arg) tmd->cd_lflags &= ~CDFL_NEED_CLNUP; (void) isp_terminate_cmd(isp, tmd); } - tmd->cd_hba = NULL; - tmd->cd_lflags = 0; tmd->cd_next = NULL; - /* don't zero cd_hflags or cd_tagval- it may be being used to catch duplicate frees */ if (isp->isp_osinfo.tfreelist) { isp->isp_osinfo.bfreelist->cd_next = tmd; } else { @@ -1320,11 +1295,7 @@ isp_taction(qact_e action, void *arg) up(rsemap); } ISP_UNLK_SOFTC(isp); - /* - * force us to not run any queues - */ - isp = NULL; - return; + break; default: printk(KERN_ERR "isp_taction: unknown action %x, arg %p\n", action, arg); break; @@ -1334,48 +1305,98 @@ isp_taction(qact_e action, void *arg) } } -static __inline int -nolunsenabled(ispsoftc_t *isp, int port) +static int +lunenabled(ispsoftc_t *isp, uint16_t bus, uint16_t lun) { - int i, wbase, wend; - - if (IS_FC(isp)) { - wbase = 0; - wend = TM_MAX_LUN_FC >> 5; - } else { - if (port) { - wend = TM_MAX_LUN_FC >> 5; - wbase = wend >> 1; - } else { - wend = (TM_MAX_LUN_FC >> 5) >> 1; - wbase = 0; + tgt_enalun_t *axl = isp->isp_osinfo.luns; + while (axl) { + if (axl->bus == bus && axl->lun == lun) { + return (1); } + axl = axl->next; } - for (i = wbase; i < wend; i++) { - if (isp->isp_osinfo.lunbmap[i]) { + return (0); +} + +static int +nolunsenabled(ispsoftc_t *isp, uint16_t bus) +{ + tgt_enalun_t *axl = isp->isp_osinfo.luns; + while (axl) { + if (axl->bus == bus) { return (0); } + axl = axl->next; } return (1); } +static int +addlun(ispsoftc_t *isp, uint16_t bus, uint16_t lun) +{ + tgt_enalun_t *axl = isp_kalloc(sizeof (tgt_enalun_t), GFP_KERNEL); + unsigned long flags; + + if (axl == NULL) { + return (-1); + } + axl->lun = lun; + axl->bus = bus; + ISP_LOCK_SOFTC(isp); + axl->next = isp->isp_osinfo.luns; + isp->isp_osinfo.luns = axl; + ISP_UNLK_SOFTC(isp); + return (0); +} + +static int +remlun(ispsoftc_t *isp, uint16_t lun, uint16_t bus) +{ + tgt_enalun_t *axl, *axy = NULL; + unsigned long flags; + ISP_LOCK_SOFTC(isp); + axl = isp->isp_osinfo.luns; + if (axl->lun == lun && axl->bus == bus) { + isp->isp_osinfo.luns = axl->next; + axy = axl; + } else { + while (axl->next) { + if (axl->next->lun == lun && axl->next->bus == bus) { + axy = axl->next; + axl->next = axy->next; + break; + } + axl = axl->next; + } + } + ISP_UNLK_SOFTC(isp); + if (axy == NULL) { + return (-1); + } + isp_kfree(axy, sizeof (tgt_enalun_t)); + return (0); +} + static void -isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) +isp_target_start_ctio(ispsoftc_t *isp, tmd_xfr_t *xfr) { void *qe; uint32_t handle; - uint32_t *rp; uint32_t nxti, optr; uint8_t local[QENTRY_LEN]; unsigned long flags; + int32_t resid; + tmd_cmd_t *tmd = xfr->td_cmd; + + xfr->td_error = 0; /* * Check for commands that are already dead */ if (tmd->cd_lflags & CDFL_ABORTED) { isp_prt(isp, ISP_LOGINFO, "[%llx] already ABORTED- not sending a CTIO", tmd->cd_tagval); - tmd->cd_error = -ENXIO; - tmd->cd_lflags |= CDFL_ERROR; + dump_stack(); + xfr->td_error = -ENXIO; goto out; } @@ -1384,46 +1405,52 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) * If we're sending data, we have to have one and only one data * direction set. */ - if (tmd->cd_xfrlen == 0) { - if ((tmd->cd_hflags & CDFH_STSVALID) == 0) { + if (xfr->td_xfrlen == 0) { + if ((xfr->td_hflags & TDFH_STSVALID) == 0) { isp_prt(isp, ISP_LOGERR, "CTIO, no data, and no status is wrong"); - tmd->cd_error = -EINVAL; - tmd->cd_lflags |= CDFL_ERROR; + dump_stack(); + xfr->td_error = -EINVAL; goto out; } } else { - if ((tmd->cd_hflags & CDFH_DATA_MASK) == 0) { + if ((xfr->td_hflags & TDFH_DATA_MASK) == 0) { isp_prt(isp, ISP_LOGERR, "data CTIO with no direction is wrong"); - tmd->cd_error = -EINVAL; - tmd->cd_lflags |= CDFL_ERROR; + dump_stack(); + xfr->td_error = -EINVAL; goto out; } - if ((tmd->cd_hflags & CDFH_DATA_MASK) == CDFH_DATA_MASK) { - isp_prt(isp, ISP_LOGERR, "data CTIO with both directions is wrong"); - tmd->cd_error = -EINVAL; - tmd->cd_lflags |= CDFL_ERROR; + if ((xfr->td_hflags & TDFH_DATA_MASK) == TDFH_DATA_MASK) { + isp_prt(isp, ISP_LOGERR, "data CTIO with both directions is wrong (for now)"); + dump_stack(); + xfr->td_error = -EINVAL; goto out; } } - tmd->cd_lflags &= ~CDFL_ERROR; - MEMZERO(local, QENTRY_LEN); + /* + * Use this lock to protect tmd fields + */ ISP_LOCK_SOFTC(isp); - if (isp_getrqentry(isp, &nxti, &optr, &qe)) { - isp_prt(isp, ISP_LOGWARN, "%s: request queue overflow", __FUNCTION__); - tmd->cd_error = -ENOMEM; - tmd->cd_lflags |= CDFL_ERROR; - ISP_UNLK_SOFTC(isp); - goto out; - } + + /* + * Pre-increment cd_moved so we know how many bytes are actually in transit. If we actually fail to move + * the bytes, we'll subtract things out when we collect status. + */ + tmd->cd_moved += xfr->td_xfrlen; + + /* + * Set the residual to be equal to the total length less the amount previously moved plus this transfer size + */ + resid = tmd->cd_totlen - tmd->cd_moved; /* * We're either moving data or completing a command here (or both). */ if (IS_24XX(isp)) { ct7_entry_t *cto = (ct7_entry_t *) local; + int tattr; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; cto->ct_header.rqs_entry_count = 1; @@ -1434,38 +1461,54 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) cto->ct_oxid = tmd->cd_oxid; cto->ct_scsi_status = tmd->cd_scsi_status; - if (tmd->cd_xfrlen == 0) { + switch (tmd->cd_tagtype) { + case CD_SIMPLE_TAG: + tattr = FCP_CMND_TASK_ATTR_SIMPLE; + break; + case CD_HEAD_TAG: + tattr = FCP_CMND_TASK_ATTR_HEAD; + break; + case CD_ORDERED_TAG: + tattr = FCP_CMND_TASK_ATTR_ORDERED; + break; + case CD_ACA_TAG: + tattr = FCP_CMND_TASK_ATTR_ACA; + break; + default: + tattr = FCP_CMND_TASK_ATTR_UNTAGGED; + break; + } + cto->ct_flags = tattr << CT7_TASK_ATTR_SHIFT; + + if (xfr->td_xfrlen == 0) { cto->ct_flags |= CT7_FLAG_MODE1 | CT7_NO_DATA | CT7_SENDSTATUS; - if ((tmd->cd_hflags & CDFH_SNSVALID) != 0) { - cto->rsp.m1.ct_resplen = min(TMD_SENSELEN, MAXRESPLEN_24XX); - MEMCPY(cto->rsp.m1.ct_resp, tmd->cd_sense, cto->rsp.m1.ct_resplen); + if ((xfr->td_hflags & TDFH_SNSVALID) != 0) { + cto->ct_senselen = min(TMD_SENSELEN, MAXRESPLEN); + MEMCPY(cto->rsp.m1.ct_resp, tmd->cd_sense, cto->ct_senselen); + cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); } } else { cto->ct_flags |= CT7_FLAG_MODE0; - if (tmd->cd_hflags & CDFH_DATA_IN) { + if (xfr->td_hflags & TDFH_DATA_IN) { cto->ct_flags |= CT7_DATA_IN; } else { cto->ct_flags |= CT7_DATA_OUT; } - if (tmd->cd_hflags & CDFH_STSVALID) { + if (xfr->td_hflags & TDFH_STSVALID) { cto->ct_flags |= CT7_SENDSTATUS; } - /* - * We assume we'll transfer what we say we'll transfer. - * It should get added back in if we fail. - */ - tmd->cd_resid -= tmd->cd_xfrlen; } - - if ((cto->ct_flags & CT7_SENDSTATUS) && tmd->cd_resid) { - cto->ct_resid = tmd->cd_resid; - cto->ct_scsi_status |= CT2_DATA_UNDER; /* XXX SHOULD BE IN ISP_STDS.H */ + if ((cto->ct_flags & CT7_SENDSTATUS) && resid) { + cto->ct_resid = resid; + if (resid < 0) { + cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8); + } else { + cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8); + } } else { cto->ct_resid = 0; } - isp_prt(isp, ISP_LOGTDEBUG0, "CTIO7[%llx] ssts %x flags %x resid %d", tmd->cd_tagval, tmd->cd_scsi_status, cto->ct_flags, cto->ct_resid); - rp = &cto->ct_resid; - + isp_prt(isp, ISP_LOGTDEBUG0, "CTIO7[%llx] scsi sts %x flags %x resid %d offset %u", tmd->cd_tagval, tmd->cd_scsi_status, cto->ct_flags, resid, xfr->td_offset); } else if (IS_FC(isp)) { ct2_entry_t *cto = (ct2_entry_t *) local; uint16_t *ssptr = NULL; @@ -1485,37 +1528,34 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) cto->ct_rxid = AT2_GET_TAG(tmd->cd_tagval); if (cto->ct_rxid == 0) { isp_prt(isp, ISP_LOGERR, "a tagval of zero is not acceptable"); - tmd->cd_error = -EINVAL; - tmd->cd_lflags |= CDFL_ERROR; + xfr->td_error = -EINVAL; ISP_UNLK_SOFTC(isp); goto out; } #if 0 /* - * XXX: I've had problems with this at varying times- dunno why + * I've had problems with this at varying times- dunno why */ cto->ct_flags = CT2_FASTPOST; -#else - cto->ct_flags = 0; #endif - if (tmd->cd_xfrlen == 0) { + if (xfr->td_xfrlen == 0) { cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA | CT2_SENDSTATUS; ssptr = &cto->rsp.m1.ct_scsi_status; *ssptr = tmd->cd_scsi_status; - if ((tmd->cd_hflags & CDFH_SNSVALID) != 0) { + if ((xfr->td_hflags & TDFH_SNSVALID) != 0) { cto->rsp.m1.ct_senselen = min(TMD_SENSELEN, MAXRESPLEN); MEMCPY(cto->rsp.m1.ct_resp, tmd->cd_sense, cto->rsp.m1.ct_senselen); cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; } } else { cto->ct_flags |= CT2_FLAG_MODE0; - if (tmd->cd_hflags & CDFH_DATA_IN) { + if (xfr->td_hflags & TDFH_DATA_IN) { cto->ct_flags |= CT2_DATA_IN; } else { cto->ct_flags |= CT2_DATA_OUT; } - if (tmd->cd_hflags & CDFH_STSVALID) { + if (xfr->td_hflags & TDFH_STSVALID) { ssptr = &cto->rsp.m0.ct_scsi_status; cto->ct_flags |= CT2_SENDSTATUS; cto->rsp.m0.ct_scsi_status = tmd->cd_scsi_status; @@ -1524,21 +1564,19 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) * to check for sense data. */ } - /* - * We assume we'll transfer what we say we'll transfer. - * It should get added back in if we fail. - */ - tmd->cd_resid -= tmd->cd_xfrlen; } - if (ssptr && tmd->cd_resid) { - cto->ct_resid = tmd->cd_resid; - *ssptr |= CT2_DATA_UNDER; + if (ssptr && resid) { + cto->ct_resid = resid; + if (resid < 0) { + *ssptr |= CT2_DATA_OVER; + } else { + *ssptr |= CT2_DATA_UNDER; + } } else { cto->ct_resid = 0; } - isp_prt(isp, ISP_LOGTDEBUG0, "CTIO2[%llx] ssts %x flags %x resid %d", tmd->cd_tagval, tmd->cd_scsi_status, cto->ct_flags, cto->ct_resid); - rp = &cto->ct_resid; + isp_prt(isp, ISP_LOGTDEBUG0, "CTIO2[%llx] scsi sts %x flags %x resid %d", tmd->cd_tagval, tmd->cd_scsi_status, cto->ct_flags, resid); if (cto->ct_flags & CT2_SENDSTATUS) { cto->ct_flags |= CT2_CCINCR; } @@ -1556,18 +1594,18 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) cto->ct_tag_val = AT_GET_TAG(tmd->cd_tagval); cto->ct_flags |= CT_TQAE; } - if (tmd->cd_lflags & CDFL_NODISC) { + if (tmd->cd_flags & CDF_NODISC) { cto->ct_flags |= CT_NODISC; } - if (tmd->cd_xfrlen == 0) { + if (xfr->td_xfrlen == 0) { cto->ct_flags |= CT_NO_DATA | CT_SENDSTATUS; cto->ct_scsi_status = tmd->cd_scsi_status; cto->ct_resid = 0; } else { - if (tmd->cd_hflags & CDFH_STSVALID) { + if (xfr->td_hflags & TDFH_STSVALID) { cto->ct_flags |= CT_SENDSTATUS; } - if (tmd->cd_hflags & CDFH_DATA_IN) { + if (xfr->td_hflags & TDFH_DATA_IN) { cto->ct_flags |= CT_DATA_IN; } else { cto->ct_flags |= CT_DATA_OUT; @@ -1576,22 +1614,26 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) * We assume we'll transfer what we say we'll transfer. * Otherwise, the command is dead. */ - tmd->cd_resid -= tmd->cd_xfrlen; - if (tmd->cd_hflags & CDFH_STSVALID) { - cto->ct_resid = tmd->cd_resid; + if (xfr->td_hflags & TDFH_STSVALID) { + cto->ct_resid = resid; } } - isp_prt(isp, ISP_LOGTDEBUG0, "CTIO[%llx] ssts %x resid %d cd_hflags %x", tmd->cd_tagval, tmd->cd_scsi_status, tmd->cd_resid, tmd->cd_hflags); - rp = &cto->ct_resid; + isp_prt(isp, ISP_LOGTDEBUG0, "CTIO[%llx] scsi sts %x resid %d cd_lflags %x", tmd->cd_tagval, tmd->cd_scsi_status, resid, xfr->td_hflags); if (cto->ct_flags & CT_SENDSTATUS) { cto->ct_flags |= CT_CCINCR; } } - if (isp_save_xs_tgt(isp, tmd, &handle)) { + if (isp_getrqentry(isp, &nxti, &optr, &qe)) { + isp_prt(isp, ISP_LOGWARN, "%s: request queue overflow", __FUNCTION__); + xfr->td_error = -ENOMEM; + ISP_UNLK_SOFTC(isp); + goto out; + } + + if (isp_save_xs_tgt(isp, xfr, &handle)) { isp_prt(isp, ISP_LOGERR, "isp_target_start_ctio: No XFLIST pointers"); - tmd->cd_error = -ENOMEM; - tmd->cd_lflags |= CDFL_ERROR; + xfr->td_error = -ENOMEM; ISP_UNLK_SOFTC(isp); goto out; } @@ -1613,7 +1655,7 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) * format. */ - switch (ISP_DMASETUP(isp, (XS_T *)tmd, (ispreq_t *) local, &nxti, optr)) { + switch (ISP_DMASETUP(isp, (XS_T *)xfr, (ispreq_t *) local, &nxti, optr)) { case CMD_QUEUED: ISP_ADD_REQUEST(isp, nxti); /* @@ -1621,34 +1663,30 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) * If the CTIO fails, we still do resource replenish, but handle it at * CTIO completion time. */ - if (tmd->cd_hflags & CDFH_STSVALID) { + if (xfr->td_hflags & TDFH_STSVALID) { tmd->cd_lflags &= ~CDFL_RESRC_FILL; } ISP_UNLK_SOFTC(isp); return; case CMD_EAGAIN: - tmd->cd_error = -ENOMEM; - tmd->cd_lflags |= CDFL_ERROR; + xfr->td_error = -ENOMEM; isp_destroy_tgt_handle(isp, handle); break; case CMD_COMPLETE: - tmd->cd_error = *rp; /* propagated back */ - tmd->cd_lflags |= CDFL_ERROR; isp_destroy_tgt_handle(isp, handle); break; default: - tmd->cd_error = -EFAULT; /* probably dma mapping failure */ - tmd->cd_lflags |= CDFL_ERROR; + xfr->td_error = -EFAULT; /* probably dma mapping failure */ isp_destroy_tgt_handle(isp, handle); break; } ISP_UNLK_SOFTC(isp); out: if ((tmd->cd_lflags & CDFL_LCL) == 0) { - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_DONE); + CALL_PARENT_XFR(isp, xfr); } } @@ -1711,7 +1749,11 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) } if ((isp->isp_osinfo.tfreelist = tmd->cd_next) == NULL) { isp->isp_osinfo.bfreelist = NULL; + } else { + tmd->cd_next = NULL; } + memset(tmd, 0, sizeof (tmd_cmd_t)); + /* * Set the local flags to BUSY. Also set the flags * to force a resource replenish just in case we never @@ -1723,20 +1765,17 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) tmd->cd_tgt = aep->at_tgt; FLATLUN_TO_L0LUN(tmd->cd_lun, aep->at_lun); if (aep->at_flags & AT_NODISC) { - tmd->cd_lflags |= CDFL_NODISC; + tmd->cd_flags |= CDF_NODISC; } if (status & QLTM_SVALID) { MEMCPY(tmd->cd_sense, aep->at_sense, QLTM_SENSELEN); - tmd->cd_lflags |= CDFL_SNSVALID; + tmd->cd_flags |= CDF_SNSVALID; } MEMCPY(tmd->cd_cdb, aep->at_cdb, min(TMD_CDBLEN, ATIO_CDBLEN)); AT_MAKE_TAGID(tmd->cd_tagval, tmd->cd_channel, isp->isp_unit, aep); tmd->cd_tagtype = aep->at_tag_type; tmd->cd_hba = isp; - tmd->cd_data = NULL; - tmd->cd_totlen = tmd->cd_resid = tmd->cd_xfrlen = tmd->cd_error = 0; - tmd->cd_scsi_status = 0; - isp_prt(isp, ISP_LOGTDEBUG1, "ATIO[%llx] CDB=0x%x bus %d iid%d->lun%d ttype 0x%x %s", tmd->cd_tagval, aep->at_cdb[0] & 0xff, + isp_prt(isp, ISP_LOGTDEBUG0, "ATIO[%llx] CDB=0x%x bus %d iid%d->lun%d ttype 0x%x %s", tmd->cd_tagval, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_type, (aep->at_flags & AT_NODISC)? "nondisc" : "disconnecting"); if (isp->isp_osinfo.hcb == 0) { @@ -1749,10 +1788,99 @@ isp_handle_platform_atio(ispsoftc_t *isp, at_entry_t *aep) isp->isp_osinfo.bfreelist = tmd; isp_endcmd(isp, aep, SCSI_BUSY, 0); } else { - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_START); + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); } } +static void +isp_lcl_respond(ispsoftc_t *isp, void *aep, tmd_cmd_t *tmd) +{ + uint8_t *cdbp; + + if (IS_24XX(isp)) { + cdbp = ((at7_entry_t *)aep)->at_cmnd.cdb_dl.sf.fcp_cmnd_cdb; + } else if (IS_FC(isp)) { + cdbp = ((at2_entry_t *)aep)->at_cdb; + } else { + cdbp = ((at_entry_t *)aep)->at_cdb; + } + + if (cdbp[0] == INQUIRY && L0LUN_TO_FLATLUN(tmd->cd_lun) == 0) { + if (cdbp[1] == 0 && cdbp[2] == 0 && cdbp[3] == 0 && cdbp[5] == 0) { + tmd_xfr_t *xfr; + struct scatterlist *dp; + int amt, i; + + for (i = 0; i < N_TGT_AUX; i++) { + if (LUN_BTST(isp->isp_osinfo.auxbmap, i)) { + break; + } + } + if (i == N_TGT_AUX) { + isp_endcmd(isp, aep, SCSI_BUSY, 0); + return; + } + LUN_BSET(isp->isp_osinfo.auxbmap, i); + xfr = &isp->isp_osinfo.auxinfo[i].xfr; + dp = &isp->isp_osinfo.auxinfo[i].sg; + MEMZERO(dp, sizeof (*dp)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + dp->address = (char *) isp->isp_osinfo.inqdata; +#else + dp->page = virt_to_page(isp->isp_osinfo.inqdata); + dp->offset = offset_in_page(isp->isp_osinfo.inqdata); +#endif + dp->length = DEFAULT_INQSIZE; + + xfr->td_data = dp; + xfr->td_xfrlen = min(DEFAULT_INQSIZE, tmd->cd_totlen); + if ((amt = cdbp[4]) == 0) { + amt = 256; + } + if (xfr->td_xfrlen > amt) { + xfr->td_xfrlen = amt; + } + xfr->td_hflags |= TDFH_DATA_IN|TDFH_STSVALID; + xfr->td_cmd = tmd; + xfr->td_offset = 0; + xfr->td_error = 0; + xfr->td_lflags = 0; + + tmd->cd_scsi_status = 0; + tmd->cd_lflags |= CDFL_LCL; + ISP_DROP_LK_SOFTC(isp); + isp_target_start_ctio(isp, xfr); + ISP_IGET_LK_SOFTC(isp); + return; + } + /* + * Illegal field in CDB + * 0x24 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK + */ + isp_endcmd(isp, aep, 0x24005102, 0); + } else if (L0LUN_TO_FLATLUN(tmd->cd_lun) == 0) { + /* + * Not Ready, Cause Not Reportable + * + * 0x4 << 24 | 0x2 << 12 | ECMD_SVALID | SCSI_CHECK + */ + isp_endcmd(isp, aep, 0x04002102, 0); + } else { + /* + * Logical Unit Not Supported: + * 0x25 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK + */ + isp_endcmd(isp, aep, 0x25005102, 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; +} + static void isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) { @@ -1799,7 +1927,10 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) } if ((isp->isp_osinfo.tfreelist = tmd->cd_next) == NULL) { isp->isp_osinfo.bfreelist = NULL; + } else { + tmd->cd_next = NULL; } + memset(tmd, 0, sizeof (tmd_cmd_t)); /* * Set the local flags to BUSY. Also set the flags @@ -1813,10 +1944,8 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) (((uint64_t) aep->at_wwpn[2]) << 16) | (((uint64_t) aep->at_wwpn[3]) << 0); tmd->cd_nphdl = iid; - tmd->cd_nseg = 0; tmd->cd_tgt = ISP_PORTWWN(isp); FLATLUN_TO_L0LUN(tmd->cd_lun, lun); - tmd->cd_channel = 0; MEMCPY(tmd->cd_cdb, aep->at_cdb, min(TMD_CDBLEN, ATIO2_CDBLEN)); switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { @@ -1840,13 +1969,13 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) switch (aep->at_execodes & (ATIO2_EX_WRITE|ATIO2_EX_READ)) { case ATIO2_EX_WRITE: - tmd->cd_lflags |= CDFL_DATA_OUT; + tmd->cd_flags |= CDF_DATA_OUT; break; case ATIO2_EX_READ: - tmd->cd_lflags |= CDFL_DATA_IN; + tmd->cd_flags |= CDF_DATA_IN; break; case ATIO2_EX_WRITE|ATIO2_EX_READ: - tmd->cd_lflags |= CDFL_BIDIR; + tmd->cd_flags |= CDF_BIDIR; isp_prt(isp, ISP_LOGWARN, "ATIO2 with both read/write set"); break; default: @@ -1855,24 +1984,21 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) AT2_MAKE_TAGID(tmd->cd_tagval, 0, isp->isp_unit, aep); tmd->cd_hba = isp; - tmd->cd_data = NULL; - tmd->cd_hflags = 0; tmd->cd_totlen = aep->at_datalen; - tmd->cd_resid = tmd->cd_xfrlen = tmd->cd_error = 0; - tmd->cd_scsi_status = 0; if ((isp->isp_dblev & ISP_LOGTDEBUG0) || isp->isp_osinfo.hcb == 0) { const char *sstr; - switch (tmd->cd_lflags & CDFL_BIDIR) { + switch (tmd->cd_flags & CDF_BIDIR) { default: sstr = "nodatadir"; break; - case CDFL_DATA_OUT: + case CDF_DATA_OUT: sstr = "DATA OUT"; break; - case CDFL_DATA_IN: + case CDF_DATA_IN: sstr = "DATA IN"; break; - case CDFL_DATA_OUT|CDFL_DATA_IN: + case CDF_DATA_OUT|CDF_DATA_IN: + sstr = "BIDIR"; break; } @@ -1881,70 +2007,10 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) } if (isp->isp_osinfo.hcb == 0) { - tmd->cd_next = NULL; - if (isp->isp_osinfo.tfreelist) { - isp->isp_osinfo.bfreelist->cd_next = tmd; - } else { - isp->isp_osinfo.tfreelist = tmd; - } - isp->isp_osinfo.bfreelist = tmd; - if (aep->at_cdb[0] == INQUIRY && lun == 0) { - if (aep->at_cdb[1] == 0 && aep->at_cdb[2] == 0 && aep->at_cdb[3] == 0 && aep->at_cdb[5] == 0) { - struct scatterlist *dp; - int amt, idx; - - idx = tmd - isp->isp_osinfo.pool; - dp = &isp->isp_osinfo.dpwrk[idx]; - MEMZERO(dp, sizeof (*dp)); - dp->page = virt_to_page(isp->isp_osinfo.inqdata); - dp->offset = offset_in_page(isp->isp_osinfo.inqdata); - dp->length = DEFAULT_INQSIZE; - tmd->cd_xfrlen = min(DEFAULT_INQSIZE, tmd->cd_totlen); - tmd->cd_data = dp; - if ((amt = tmd->cd_cdb[4]) == 0) { - amt = 256; - } - if (tmd->cd_xfrlen > amt) { - tmd->cd_xfrlen = amt; - } - tmd->cd_resid = tmd->cd_totlen; - tmd->cd_hflags |= CDFH_DATA_IN|CDFH_STSVALID; - tmd->cd_lflags |= CDFL_LCL; - ISP_DROP_LK_SOFTC(isp); - isp_target_start_ctio(isp, tmd); - ISP_IGET_LK_SOFTC(isp); - return; - } else { - /* - * Illegal field in CDB - * 0x24 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK - */ - isp_endcmd(isp, aep, 0x24005102, 0); - } - } else if (lun == 0) { - /* - * Not Ready, Cause Not Reportable - * - * 0x4 << 24 | 0x2 << 12 | ECMD_SVALID | SCSI_CHECK - */ - isp_endcmd(isp, aep, 0x04002102, 0); - } else { - /* - * Logical Unit Not Supported: - * 0x25 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK - */ - isp_endcmd(isp, aep, 0x25005102, 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; - return; + isp_lcl_respond(isp, aep, tmd); + } else { + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); } - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_START); } static void @@ -1980,7 +2046,7 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) hdl = 0xffff; for (i = 0; i < TM_CS; i++) { if (isp->isp_osinfo.tgt_cache[i].portid == sid) { - isp_prt(isp, ISP_LOGTDEBUG0, "[0x%x] assigning NPHDL from target cache", aep->at_rxid); + isp_prt(isp, ISP_LOGTDEBUG2, "[0x%x] assigning NPHDL from target cache", aep->at_rxid); hdl = isp->isp_osinfo.tgt_cache[i].nphdl; iid = isp->isp_osinfo.tgt_cache[i].iid; break; @@ -2000,6 +2066,7 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) if ((isp->isp_osinfo.tfreelist = tmd->cd_next) == NULL) { isp->isp_osinfo.bfreelist = NULL; } + memset(tmd, 0, sizeof (tmd_cmd_t)); /* * Set the local flags to BUSY. Also set the flags @@ -2040,13 +2107,13 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) switch (aep->at_cmnd.fcp_cmnd_alen_datadir & FCP_CMND_DATA_DIR_MASK) { case FCP_CMND_DATA_WRITE: - tmd->cd_lflags |= CDFL_DATA_OUT; + tmd->cd_flags |= CDF_DATA_OUT; break; case FCP_CMND_DATA_READ: - tmd->cd_lflags |= CDFL_DATA_IN; + tmd->cd_flags |= CDF_DATA_IN; break; case FCP_CMND_DATA_READ|FCP_CMND_DATA_WRITE: - tmd->cd_lflags |= CDFL_BIDIR; + tmd->cd_flags |= CDF_BIDIR; isp_prt(isp, ISP_LOGINFO, "FCP_CMND_IU with both read/write set"); break; default: @@ -2063,26 +2130,20 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) /* XXX: bus/vpidx not known at this level! */ AT2_MAKE_TAGID(tmd->cd_tagval, 0, 0, aep); tmd->cd_hba = isp; - tmd->cd_data = NULL; - tmd->cd_hflags = 0; - tmd->cd_resid = 0; - tmd->cd_xfrlen = 0; - tmd->cd_error = 0; - tmd->cd_scsi_status = 0; tmd->cd_oxid = aep->at_hdr.ox_id; if ((isp->isp_dblev & ISP_LOGTDEBUG0) || isp->isp_osinfo.hcb == 0) { const char *sstr; - switch (tmd->cd_lflags & CDFL_BIDIR) { + switch (tmd->cd_flags & CDF_BIDIR) { default: sstr = "nodatadir"; break; - case CDFL_DATA_OUT: + case CDF_DATA_OUT: sstr = "DATA OUT"; break; - case CDFL_DATA_IN: + case CDF_DATA_IN: sstr = "DATA IN"; break; - case CDFL_DATA_OUT|CDFL_DATA_IN: + case CDF_DATA_OUT|CDF_DATA_IN: sstr = "BIDIR"; break; } @@ -2104,77 +2165,14 @@ isp_handle_platform_atio7(ispsoftc_t *isp, at7_entry_t *aep) } if (isp->isp_osinfo.hcb == 0) { - tmd->cd_next = NULL; - if (isp->isp_osinfo.tfreelist) { - isp->isp_osinfo.bfreelist->cd_next = tmd; - } else { - isp->isp_osinfo.tfreelist = tmd; - } - isp->isp_osinfo.bfreelist = tmd; - if (tmd->cd_cdb[0] == INQUIRY && lun == 0) { - if (tmd->cd_cdb[1] == 0 && tmd->cd_cdb[2] == 0 && tmd->cd_cdb[3] == 0 && tmd->cd_cdb[5] == 0) { - struct scatterlist *dp; - int amt, idx; - - idx = tmd - isp->isp_osinfo.pool; - dp = &isp->isp_osinfo.dpwrk[idx]; - MEMZERO(dp, sizeof (*dp)); - dp->page = virt_to_page(isp->isp_osinfo.inqdata); - dp->offset = offset_in_page(isp->isp_osinfo.inqdata); - dp->length = DEFAULT_INQSIZE; - tmd->cd_xfrlen = min(DEFAULT_INQSIZE, tmd->cd_totlen); - tmd->cd_data = dp; - if ((amt = tmd->cd_cdb[4]) == 0) { - amt = 256; - } - if (tmd->cd_xfrlen > amt) { - tmd->cd_xfrlen = amt; - } - tmd->cd_resid = tmd->cd_totlen; - tmd->cd_hflags |= CDFH_DATA_IN|CDFH_STSVALID; - tmd->cd_lflags |= CDFL_LCL; - ISP_DROP_LK_SOFTC(isp); - isp_target_start_ctio(isp, tmd); - ISP_IGET_LK_SOFTC(isp); - return; - } else { - /* - * Illegal field in CDB - * 0x24 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK - */ - aep->at_hdr.seq_id = tmd->cd_nphdl; - isp_endcmd(isp, aep, 0x24005102, 0); - } - } else if (lun == 0) { - /* - * Not Ready, Cause Not Reportable - * - * 0x4 << 24 | 0x2 << 12 | ECMD_SVALID | SCSI_CHECK - */ - aep->at_hdr.seq_id = tmd->cd_nphdl; - isp_endcmd(isp, aep, 0x04002102, 0); - } else { - /* - * Logical Unit Not Supported: - * 0x25 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK - */ - aep->at_hdr.seq_id = tmd->cd_nphdl; - isp_endcmd(isp, aep, 0x25005102, 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; + isp_lcl_respond(isp, aep, tmd); return; } if (tmd->cd_iid == INI_ANY) { isp_prt(isp, ISP_LOGINFO, "[%llx] asking taskthread to find iid of initiator", tmd->cd_tagval); SEND_THREAD_EVENT(isp, ISP_THREAD_FINDIID, tmd, 0, __FUNCTION__, __LINE__); } else { - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_START); + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); } } @@ -2208,80 +2206,86 @@ isp_terminate_cmd(ispsoftc_t *isp, tmd_cmd_t *tmd) static void isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) { + tmd_xfr_t *xfr; tmd_cmd_t *tmd; - int sentstatus, ok, resid = 0, sts, id; + char *ctstr; + int sentstatus = 0, ok, resid = 0, id; + int status, flags; /* * CTIO, CTIO2, and CTIO7 are close enough.... */ - tmd = (tmd_cmd_t *) isp_find_xs_tgt(isp, ((ct_entry_t *)arg)->ct_syshandle); - if (tmd == NULL) { - isp_prt(isp, ISP_LOGERR, "isp_handle_platform_ctio: null tmd"); - return; - } - if (IS_24XX(isp)) { ct7_entry_t *ct = arg; + xfr = (tmd_xfr_t *) isp_find_xs_tgt(isp, ct->ct_syshandle); + if (xfr == NULL) { + isp_prt(isp, ISP_LOGERR, "isp_handle_platform_ctio: null xfr"); + return; + } + tmd = xfr->td_cmd; isp_destroy_tgt_handle(isp, ct->ct_syshandle); - sentstatus = ct->ct_flags & CT7_SENDSTATUS; - if (sentstatus) { - tmd->cd_lflags |= CDFL_SENTSTATUS; - } - sts = ct->ct_nphdl; - ok = sts == CT7_OK; - if (ok && sentstatus && (tmd->cd_hflags & CDFH_SNSVALID)) { - tmd->cd_lflags |= CDFL_SENTSENSE; - } - isp_prt(isp, ISP_LOGTDEBUG1, "CTIO7[%llx] sts 0x%x flg 0x%x sns %d %s", tmd->cd_tagval, ct->ct_nphdl, ct->ct_flags, - (tmd->cd_lflags & CDFL_SENTSENSE) != 0, sentstatus? "FIN" : "MID"); + status = ct->ct_nphdl; + flags = ct->ct_flags; + sentstatus = (flags & CT7_SENDSTATUS) != 0; + ok = status == CT7_OK; + ctstr = "CTIO7"; if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) { resid = ct->ct_resid; } id = ct->ct_iid_lo | (ct->ct_iid_hi << 16); } else if (IS_FC(isp)) { ct2_entry_t *ct = arg; + xfr = (tmd_xfr_t *) isp_find_xs_tgt(isp, ct->ct_syshandle); + if (xfr == NULL) { + isp_prt(isp, ISP_LOGERR, "isp_handle_platform_ctio: null xfr"); + return; + } + tmd = xfr->td_cmd; isp_destroy_tgt_handle(isp, ct->ct_syshandle); - sentstatus = ct->ct_flags & CT2_SENDSTATUS; - if (sentstatus) { - tmd->cd_lflags |= CDFL_SENTSTATUS; - } - sts = ct->ct_status & ~QLTM_SVALID; - ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; - if (ok && sentstatus && (tmd->cd_hflags & CDFH_SNSVALID)) { - tmd->cd_lflags |= CDFL_SENTSENSE; - } - isp_prt(isp, ISP_LOGTDEBUG1, "CTIO2[%llx] sts 0x%x flg 0x%x sns %d %s", tmd->cd_tagval, ct->ct_status, ct->ct_flags, - (tmd->cd_lflags & CDFL_SENTSENSE) != 0, sentstatus? "FIN" : "MID"); + status = ct->ct_status; + flags = ct->ct_flags; + sentstatus = (flags & CT2_SENDSTATUS) != 0; + ok = (status & ~QLTM_SVALID) == CT_OK; + ctstr = "CTIO2"; if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { resid = ct->ct_resid; } id = ct->ct_iid; } else { ct_entry_t *ct = arg; + xfr = (tmd_xfr_t *) isp_find_xs_tgt(isp, ct->ct_syshandle); + if (xfr == NULL) { + isp_prt(isp, ISP_LOGERR, "isp_handle_platform_ctio: null xfr"); + return; + } + tmd = xfr->td_cmd; isp_destroy_tgt_handle(isp, ct->ct_syshandle); - sts = ct->ct_status & ~QLTM_SVALID; - sentstatus = ct->ct_flags & CT_SENDSTATUS; - if (sentstatus) { - tmd->cd_lflags |= CDFL_SENTSTATUS; - } - ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; - if (ok && sentstatus && (tmd->cd_hflags & CDFH_SNSVALID)) { - tmd->cd_lflags |= CDFL_SENTSENSE; - } - isp_prt(isp, ISP_LOGTDEBUG1, "CTIO[%llx] loopid 0x%x tgt %d lun %d sts 0x%x flg %x %s", tmd->cd_tagval, ct->ct_iid, ct->ct_tgt, ct->ct_lun, - ct->ct_status, ct->ct_flags, sentstatus? "FIN" : "MID"); + status = ct->ct_status; + flags = ct->ct_flags; + sentstatus = (flags & CT_SENDSTATUS) != 0; + ok = (status & ~QLTM_SVALID) == CT_OK; + ctstr = "CTIO"; if (ct->ct_status & QLTM_SVALID) { char *sp = (char *)ct; sp += CTIO_SENSE_OFFSET; MEMCPY(tmd->cd_sense, sp, QLTM_SENSELEN); - tmd->cd_lflags |= CDFL_SNSVALID; + xfr->td_lflags |= CDF_SNSVALID; } if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { resid = ct->ct_resid; } id = ct->ct_iid; } - tmd->cd_resid += resid; + if (sentstatus) { + xfr->td_lflags |= TDFL_SENTSTATUS; + } + if (ok && sentstatus && (xfr->td_hflags & TDFH_SNSVALID)) { + xfr->td_lflags |= TDFL_SENTSENSE; + } + + tmd->cd_moved -= resid; + + isp_prt(isp, ISP_LOGTDEBUG0, "%s[%llx] status 0x%x flg 0x%x %s", ctstr, tmd->cd_tagval, status, flags, sentstatus? "FIN" : "MID"); /* * We're here either because intermediate data transfers are done @@ -2292,7 +2296,7 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) * what to do next, so all we do here is collect status and * pass information along. */ - isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO done (resid %d)", (sentstatus)? " FINAL " : "MIDTERM ", tmd->cd_resid); + isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO done (moved %u)", (sentstatus)? " FINAL " : "MIDTERM ", tmd->cd_moved); if (!ok) { const char *cx; @@ -2303,23 +2307,20 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) } else { cx = "O"; } - if (sts == CT_ABORTED) { + if ((status & ~QLTM_SVALID) == CT_ABORTED) { isp_prt(isp, ISP_LOGINFO, "[%llx] CTI%s aborted", tmd->cd_tagval, cx); tmd->cd_lflags |= CDFL_ABORTED; - } else if (sts == CT_LOGOUT) { + } else if ((status & QLTM_SVALID) == CT_LOGOUT) { isp_prt(isp, ISP_LOGINFO, "[%llx] CTI%s killed by Port Logout", tmd->cd_tagval, cx); } else { - isp_prt(isp, ISP_LOGINFO, "[%llx] CTI%s ended with badstate (0x%x)", tmd->cd_tagval, cx, sts); + isp_prt(isp, ISP_LOGINFO, "[%llx] CTI%s ended with badstate (0x%x)", tmd->cd_tagval, cx, status); } - tmd->cd_lflags |= CDFL_ERROR|CDFL_CALL_CMPLT; - tmd->cd_error = -EIO; + xfr->td_error = -EIO; if (isp_target_putback_atio(isp, tmd)) { tmd->cd_lflags |= CDFL_RESRC_FILL; - isp_complete_ctio(isp, tmd); } - if (sts == CT_LOGOUT) { + if ((status & ~QLTM_SVALID) == CT_LOGOUT) { int i; - for (i = 0; i < MAX_FC_TARG; i++) { if (FCPARAM(isp)->portdb[i].state != FC_PORTDB_STATE_VALID) { continue; @@ -2337,9 +2338,8 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) break; } } - } else { - isp_complete_ctio(isp, tmd); } + isp_complete_ctio(isp, xfr); } static int @@ -2351,9 +2351,6 @@ isp_target_putback_atio(ispsoftc_t *isp, tmd_cmd_t *tmd) tmd->cd_lflags &= ~CDFL_RESRC_FILL; if (IS_24XX(isp)) { - if (tmd->cd_lflags & CDFL_CALL_CMPLT) { - isp_complete_ctio(isp, tmd); - } return (0); } if (isp_getrqentry(isp, &nxti, NULL, &qe)) { @@ -2394,20 +2391,17 @@ isp_target_putback_atio(ispsoftc_t *isp, tmd_cmd_t *tmd) } ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe); ISP_ADD_REQUEST(isp, nxti); - if (tmd->cd_lflags & CDFL_CALL_CMPLT) { - isp_complete_ctio(isp, tmd); - } return (0); } static void -isp_complete_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) +isp_complete_ctio(ispsoftc_t *isp, tmd_xfr_t *xfr) { + tmd_cmd_t *tmd = xfr->td_cmd; isp->isp_osinfo.cmds_completed++; - tmd->cd_lflags &= ~CDFL_CALL_CMPLT; if (isp->isp_osinfo.hcb || (tmd->cd_lflags & CDFL_LCL)) { if (isp->isp_osinfo.hcb == 0) { - isp_prt(isp, ISP_LOGWARN, "nobody to tell about CTIO complete"); + isp_prt(isp, ISP_LOGWARN, "nobody to tell about CTIO complete, leaking xfr structure"); MEMZERO(tmd, TMD_SIZE); if (isp->isp_osinfo.tfreelist) { isp->isp_osinfo.bfreelist->cd_next = tmd; @@ -2416,50 +2410,28 @@ isp_complete_ctio(ispsoftc_t *isp, tmd_cmd_t *tmd) } isp->isp_osinfo.bfreelist = tmd; } else { - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_DONE); + CALL_PARENT_XFR(isp, xfr); } } } int -isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t lun) +isp_enable_lun(ispsoftc_t *isp, uint16_t bus, uint64_t tgt, uint16_t lun) { DECLARE_MUTEX_LOCKED(rsem); uint16_t rstat; - int rv, enabled, cmd; + int rv, cmd; unsigned long flags; - /* - * First, we can't do anything unless we have an upper - * level target driver to route commands to. - */ - if (isp->isp_osinfo.hcb == 0) { - return (-EINVAL); - } /* - * Second, check for sanity of enable argument. + * Check to see if we're enabling on fibre channel and make sure we have target role set up. */ - enabled = ((isp->isp_osinfo.tmflags & (1 << bus)) != 0); - if (enable == 0 && enabled == 0) { - return (-EINVAL); - } - - if (IS_24XX(isp) && lun != LUN_ANY) { - isp_prt(isp, ISP_LOGTDEBUG0, "can only do wildcard luns for 24XX cards"); - lun = LUN_ANY; - } - - /* - * Third, check to see if we're enabling on fibre channel - * and don't yet have a notion of who the heck we are (no - * loop yet). - */ - if (IS_FC(isp) && enable && !enabled) { + if (IS_FC(isp)) { ISP_LOCK_SOFTC(isp); if ((isp->isp_role & ISP_ROLE_TARGET) == 0) { isp->isp_role |= ISP_ROLE_TARGET; - if (isp_drain_reset(isp, "lun enables")) { + if (isp_drain_reset(isp, "lun enable")) { ISP_UNLK_SOFTC(isp); return (-EIO); } @@ -2481,15 +2453,6 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t } } - /* - * Do some sanity checking on lun arguments. - */ - if (lun != LUN_ANY) { - if (lun >= (IS_FC(isp)? TM_MAX_LUN_FC : TM_MAX_LUN_SCSI)) { - return (-EINVAL); - } - } - /* * Snag the semaphore on the return state value on enables/disables. */ @@ -2497,22 +2460,29 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t return (-EINTR); } - if (lun == LUN_ANY) { - if (enable && LUN_BTST(isp, bus, 0)) { + /* + * If this lun is enabled on this bus already, that's an error. + */ + if (lunenabled(isp, bus, lun)) { + up(&isp->isp_osinfo.tgt_inisem); + return (-EEXIST); + } + + + /* + * If this bus is wildcarded, we don't allow any further cations. + */ + if (lun != LUN_ANY) { + if (lunenabled(isp, bus, LUN_ANY)) { up(&isp->isp_osinfo.tgt_inisem); return (-EEXIST); } - } else { - if (enable && LUN_BTST(isp, bus, lun)) { - up(&isp->isp_osinfo.tgt_inisem); - return (-EEXIST); - } - if (!enable && !LUN_BTST(isp, bus, lun)) { - up(&isp->isp_osinfo.tgt_inisem); - return (-ENODEV); - } } - if (enable && nolunsenabled(isp, bus)) { + + /* + * If this is the first lun being enabled for this bus, tell the chip to be in target mode. + */ + if (nolunsenabled(isp, bus)) { int av = (bus << 31) | ENABLE_TARGET_FLAG; ISP_LOCK_SOFTC(isp); rv = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); @@ -2527,8 +2497,7 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t isp->isp_osinfo.rsemap = &rsem; if (IS_24XX(isp)) { rstat = LUN_OK; - } else if (enable) { - uint32_t seq = isp->isp_osinfo.rollinfo++; + } else { int n, ulun = lun; cmd = RQSTYPE_ENABLE_LUN; @@ -2543,11 +2512,10 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t * (enabling or modifying) lun 0. */ ulun = 0; - isp->isp_osinfo.wildcarded = 1; } } rstat = LUN_ERR; - if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, DFLT_CMND_CNT, n, seq)) { + if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, DFLT_CMND_CNT, n, 0)) { isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); goto out; } @@ -2560,12 +2528,85 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t isp_prt(isp, ISP_LOGERR, "MODIFY/ENABLE LUN returned 0x%x", rstat); goto out; } + } +out: + ISP_UNLK_SOFTC(isp); + if (rstat != LUN_OK) { + isp_prt(isp, ISP_LOGERR, "lun %u enable failed", lun); + up(&isp->isp_osinfo.tgt_inisem); + return (-EIO); + } + if (addlun(isp, bus, lun)) { + isp_prt(isp, ISP_LOGERR, "failed to add lun %u", lun); + up(&isp->isp_osinfo.tgt_inisem); + return (-EIO); + } + if (lun == LUN_ANY) { + isp_prt(isp, ISP_LOGINFO, "All luns now enabled for target mode on channel %d", bus); + } else { + isp_prt(isp, ISP_LOGINFO, "lun %u now disabled for target mode on channel %d", lun, bus); + } + + /* + * Make sure we stay resident while we have a lun enabled + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + /* + * Stay loaded while we have any enabled luns + */ + MOD_INC_USE_COUNT; +#else + if (try_module_get(isp->isp_osinfo.host->hostt->module)) { + isp->isp_osinfo.isget = 1; + } else { + isp->isp_osinfo.isget = 0; + } +#endif + up(&isp->isp_osinfo.tgt_inisem); + return (0); +} + +int +isp_disable_lun(ispsoftc_t *isp, uint16_t bus, uint64_t tgt, uint16_t lun) +{ + DECLARE_MUTEX_LOCKED(rsem); + uint16_t rstat; + int rv, cmd; + unsigned long flags; + + /* + * If this is a wildcard target, select our initiator + * id/loop id for use as what we enable as. + */ + + if (tgt == TGT_ANY) { + if (IS_FC(isp)) { + tgt = ((fcparam *)isp->isp_param)->isp_loopid; + } else { + tgt = ((sdparam *)isp->isp_param)->isp_initiator_id; + } + } + + + /* + * Snag the semaphore on the return state value on enables/disables. + */ + if (down_interruptible(&isp->isp_osinfo.tgt_inisem)) { + return (-EINTR); + } + + if (lunenabled(isp, bus, lun) == 0) { + up(&isp->isp_osinfo.tgt_inisem); + return (-ENODEV); + } + ISP_LOCK_SOFTC(isp); + isp->isp_osinfo.rsemap = &rsem; + if (IS_24XX(isp)) { + rstat = LUN_OK; } else { int n, ulun = lun; - uint32_t seq; rstat = LUN_ERR; - seq = isp->isp_osinfo.rollinfo++; cmd = -RQSTYPE_MODIFY_LUN; n = DFLT_INOT_CNT; @@ -2577,7 +2618,7 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t */ ulun = 0; } - if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, DFLT_CMND_CNT, n, seq)) { + if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, DFLT_CMND_CNT, n, 0)) { isp_prt(isp, ISP_LOGINFO, "isp_lun_cmd failed"); /* but proceed anyway */ rstat = LUN_OK; @@ -2596,12 +2637,11 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t if (IS_FC(isp) && lun) { goto out; } - seq = isp->isp_osinfo.rollinfo++; isp->isp_osinfo.rsemap = &rsem; rstat = LUN_ERR; cmd = -RQSTYPE_ENABLE_LUN; - if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) { + if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, 0)) { isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); goto out; } @@ -2617,69 +2657,49 @@ isp_en_dis_lun(ispsoftc_t *isp, int enable, uint16_t bus, uint64_t tgt, uint16_t } } out: - + ISP_UNLK_SOFTC(isp); if (rstat != LUN_OK) { - isp_prt(isp, ISP_LOGERR, "lun %d %sable failed", lun, (enable) ? "en" : "dis"); - ISP_UNLK_SOFTC(isp); - up(&isp->isp_osinfo.tgt_inisem); - return (-EIO); + isp_prt(isp, ISP_LOGERR, "lun %u disable failed", lun); + /* but continue anyway */ + } + remlun(isp, bus, lun); + if (lun == LUN_ANY) { + isp_prt(isp, ISP_LOGINFO, "All luns now disabled for target mode on channel %d", bus); } else { - if (lun == LUN_ANY) { - isp_prt(isp, ISP_LOGINFO, "All luns now %sabled for target mode on channel %d", (enable)? "en" : "dis", bus); - } else { - isp_prt(isp, ISP_LOGINFO, "lun %d now %sabled for target mode on channel %d", lun, (enable)? "en" : "dis", bus); + isp_prt(isp, ISP_LOGINFO, "lun %u now disabled for target mode on channel %d", lun, bus); + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + MOD_DEC_USE_COUNT; +#else + if (isp->isp_osinfo.isget) { + isp->isp_osinfo.isget = 0; + module_put(isp->isp_osinfo.host->hostt->module); + } +#endif + if (nolunsenabled(isp, bus)) { + int av = bus << 31; + ISP_LOCK_SOFTC(isp); + rv = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); + ISP_UNLK_SOFTC(isp); + if (rv) { + isp_prt(isp, ISP_LOGERR, "failed to disable target mode on channel %d", bus); + /* but proceed anyway */ } - if (enable == 0) { - if (isp->isp_osinfo.wildcarded) { - LUN_BCLR(isp, bus, 0); - } else { - LUN_BCLR(isp, bus, lun); - } - if (nolunsenabled(isp, bus)) { - int av = bus << 31; - rv = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); - if (rv) { - isp_prt(isp, ISP_LOGERR, "failed to disable target mode on channel %d", bus); - /* but proceed anyway */ - } - if (isp->isp_osinfo.isget) { - isp->isp_osinfo.isget = 0; + isp->isp_role &= ~ISP_ROLE_TARGET; + if (IS_FC(isp)) { + ISP_LOCK_SOFTC(isp); + if (isp_drain_reset(isp, "lun disables") == 0) { + if ((isp->isp_role & ISP_ROLE_INITIATOR) != 0) { ISP_UNLK_SOFTC(isp); - module_put(isp->isp_osinfo.host->hostt->module); + SEND_THREAD_EVENT(isp, ISP_THREAD_FC_RESCAN, NULL, 0, __FUNCTION__, __LINE__); ISP_LOCK_SOFTC(isp); } - isp->isp_osinfo.tmflags &= ~(1 << bus); - isp->isp_role &= ~ISP_ROLE_TARGET; - if (IS_FC(isp)) { - if (isp_drain_reset(isp, "lun disables") == 0) { - if ((isp->isp_role & ISP_ROLE_INITIATOR) != 0) { - ISP_UNLK_SOFTC(isp); - SEND_THREAD_EVENT(isp, ISP_THREAD_FC_RESCAN, NULL, 1, __FUNCTION__, __LINE__); - ISP_LOCK_SOFTC(isp); - } - } - } } - } else { ISP_UNLK_SOFTC(isp); - if (try_module_get(isp->isp_osinfo.host->hostt->module)) { - ISP_LOCK_SOFTC(isp); - isp->isp_osinfo.isget = 1; - } else { - ISP_LOCK_SOFTC(isp); - isp->isp_osinfo.isget = 0; - } - isp->isp_osinfo.tmflags |= (1 << bus); - if (isp->isp_osinfo.wildcarded) { - LUN_BSET(isp, bus, 0); - } else { - LUN_BSET(isp, bus, lun); - } } - ISP_UNLK_SOFTC(isp); - up(&isp->isp_osinfo.tgt_inisem); - return (0); } + up(&isp->isp_osinfo.tgt_inisem); + return (0); } #endif @@ -4110,7 +4130,7 @@ isp_task_thread(void *arg) tmd->cd_iid = lp->port_wwn; tmd->cd_nphdl = lp->handle; isp_prt(isp, ISP_LOGINFO, "%s: [%llx] found iid (0x%016llx)-sending upstream", __FUNCTION__, tmd->cd_tagval, (unsigned long long)tmd->cd_iid); - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_START); + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); ISP_UNLKU_SOFTC(isp); isp_tgt_tq(isp); break; @@ -4130,7 +4150,7 @@ isp_task_thread(void *arg) tmd->cd_iid = wwn; isp_prt(isp, ISP_LOGINFO, "[%llx] found iid (0x%016llx) via GET_PORT_NAME- sending upstream", tmd->cd_tagval, (unsigned long long) tmd->cd_iid); - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_START); + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); ISP_UNLKU_SOFTC(isp); isp_tgt_tq(isp); } @@ -4148,7 +4168,7 @@ isp_task_thread(void *arg) if (isp_find_pdb_sid(isp, tmd->cd_portid, &lp)) { tmd->cd_iid = lp->port_wwn; tmd->cd_nphdl = lp->handle; - CALL_PARENT_TARGET(isp, tmd, QOUT_TMD_START); + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); ISP_UNLKU_SOFTC(isp); isp_tgt_tq(isp); break; @@ -4194,13 +4214,13 @@ isp_task_thread(void *arg) break; } if (tmd->cd_lflags & CDFL_NEED_CLNUP) { - tmd->cd_lflags &= ~CDFL_NEED_CLNUP; + tmd->cd_lflags ^= CDFL_NEED_CLNUP; (void) isp_terminate_cmd(isp, tmd); } tmd->cd_hba = NULL; - tmd->cd_lflags = 0; + tmd->cd_flags = 0; tmd->cd_next = NULL; - /* don't zero cd_hflags or cd_tagval- it may be being used to catch duplicate frees */ + /* don't zero cd_lflags or cd_tagval- it may be being used to catch duplicate frees */ if (isp->isp_osinfo.tfreelist) { isp->isp_osinfo.bfreelist->cd_next = tmd; } else { diff --git a/qla_isp/linux/isp_linux.h b/qla_isp/linux/isp_linux.h index 8ce7f4ba3..c1ca39d55 100644 --- a/qla_isp/linux/isp_linux.h +++ b/qla_isp/linux/isp_linux.h @@ -1,4 +1,4 @@ -/* $Id: isp_linux.h,v 1.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; diff --git a/qla_isp/linux/isp_pci.c b/qla_isp/linux/isp_pci.c index 8a41d2a0c..d89fdb625 100644 --- a/qla_isp/linux/isp_pci.c +++ b/qla_isp/linux/isp_pci.c @@ -1,4 +1,4 @@ -/* $Id: isp_pci.c,v 1.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, ""); @@ -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, ""); + /* * 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, ""); 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, ""); + 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, ""); 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 diff --git a/qla_isp/linux/isp_scst.c b/qla_isp/linux/isp_scst.c index ea6ffd4dc..fe7f4bfe6 100644 --- a/qla_isp/linux/isp_scst.c +++ b/qla_isp/linux/isp_scst.c @@ -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); } diff --git a/qla_isp/linux/scsi_target.c b/qla_isp/linux/scsi_target.c index f4aa090ee..2404d93b5 100644 --- a/qla_isp/linux/scsi_target.c +++ b/qla_isp/linux/scsi_target.c @@ -1,4 +1,4 @@ -/* $Id: scsi_target.c,v 1.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 #ifndef KERNEL_VERSION #define KERNEL_VERSION(v,p,s) (((v)<<16)+(p<<8)+s) #endif #include -#ifdef CONFIG_SMP -#define __SMP__ 1 -#endif - #include #include #include @@ -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); }