MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
+/* Set string for command line args from insmod */
#ifdef MODULE
-static int dv = MPTSCSIH_DOMAIN_VALIDATION;
-module_param(dv, int, 0);
-MODULE_PARM_DESC(dv, "DV Algorithm: enhanced = 1, basic = 0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)");
-
-static int width = MPTSCSIH_MAX_WIDTH;
-module_param(width, int, 0);
-MODULE_PARM_DESC(width, "Max Bus Width: wide = 1, narrow = 0 (default=MPTSCSIH_MAX_WIDTH=1)");
-
-static ushort factor = MPTSCSIH_MIN_SYNC;
-module_param(factor, ushort, 0);
-MODULE_PARM_DESC(factor, "Min Sync Factor: (default=MPTSCSIH_MIN_SYNC=0x08)");
-
-static int saf_te = MPTSCSIH_SAF_TE;
-module_param(saf_te, int, 0);
-MODULE_PARM_DESC(saf_te, "Force enabling SEP Processor: (default=MPTSCSIH_SAF_TE=0)");
+char *mptscsih = NULL;
+MODULE_PARM(mptscsih, "s");
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
#endif
+#ifdef MODULE
+static int mptscsih_setup(char *str);
+#endif
/* module entry point */
static int __init mptscsih_init (void);
static void __exit mptscsih_exit (void);
static int scandv_wait_done = 1;
-/* Driver command line structure
+/* Driver default setup
*/
-static struct mptscsih_driver_setup driver_setup;
+static struct mptscsih_driver_setup
+ driver_setup = MPTSCSIH_DRIVER_SETUP;
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+static struct scsi_cmnd *foo_to[8];
+#endif
+
static struct scsi_host_template driver_template;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
ioc->name));
spin_lock_irqsave(&ioc->FreeQlock, flags);
- if (!list_empty(&ioc->FreeChainQ)) {
+ if (!Q_IS_EMPTY(&ioc->FreeChainQ)) {
+
int offset;
- chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
- u.frame.linkage.list);
- list_del(&chainBuf->u.frame.linkage.list);
+ chainBuf = ioc->FreeChainQ.head;
+ Q_DEL_ITEM(&chainBuf->u.frame.linkage);
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
chain_idx = offset / ioc->req_sz;
rc = SUCCESS;
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
ioc->name, *retIndex, chainBuf));
- } else {
+ }
+ else {
rc = FAILED;
chain_idx = MPT_HOST_NO_CHAIN;
dfailprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
*retIndex = chain_idx;
+
return rc;
} /* mptscsih_getFreeChainBuffer() */
pScsiReq = (SCSIIORequest_t *) mf;
pScsiReply = (SCSIIOReply_t *) mr;
+#ifdef MPTSCSIH_DBG_TIMEOUT
+ if (ioc->timeout_cnt > 0) {
+ int ii, left = 0;
+
+ for (ii=0; ii < 8; ii++) {
+ if (sc == foo_to[ii]) {
+ printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n",
+ ioc->name, sc, jiffies);
+ foo_to[ii] = NULL;
+ }
+ if (foo_to[ii] != NULL)
+ left++;
+ }
+
+ if (left == 0) {
+ ioc->timeout_maxcnt = 0;
+ ioc->timeout_cnt = 0;
+ }
+ }
+#endif
+
if (pScsiReply == NULL) {
/* special context reply handling */
;
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
- sc->resid = sc->request_bufflen - xfer_cnt;
- dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
- "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
- "resid=%d bufflen=%d xfer_cnt=%d\n",
- ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
- status, scsi_state, scsi_status, sc->resid,
- sc->request_bufflen, xfer_cnt));
+ dreplyprintk((KERN_NOTICE " Reply (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
+ ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
+ mf, mr, sc));
+ dreplyprintk((KERN_NOTICE "IOCStatus=%04xh SCSIState=%02xh"
+ " SCSIStatus=%02xh xfer_cnt=%08xh\n",
+ status, scsi_state, scsi_status, xfer_cnt));
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
copy_sense_data(sc, hd, mf, pScsiReply);
sc->result = DID_RESET << 16;
/* GEM Workaround. */
- if (ioc->bus_type == SCSI)
+ if (hd->is_spi)
mptscsih_no_negotiate(hd, sc->device->id);
break;
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
+ sc->resid = sc->request_bufflen - xfer_cnt;
if ( xfer_cnt >= sc->underflow ) {
/* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
*/
;
} else {
- if (xfer_cnt < sc->underflow) {
+ if ( (xfer_cnt == 0) || (sc->underflow > xfer_cnt)) {
sc->result = DID_SOFT_ERROR << 16;
}
if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
}
}
+ /* Give report and update residual count.
+ */
dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
sc->underflow));
dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
+
+ sc->resid = sc->request_bufflen - xfer_cnt;
+ dreplyprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid));
+
/* Report Queue Full
*/
if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
break;
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
- sc->result = DID_SOFT_ERROR << 16;
+ sc->result = DID_SOFT_ERROR << 16;
break;
case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
* max_lun = 1 + actual last lun,
* see hosts.h :o(
*/
- if (ioc->bus_type == SCSI) {
+ if ((int)ioc->chip_type > (int)FC929) {
sh->max_id = MPT_MAX_SCSI_DEVICES;
} else {
/* For FC, increase the queue depth
hd = (MPT_SCSI_HOST *) sh->hostdata;
hd->ioc = ioc;
+ if ((int)ioc->chip_type > (int)FC929)
+ hd->is_spi = 1;
+
+ if (DmpService && (ioc->chip_type == FC919 ||
+ ioc->chip_type == FC929)) {
+ hd->is_multipath = 1;
+ }
+
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
ioc->name, hd->ScsiLookup, sz));
+ /* Initialize this Scsi_Host
+ * internal task Q.
+ */
+ Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
+ hd->taskQcnt = 0;
+
/* Allocate memory for the device structures.
* A non-Null pointer at an offset
* indicates a device exists.
/* Moved Earlier Pam D */
/* ioc->sh = sh; */
- if (ioc->bus_type == SCSI) {
+#ifdef MPTSCSIH_DBG_TIMEOUT
+ ioc->timeout_hard = 0;
+ ioc->timeout_delta = 30 * HZ;
+ ioc->timeout_maxcnt = 0;
+ ioc->timeout_cnt = 0;
+ for (ii=0; ii < 8; ii++)
+ foo_to[ii] = NULL;
+#endif
+ if (hd->is_spi) {
/* Update with the driver setup
* values.
*/
}
if (ioc->spi_data.minSyncFactor <
- driver_setup.min_sync_factor) {
+ driver_setup.min_sync_fac) {
ioc->spi_data.minSyncFactor =
- driver_setup.min_sync_factor;
+ driver_setup.min_sync_fac;
}
if (ioc->spi_data.minSyncFactor == MPT_ASYNC) {
"dv %x width %x factor %x saf_te %x\n",
ioc->name, driver_setup.dv,
driver_setup.max_width,
- driver_setup.min_sync_factor,
+ driver_setup.min_sync_fac,
driver_setup.saf_te));
}
hd = (MPT_SCSI_HOST *)host->hostdata;
if (hd != NULL) {
- int sz1;
+ int sz1, sz3, sztarget=0;
mptscsih_shutdown(&pdev->dev);
- sz1=0;
+ sz1 = sz3 = 0;
if (hd->ScsiLookup != NULL) {
sz1 = hd->ioc->req_depth * sizeof(void *);
}
if (hd->Targets != NULL) {
+ int max, ii;
+
+ /*
+ * Free any target structures that were allocated.
+ */
+ if (hd->is_spi) {
+ max = MPT_MAX_SCSI_DEVICES;
+ } else {
+ max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+ }
+ for (ii=0; ii < max; ii++) {
+ if (hd->Targets[ii]) {
+ kfree(hd->Targets[ii]);
+ hd->Targets[ii] = NULL;
+ sztarget += sizeof(VirtDevice);
+ }
+ }
+
/*
* Free pointer array.
*/
+ sz3 = max * sizeof(void *);
kfree(hd->Targets);
hd->Targets = NULL;
}
dprintk((MYIOC_s_INFO_FMT
- "Free'd ScsiLookup (%d) memory\n",
- hd->ioc->name, sz1));
+ "Free'd ScsiLookup (%d) Target (%d+%d) memory\n",
+ hd->ioc->name, sz1, sz3, sztarget));
+ dprintk(("Free'd done and free Q (%d) memory\n", szQ));
/* NULL the Scsi_Host pointer
*/
}
#ifdef MODULE
- dinitprintk((KERN_INFO MYNAM
- ": Command Line Args: dv=%d max_width=%d "
- "factor=0x%x saf_te=%d\n",
- dv, width, factor, saf_te));
-
- driver_setup.dv = (dv) ? 1 : 0;
- driver_setup.max_width = (width) ? 1 : 0;
- driver_setup.min_sync_factor = factor;
- driver_setup.saf_te = (saf_te) ? 1 : 0;;
+ /* Evaluate the command line arguments, if any */
+ if (mptscsih)
+ mptscsih_setup(mptscsih);
#endif
if(mpt_device_driver_register(&mptscsih_driver,
return ((info.pos > info.offset) ? info.pos - info.offset : 0);
}
+#ifndef MPTSCSIH_DBG_TIMEOUT
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len)
+{
+ /* Not yet implemented */
+ return len;
+}
+#else
+#define is_digit(c) ((c) >= '0' && (c) <= '9')
+#define digit_to_bin(c) ((c) - '0')
+#define is_space(c) ((c) == ' ' || (c) == '\t')
+
+#define UC_DBG_TIMEOUT 0x01
+#define UC_DBG_HARDRESET 0x02
+
+static int skip_spaces(char *ptr, int len)
+{
+ int cnt, c;
+
+ for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
+
+ return (len - cnt);
+}
+
+static int get_int_arg(char *ptr, int len, ulong *pv)
+{
+ int cnt, c;
+ ulong v;
+ for (v = 0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) {
+ v = (v * 10) + digit_to_bin(c);
+ }
+
+ if (pv)
+ *pv = v;
+
+ return (len - cnt);
+}
+
+
+static int is_keyword(char *ptr, int len, char *verb)
+{
+ int verb_len = strlen(verb);
+
+ if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+ return verb_len;
+ else
+ return 0;
+}
+
+#define SKIP_SPACES(min_spaces) \
+ if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \
+ return -EINVAL; \
+ ptr += arg_len; \
+ len -= arg_len;
+
+#define GET_INT_ARG(v) \
+ if (!(arg_len = get_int_arg(ptr,len, &(v)))) \
+ return -EINVAL; \
+ ptr += arg_len; \
+ len -= arg_len;
+
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length)
+{
+ char *ptr = buffer;
+ char btmp[24]; /* REMOVE */
+ int arg_len;
+ int len = length;
+ int cmd;
+ ulong number = 1;
+ ulong delta = 10;
+
+ if ((len > 0) && (ptr[len -1] == '\n'))
+ --len;
+
+ if (len < 22) {
+ strncpy(btmp, buffer, len);
+ btmp[len+1]='\0';
+ } else {
+ strncpy(btmp, buffer, 22);
+ btmp[23]='\0';
+ }
+ printk("user_command: ioc %d, buffer %s, length %d\n",
+ ioc->id, btmp, length);
+
+ if ((arg_len = is_keyword(ptr, len, "timeout")) != 0)
+ cmd = UC_DBG_TIMEOUT;
+ else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0)
+ cmd = UC_DBG_HARDRESET;
+ else
+ return -EINVAL;
+
+ ptr += arg_len;
+ len -= arg_len;
+
+ switch(cmd) {
+ case UC_DBG_TIMEOUT:
+ SKIP_SPACES(1);
+ GET_INT_ARG(number);
+ SKIP_SPACES(1);
+ GET_INT_ARG(delta);
+ break;
+ }
+
+ printk("user_command: cnt=%ld delta=%ld\n", number, delta);
+
+ if (len)
+ return -EINVAL;
+ else {
+ if (cmd == UC_DBG_HARDRESET) {
+ ioc->timeout_hard = 1;
+ } else if (cmd == UC_DBG_TIMEOUT) {
+ /* process this command ...
+ */
+ ioc->timeout_maxcnt = 0;
+ ioc->timeout_delta = delta < 2 ? 2 : delta;
+ ioc->timeout_cnt = 0;
+ ioc->timeout_maxcnt = number < 8 ? number: 8;
+ }
+ }
+ /* Not yet implemented */
+ return length;
+}
+#endif
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_proc_info - Return information about MPT adapter
* hostno: scsi host number
* func: if write = 1; if read = 0
*/
-static int
+static int
mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int func)
{
int size = 0;
if (func) {
- /*
- * write is not supported
- */
+ size = mptscsih_user_command(ioc, buffer, length);
} else {
if (start)
*start = buffer;
return size;
}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define ADD_INDEX_LOG(req_ent) do { } while(0)
u32 cmd_len;
int my_idx;
int ii;
+ int rc;
+ int did_errcode;
+ int issueCmd;
+ did_errcode = 0;
hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
target = SCpnt->device->id;
lun = SCpnt->device->lun;
/* Now add the SG list
* Always have a SGE even if null length.
*/
+ rc = SUCCESS;
if (datalen == 0) {
/* Add a NULL SGE */
mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
(dma_addr_t) -1);
} else {
/* Add a 32 or 64 bit SGE */
- if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
- goto fail;
+ rc = mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx);
}
- hd->ScsiLookup[my_idx] = SCpnt;
- SCpnt->host_scribble = NULL;
+
+ if (rc == SUCCESS) {
+ hd->ScsiLookup[my_idx] = SCpnt;
+ SCpnt->host_scribble = NULL;
+
+ /* SCSI specific processing */
+ issueCmd = 1;
+ if (hd->is_spi) {
+ int dvStatus = hd->ioc->spi_data.dvStatus[target];
+
+ if (dvStatus || hd->ioc->spi_data.forceDv) {
#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
- if (hd->ioc->bus_type == SCSI) {
- int dvStatus = hd->ioc->spi_data.dvStatus[target];
- int issueCmd = 1;
-
- if (dvStatus || hd->ioc->spi_data.forceDv) {
-
- if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
- (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
- unsigned long lflags;
- /* Schedule DV if necessary */
- spin_lock_irqsave(&dvtaskQ_lock, lflags);
- if (!dvtaskQ_active) {
- dvtaskQ_active = 1;
- spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
- INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
-
- schedule_work(&mptscsih_dvTask);
- } else {
- spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+ if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
+ (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
+ unsigned long lflags;
+ /* Schedule DV if necessary */
+ spin_lock_irqsave(&dvtaskQ_lock, lflags);
+ if (!dvtaskQ_active) {
+ dvtaskQ_active = 1;
+ spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+ INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
+
+ schedule_work(&mptscsih_dvTask);
+ } else {
+ spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+ }
+ hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
}
- hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
- }
- /* Trying to do DV to this target, extend timeout.
- * Wait to issue until flag is clear
- */
- if (dvStatus & MPT_SCSICFG_DV_PENDING) {
- mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
- issueCmd = 0;
- }
+ /* Trying to do DV to this target, extend timeout.
+ * Wait to issue until flag is clear
+ */
+ if (dvStatus & MPT_SCSICFG_DV_PENDING) {
+ mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
+ issueCmd = 0;
+ }
- /* Set the DV flags.
- */
- if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
- mptscsih_set_dvflags(hd, pScsiReq);
+ /* Set the DV flags.
+ */
+ if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
+ mptscsih_set_dvflags(hd, pScsiReq);
+#endif
+ }
+ }
- if (!issueCmd)
- goto fail;
+#ifdef MPTSCSIH_DBG_TIMEOUT
+ if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) {
+ foo_to[hd->ioc->timeout_cnt] = SCpnt;
+ hd->ioc->timeout_cnt++;
+ //mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta);
+ issueCmd = 0;
+ printk(MYIOC_s_WARN_FMT
+ "to pendingQ: (sc=%p, mf=%p, time=%ld)\n",
+ hd->ioc->name, SCpnt, mf, jiffies);
}
- }
#endif
- mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf);
- dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
- hd->ioc->name, SCpnt, mf, my_idx));
- DBG_DUMP_REQUEST_FRAME(mf)
+ if (issueCmd) {
+ mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf);
+ dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+ hd->ioc->name, SCpnt, mf, my_idx));
+ DBG_DUMP_REQUEST_FRAME(mf)
+ } else
+ goto fail;
+ } else
+ goto fail;
+
return 0;
fail:
chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
+ (chain_idx * ioc->req_sz));
-
spin_lock_irqsave(&ioc->FreeQlock, flags);
- list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
+ Q_ADD_TAIL(&ioc->FreeChainQ.head,
+ &chain->u.frame.linkage, MPT_FRAME_HDR);
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
}
}
+#ifdef MPTSCSIH_DBG_TIMEOUT
+ if (hd->ioc->timeout_hard)
+ rc = 1;
+#endif
+
/* Only fall through to the HRH if this is a bus reset
*/
if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
hd->ioc->name, SCpnt);
- /* Supported for FC only.
+ /* Unsupported for SCSI. Supported for FCP
*/
- if (hd->ioc->bus_type == SCSI)
+ if (hd->is_spi)
return FAILED;
spin_unlock_irq(host_lock);
if (hd->tmPtr) {
del_timer(&hd->TMtimer);
}
+ dtmprintk((MYIOC_s_WARN_FMT "taskQcnt (%d)\n",
+ ioc->name, hd->taskQcnt));
} else {
dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
ioc->name));
mptscsih_slave_alloc(struct scsi_device *device)
{
struct Scsi_Host *host = device->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd;
VirtDevice *vdev;
- uint target = device->id;
+
+ hd = (MPT_SCSI_HOST *)host->hostdata;
if (hd == NULL)
return -ENODEV;
- if ((vdev = hd->Targets[target]) != NULL)
- goto out;
-
- vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
- printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
- return -ENOMEM;
- }
-
- memset(vdev, 0, sizeof(VirtDevice));
- vdev->tflags = MPT_TARGET_FLAGS_Q_YES;
- vdev->ioc_id = hd->ioc->id;
- vdev->target_id = device->id;
- vdev->bus_id = device->channel;
- vdev->raidVolume = 0;
- hd->Targets[device->id] = vdev;
- if (hd->ioc->bus_type == SCSI) {
- if (hd->ioc->spi_data.isRaid & (1 << device->id)) {
- vdev->raidVolume = 1;
- ddvtprintk((KERN_INFO
- "RAID Volume @ id %d\n", device->id));
+ if ((vdev = hd->Targets[device->id]) == NULL) {
+ if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
+ printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%d) FAILED!\n",
+ hd->ioc->name, (int)sizeof(VirtDevice));
+ return -ENOMEM;
+ } else {
+ memset(vdev, 0, sizeof(VirtDevice));
+ rwlock_init(&vdev->VdevLock);
+ Q_INIT(&vdev->WaitQ, void);
+ Q_INIT(&vdev->SentQ, void);
+ Q_INIT(&vdev->DoneQ, void);
+ vdev->tflags = MPT_TARGET_FLAGS_Q_YES;
+ vdev->ioc_id = hd->ioc->id;
+ vdev->target_id = device->id;
+ vdev->bus_id = device->channel;
+ vdev->raidVolume = 0;
+ hd->Targets[device->id] = vdev;
+ if (hd->is_spi) {
+ if (hd->ioc->spi_data.isRaid & (1 << device->id)) {
+ vdev->raidVolume = 1;
+ ddvtprintk((KERN_INFO
+ "RAID Volume @ id %d\n", device->id));
+ }
+ } else {
+ vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+ }
}
- } else {
- vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
}
-
- out:
vdev->num_luns++;
- return 0;
-}
-
-static int mptscsih_is_raid_volume(MPT_SCSI_HOST *hd, uint id)
-{
- int i;
-
- if (!hd->ioc->spi_data.isRaid || !hd->ioc->spi_data.pIocPg3)
- return 0;
-
- for (i = 0; i < hd->ioc->spi_data.pIocPg3->NumPhysDisks; i++) {
- if (id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID)
- return 1;
- }
return 0;
}
mptscsih_slave_destroy(struct scsi_device *device)
{
struct Scsi_Host *host = device->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd;
VirtDevice *vdev;
- uint target = device->id;
- uint lun = device->lun;
+ int raid_volume=0;
+
+ hd = (MPT_SCSI_HOST *)host->hostdata;
if (hd == NULL)
return;
- mptscsih_search_running_cmds(hd, target, lun);
+ mptscsih_search_running_cmds(hd, device->id, device->lun);
- vdev = hd->Targets[target];
- vdev->luns[0] &= ~(1 << lun);
- if (--vdev->num_luns)
- return;
+ /* Free memory and reset all flags for this target
+ */
+ if ((vdev = hd->Targets[device->id]) != NULL) {
+ vdev->num_luns--;
- kfree(hd->Targets[target]);
- hd->Targets[target] = NULL;
-
- if (hd->ioc->bus_type == SCSI) {
- if (mptscsih_is_raid_volume(hd, target)) {
- hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
- } else {
- hd->ioc->spi_data.dvStatus[target] =
- MPT_SCSICFG_NEGOTIATE;
+ if (vdev->luns[0] & (1 << device->lun))
+ vdev->luns[0] &= ~(1 << device->lun);
+
+ /* Free device structure only if number of luns is 0.
+ */
+ if (vdev->num_luns == 0) {
+ kfree(hd->Targets[device->id]);
+ hd->Targets[device->id] = NULL;
+
+ if (!hd->is_spi)
+ return;
+
+ if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) {
+ int i;
+ for(i=0;i<hd->ioc->spi_data.pIocPg3->NumPhysDisks &&
+ raid_volume==0;i++)
- if (!hd->negoNvram) {
- hd->ioc->spi_data.dvStatus[target] |=
- MPT_SCSICFG_DV_NOT_DONE;
+ if(device->id ==
+ hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID) {
+ raid_volume=1;
+ hd->ioc->spi_data.forceDv |=
+ MPT_SCSICFG_RELOAD_IOC_PG3;
+ }
}
- }
- }
-}
-static void
-mptscsih_set_queue_depth(struct scsi_device *device, MPT_SCSI_HOST *hd,
- VirtDevice *pTarget, int qdepth)
-{
- int max_depth;
- int tagged;
+ if(!raid_volume){
+ hd->ioc->spi_data.dvStatus[device->id] =
+ MPT_SCSICFG_NEGOTIATE;
- if (hd->ioc->bus_type == SCSI) {
- if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
- if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
- max_depth = 1;
- else if (((pTarget->inq_data[0] & 0x1f) == 0x00) &&
- (pTarget->minSyncFactor <= MPT_ULTRA160 ))
- max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
- else
- max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
- } else {
- /* error case - No Inq. Data */
- max_depth = 1;
+ if (hd->negoNvram == 0)
+ hd->ioc->spi_data.dvStatus[device->id]
+ |= MPT_SCSICFG_DV_NOT_DONE;
+ }
}
- } else
- max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
-
- if (qdepth > max_depth)
- qdepth = max_depth;
- if (qdepth == 1)
- tagged = 0;
- else
- tagged = MSG_SIMPLE_TAG;
+ }
- scsi_adjust_queue_depth(device, tagged, qdepth);
+ return;
}
-
/*
* OS entry point to adjust the queue_depths on a per-device basis.
* Called once per device the bus scan. Use it to force the queue_depth
mptscsih_initTarget(hd, device->channel, device->id, device->lun,
device->inquiry, device->inquiry_len );
- mptscsih_set_queue_depth(device, hd, pTarget, MPT_SCSI_CMD_PER_DEV_HIGH);
+ scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+ MPT_SCSI_CMD_PER_DEV_HIGH);
+ if ( hd->is_spi ) {
+ if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+ if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+ scsi_adjust_queue_depth(device, 0, 1);
+ else if (((pTarget->inq_data[0] & 0x1f) == 0x00)
+ && (pTarget->minSyncFactor <= MPT_ULTRA160 ))
+ scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+ MPT_SCSI_CMD_PER_DEV_HIGH);
+ else
+ scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+ MPT_SCSI_CMD_PER_DEV_LOW);
+ } else {
+ /* error case - No Inq. Data */
+ scsi_adjust_queue_depth(device, 0, 1);
+ }
+ }
dsprintk((MYIOC_s_INFO_FMT
"Queue depth=%d, tflags=%x\n",
return 0;
}
-static ssize_t
-mptscsih_store_queue_depth(struct device *dev, const char *buf, size_t count)
-{
- int depth;
- struct scsi_device *sdev = to_scsi_device(dev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) sdev->host->hostdata;
- VirtDevice *pTarget;
-
- depth = simple_strtoul(buf, NULL, 0);
- if (depth == 0)
- return -EINVAL;
- pTarget = hd->Targets[sdev->id];
- if (pTarget == NULL)
- return -EINVAL;
- mptscsih_set_queue_depth(sdev, (MPT_SCSI_HOST *) sdev->host->hostdata,
- pTarget, depth);
- return count;
-}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
pReq = (SCSIIORequest_t *) mf;
index = (int) pReq->TargetID;
target = hd->Targets[index];
+ if (hd->is_multipath && sc->device->hostdata)
+ target = (VirtDevice *) sc->device->hostdata;
if (sense_count) {
u8 *sense_data;
mpt_free_msg_frame(ioc, hd->tmPtr);
}
+#ifdef MPTSCSIH_DBG_TIMEOUT
+ ioc->timeout_hard = 0;
+#endif
+
dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
} else {
/* 4. Renegotiate to all devices, if SCSI
*/
- if (ioc->bus_type == SCSI) {
+ if (hd->is_spi) {
dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
}
/* 7. Set flag to force DV and re-read IOC Page 3
*/
- if (ioc->bus_type == SCSI) {
+ if (hd->is_spi) {
ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
ddvtprintk(("Set reload IOC Pg3 Flag\n"));
}
hd = NULL;
if (ioc->sh) {
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
- if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1))
+ if (hd && (hd->is_spi) && (hd->soft_resets < -1))
hd->soft_resets++;
}
break;
if (ioc->sh)
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
- if (hd && (ioc->bus_type == SCSI) && (hd->negoNvram == 0)) {
+ if (hd && (hd->is_spi) && (hd->negoNvram == 0)) {
ScsiCfgData *pSpi;
Ioc3PhysDisk_t *pPDisk;
int numPDisk;
return 1; /* currently means nothing really */
}
-static struct device_attribute mptscsih_queue_depth_attr = {
- .attr = {
- .name = "queue_depth",
- .mode = S_IWUSR,
- },
- .store = mptscsih_store_queue_depth,
-};
-
-static struct device_attribute *mptscsih_dev_attrs[] = {
- &mptscsih_queue_depth_attr,
- NULL,
-};
-
static struct scsi_host_template driver_template = {
.proc_name = "mptscsih",
.proc_info = mptscsih_proc_info,
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
- .sdev_attrs = mptscsih_dev_attrs,
};
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
indexed_lun = (lun % 32);
vdev->luns[lun_index] |= (1 << indexed_lun);
- if (hd->ioc->bus_type == SCSI) {
+ if (hd->is_spi) {
if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
/* Treat all Processors as SAF-TE if
* command line option is set */
/* Write SDP1 for all SCSI devices
* Alloc memory and set up config buffer
*/
- if (ioc->bus_type == SCSI) {
+ if (hd->is_spi) {
if (ioc->spi_data.sdp1length > 0) {
pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
msleep(250);
/* DV only to SCSI adapters */
- if (ioc->bus_type != SCSI)
+ if ((int)ioc->chip_type <= (int)FC929)
continue;
/* Make sure everything looks ok */
#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Commandline Parsing routines and defines.
+ *
+ * insmod format:
+ * insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1"
+ * boot format:
+ * mptscsih=width:1,dv:n,factor:0x8,saf-te:1
+ *
+ */
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+#ifdef MODULE
+static char setup_token[] __initdata =
+ "dv:"
+ "width:"
+ "factor:"
+ "saf-te:"
+ ; /* DO NOT REMOVE THIS ';' */
+#endif
+
+#define OPT_DV 1
+#define OPT_MAX_WIDTH 2
+#define OPT_MIN_SYNC_FACTOR 3
+#define OPT_SAF_TE 4
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#ifdef MODULE
+static int
+get_setup_token(char *p)
+{
+ char *cur = setup_token;
+ char *pc;
+ int i = 0;
+
+ while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+ ++pc;
+ ++i;
+ if (!strncmp(p, cur, pc - cur))
+ return i;
+ cur = pc;
+ }
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_setup(char *str)
+{
+ char *cur = str;
+ char *pc, *pv;
+ unsigned long val;
+ int c;
+
+ while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+ char *pe;
+
+ val = 0;
+ pv = pc;
+ c = *++pv;
+
+ if (c == 'n')
+ val = 0;
+ else if (c == 'y')
+ val = 1;
+ else
+ val = (int) simple_strtoul(pv, &pe, 0);
+
+ printk("Found Token: %s, value %x\n", cur, (int)val);
+ switch (get_setup_token(cur)) {
+ case OPT_DV:
+ driver_setup.dv = val;
+ break;
+
+ case OPT_MAX_WIDTH:
+ driver_setup.max_width = val;
+ break;
+
+ case OPT_MIN_SYNC_FACTOR:
+ driver_setup.min_sync_fac = val;
+ break;
+
+ case OPT_SAF_TE:
+ driver_setup.saf_te = val;
+ break;
+
+ default:
+ printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+ break;
+ }
+
+ if ((cur = strchr(cur, ARG_SEP)) != NULL)
+ ++cur;
+ }
+ return 1;
+}
+#endif
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
module_init(mptscsih_init);
module_exit(mptscsih_exit);