Commit 17bb4650 authored by Pam Delaney's avatar Pam Delaney Committed by Christoph Hellwig

[PATCH] Fusion-MPT Update (2.03.01.01)

This upgrades the Fusion-MPT driver from 2.03.00.02 to 2.03.01.01.

Bug Fixes:
 o Added back missing queuecommand entry point define ?!
 o Added to code to break marriage of two controllers during unload
  (could cause a panic)
 o SCSI driver will de-register with base driver if no SCSI-capable
   adapters found

Minor Changes:
 o Removed errant spaces at ends of lines  (most of the changes)
 o Moved code around (and in-lined) some functions for performance reasons.
 o Modified /proc functionality to facilitate testing with 2.5
 o Added a call to synchronize_irq on unload (HP request)
 o Modified load of base to close a potential hole
 o Added code to set the FW IO coalescing depth (IBM request)
 o Changed return when mptctl driver registration fails (Kernel.org request)
 o SCSI driver detect routine calls a generic spinlock for all kernels
   (Kernel.org request)
 o Controller RAID page dynamic instead of static

Currently running a multi-disk stress test w/ 2.5.53,  this patch and driver
built-in. Verified basic reset handling is working properly.
parent 2c3808d6
......@@ -246,35 +246,17 @@ static __inline__ int __get_order(unsigned long size)
#endif
/*
* We use our new error handling code if the kernel version is 2.5.1 or newer.
* We use our new error handling code if the kernel version is 2.4.18 or newer.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18)
#define MPT_SCSI_USE_NEW_EH
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
#define mptscsih_lock(iocp, flags) \
spin_lock_irqsave(&iocp->FreeQlock, flags)
#else
#define mptscsih_lock(iocp, flags) \
({ save_flags(flags); \
cli(); \
})
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
#define mptscsih_unlock(iocp, flags) \
spin_unlock_irqrestore(&iocp->FreeQlock, flags)
#else
#define mptscsih_unlock(iocp, flags) restore_flags(flags);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
#define mpt_work_struct work_struct
#define mpt_work_struct work_struct
#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
#else
#define mpt_work_struct tq_struct
#define mpt_work_struct tq_struct
#define MPT_INIT_WORK(_task, _func, _data) \
({ (_task)->sync = 0; \
(_task)->routine = (_func); \
......@@ -282,6 +264,13 @@ static __inline__ int __get_order(unsigned long size)
})
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
#define mptscsih_sync_irq(_irq) synchronize_irq(_irq)
#else
#define mptscsih_sync_irq(_irq) synchronize_irq()
#endif
/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* _LINUX_COMPAT_H */
......
......@@ -49,7 +49,7 @@
* (mailto:sjralston1@netscape.net)
* (mailto:Pam.Delaney@lsil.com)
*
* $Id: mptbase.c,v 1.123 2002/10/17 20:15:56 pdelaney Exp $
* $Id: mptbase.c,v 1.125 2002/12/03 21:26:32 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -208,6 +208,7 @@ static int GetIoUnitPage2(MPT_ADAPTER *ioc);
static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
static int mpt_findImVolumes(MPT_ADAPTER *ioc);
static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
static void mpt_timer_expired(unsigned long data);
static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
......@@ -443,7 +444,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
*/
if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
|| (mf < ioc->req_frames)) ) {
printk(MYIOC_s_WARN_FMT
printk(MYIOC_s_WARN_FMT
"mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
cb_idx = 0;
pa = 0;
......@@ -451,14 +452,14 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
}
if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
|| (mr < ioc->reply_frames)) ) {
printk(MYIOC_s_WARN_FMT
printk(MYIOC_s_WARN_FMT
"mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
cb_idx = 0;
pa = 0;
freeme = 0;
}
if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
printk(MYIOC_s_WARN_FMT
printk(MYIOC_s_WARN_FMT
"mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
cb_idx = 0;
pa = 0;
......@@ -576,9 +577,11 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
CONFIGPARMS *pCfg;
unsigned long flags;
dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
ioc->name, mf, reply));
DBG_DUMP_REPLY_FRAME(reply)
pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
if (pCfg) {
......@@ -599,7 +602,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
u16 status;
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
dprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
status, le32_to_cpu(pReply->IOCLogInfo)));
pCfg->status = status;
......@@ -943,7 +946,7 @@ mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
* mpt_add_sge - Place a simple SGE at address pAddr.
* @pAddr: virtual address for SGE
* @flagslength: SGE flags and data transfer length
* @dma_addr: Physical address
* @dma_addr: Physical address
*
* This routine places a MPT request frame back on the MPT adapter's
* FreeQ.
......@@ -973,7 +976,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
* @pAddr: virtual address for SGE
* @next: nextChainOffset value (u32's)
* @length: length of next SGL segment
* @dma_addr: Physical address
* @dma_addr: Physical address
*
* This routine places a MPT request frame back on the MPT adapter's
* FreeQ.
......@@ -986,7 +989,7 @@ mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
u32 tmp = dma_addr & 0xFFFFFFFF;
pChain->Length = cpu_to_le16(length);
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
pChain->NextChainOffset = next;
......@@ -1283,7 +1286,7 @@ mpt_adapter_install(struct pci_dev *pdev)
return r;
if (!pci_set_dma_mask(pdev, mask)) {
dprintk((KERN_INFO MYNAM
dprintk((KERN_INFO MYNAM
": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
} else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
......@@ -1470,6 +1473,12 @@ mpt_adapter_install(struct pci_dev *pdev)
ioc->active = 0;
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
/* tack onto tail of our MPT adapter list */
Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
/* Set lookup ptr. */
mpt_adapters[ioc->id] = ioc;
ioc->pci_irq = -1;
if (pdev->irq) {
r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
......@@ -1482,6 +1491,8 @@ mpt_adapter_install(struct pci_dev *pdev)
printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
ioc->name, __irq_itoa(pdev->irq));
#endif
Q_DEL_ITEM(ioc);
mpt_adapters[ioc->id] = NULL;
iounmap(mem);
kfree(ioc);
return -EBUSY;
......@@ -1498,16 +1509,10 @@ mpt_adapter_install(struct pci_dev *pdev)
#endif
}
/* tack onto tail of our MPT adapter list */
Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
/* Set lookup ptr. */
mpt_adapters[ioc->id] = ioc;
/* NEW! 20010220 -sralston
* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
*/
if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)
if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)
|| (ioc->chip_type == C1035) || (ioc->chip_type == FC929X))
mpt_detect_bound_ports(ioc, pdev);
......@@ -1638,6 +1643,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
/* Handle the alt IOC too */
if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
ddlprintk((MYIOC_s_INFO_FMT
"Alt-ioc firmware upload required!\n",
ioc->name));
r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
if (r != 0)
printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
......@@ -1706,14 +1714,18 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
*/
mpt_GetScsiPortSettings(ioc, 0);
/* Get version and length of SDP 1
/* Get version and length of SDP 1
*/
mpt_readScsiDevicePageHeaders(ioc, 0);
/* Find IM volumes
/* Find IM volumes
*/
if (ioc->facts.MsgVersion >= 0x0102)
mpt_findImVolumes(ioc);
/* Check, and possibly reset, the coalescing value
*/
mpt_read_ioc_pg_1(ioc);
}
GetIoUnitPage2(ioc);
......@@ -1819,7 +1831,7 @@ mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
if ((state = mpt_downloadboot(this, NO_SLEEP)) < 0) {
printk(KERN_WARNING MYNAM
printk(KERN_WARNING MYNAM
": firmware downloadboot failure (%d)!\n", state);
}
}
......@@ -1919,6 +1931,11 @@ mpt_adapter_dispose(MPT_ADAPTER *this)
sz_first = this->alloc_total;
if (this->alt_ioc != NULL) {
this->alt_ioc->alt_ioc = NULL;
this->alt_ioc = NULL;
}
mpt_adapter_disable(this, 1);
if (this->pci_irq != -1) {
......@@ -1998,8 +2015,8 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
*
* Returns:
* 1 - DIAG reset and READY
* 0 - READY initially OR soft reset and READY
* -1 - Any failure on KickStart
* 0 - READY initially OR soft reset and READY
* -1 - Any failure on KickStart
* -2 - Msg Unit Reset Failed
* -3 - IO Unit Reset Failed
* -4 - IOC owned by a PEER
......@@ -2042,7 +2059,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
else
statefault = 4;
}
}
}
/*
* Check to see if IOC is in FAULT state.
......@@ -2244,7 +2261,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
/*
* FC f/w version changed between 1.1 and 1.2
* FC f/w version changed between 1.1 and 1.2
* Old: u16{Major(4),Minor(4),SubMinor(8)}
* New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
*/
......@@ -2417,10 +2434,10 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
else
else
ioc->upload_fw = 1;
}
ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n",
ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n",
ioc->name, ioc_init.Flags, ioc->upload_fw));
if ((int)ioc->chip_type <= (int)FC929) {
......@@ -2554,8 +2571,8 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
* Outputs: frags - number of fragments needed
* Return NULL if failed.
*/
void *
mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
void *
mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
{
fw_image_t **cached_fw = NULL;
u8 *mem = NULL;
......@@ -2564,7 +2581,7 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
int bytes_left, bytes, num_frags;
int sz, ii;
/* cached_fw
/* cached_fw
*/
sz = ioc->num_fw_frags * sizeof(void *);
mem = kmalloc(sz, GFP_ATOMIC);
......@@ -2721,8 +2738,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc,
ioc->facts.FWImageSize, &num_frags, &alloc_sz);
ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc,
ioc->facts.FWImageSize, &num_frags, &alloc_sz);
if (ioc->cached_fw == NULL) {
/* Major Failure.
......@@ -2769,8 +2786,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
}
mpt_add_sge(&request[sgeoffset],
MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size,
mpt_add_sge(&request[sgeoffset],
MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size,
ioc->cached_fw[ii]->fw_dma);
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
......@@ -3117,8 +3134,8 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
* 0 - no reset due to History bit, READY
* -1 - no reset due to History bit but not READY
* OR reset but failed to come READY
* -2 - no reset, could not enter DIAG mode
* -3 - reset but bad FW bit
* -2 - no reset, could not enter DIAG mode
* -3 - reset but bad FW bit
*/
static int
KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
......@@ -3254,18 +3271,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
ioc->name, diag0val, diag1val));
#endif
/* Write the PreventIocBoot bit */
#if 1
if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
#else
if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
#endif
diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
}
/*
* Disable the ARM (Bug fix)
*
*
*/
CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
mdelay (1);
......@@ -3304,11 +3317,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
/* FIXME? Examine results here? */
}
#if 1
if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
#else
if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
#endif
/* If the DownloadBoot operation fails, the
* IOC will be left unusable. This is a fatal error
* case. _diag_reset will return < 0
......@@ -3318,7 +3327,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
#ifdef MPT_DEBUG
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
dprintk((MYIOC_s_INFO_FMT
dprintk((MYIOC_s_INFO_FMT
"DbG2b: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
#endif
......@@ -3335,7 +3344,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
}
}
if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
printk(KERN_WARNING MYNAM
printk(KERN_WARNING MYNAM
": firmware downloadboot failure (%d)!\n", count);
}
......@@ -3467,7 +3476,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
return r;
/* FW ACK'd request, wait for READY state
/* FW ACK'd request, wait for READY state
*/
cntdn = HZ * 15;
count = 0;
......@@ -3631,6 +3640,9 @@ PrimeIocFifos(MPT_ADAPTER *ioc)
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
#ifdef MFCNT
ioc->mfcnt = 0;
#endif
if (ioc->sense_buf_pool == NULL) {
sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
......@@ -4267,7 +4279,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
int ii;
int data, rc = 0;
/* Allocate memory
/* Allocate memory
*/
if (!ioc->spi_data.nvram) {
int sz;
......@@ -4446,12 +4458,17 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
ioc->spi_data.sdp0length = cfg.hdr->PageLength;
dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
return 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
* @ioc: Pointer to a Adapter Strucutre
* @portnum: IOC port number
*
......@@ -4464,17 +4481,13 @@ static int
mpt_findImVolumes(MPT_ADAPTER *ioc)
{
IOCPage2_t *pIoc2 = NULL;
IOCPage3_t *pIoc3 = NULL;
ConfigPageIoc2RaidVol_t *pIocRv = NULL;
u8 *mem;
dma_addr_t ioc2_dma;
dma_addr_t ioc3_dma;
CONFIGPARMS cfg;
ConfigPageHeader_t header;
int jj;
int rc = 0;
int iocpage2sz;
int iocpage3sz = 0;
u8 nVols, nPhys;
u8 vid, vbus, vioc;
......@@ -4541,44 +4554,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
/* No physical disks. Done.
*/
} else {
/* There is at least one physical disk.
* Read and save IOC Page 3
*/
header.PageVersion = 0;
header.PageLength = 0;
header.PageNumber = 3;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
cfg.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
cfg.timeout = 0;
if (mpt_config(ioc, &cfg) != 0)
goto done_and_free;
if (header.PageLength == 0)
goto done_and_free;
/* Read Header good, alloc memory
*/
iocpage3sz = header.PageLength * 4;
pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
if (!pIoc3)
goto done_and_free;
/* Read the Page and save the data
* into malloc'd memory.
*/
cfg.physAddr = ioc3_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
mem = kmalloc(iocpage3sz, GFP_ATOMIC);
if (mem) {
memcpy(mem, (u8 *)pIoc3, iocpage3sz);
ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
}
}
mpt_read_ioc_pg_3(ioc);
}
done_and_free:
......@@ -4587,14 +4563,159 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
pIoc2 = NULL;
}
return rc;
}
int
mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
{
IOCPage3_t *pIoc3 = NULL;
u8 *mem;
CONFIGPARMS cfg;
ConfigPageHeader_t header;
dma_addr_t ioc3_dma;
int iocpage3sz = 0;
/* Free the old page
*/
if (ioc->spi_data.pIocPg3) {
kfree(ioc->spi_data.pIocPg3);
ioc->spi_data.pIocPg3 = NULL;
}
/* There is at least one physical disk.
* Read and save IOC Page 3
*/
header.PageVersion = 0;
header.PageLength = 0;
header.PageNumber = 3;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
cfg.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
cfg.timeout = 0;
if (mpt_config(ioc, &cfg) != 0)
return 0;
if (header.PageLength == 0)
return 0;
/* Read Header good, alloc memory
*/
iocpage3sz = header.PageLength * 4;
pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
if (!pIoc3)
return 0;
/* Read the Page and save the data
* into malloc'd memory.
*/
cfg.physAddr = ioc3_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
mem = kmalloc(iocpage3sz, GFP_ATOMIC);
if (mem) {
memcpy(mem, (u8 *)pIoc3, iocpage3sz);
ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
}
}
if (pIoc3) {
pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
pIoc3 = NULL;
}
return rc;
return 0;
}
static void
mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
{
IOCPage1_t *pIoc1 = NULL;
CONFIGPARMS cfg;
ConfigPageHeader_t header;
dma_addr_t ioc1_dma;
int iocpage1sz = 0;
u32 tmp;
/* Check the Coalescing Timeout in IOC Page 1
*/
header.PageVersion = 0;
header.PageLength = 0;
header.PageNumber = 1;
header.PageType = MPI_CONFIG_PAGETYPE_IOC;
cfg.hdr = &header;
cfg.physAddr = -1;
cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0;
cfg.timeout = 0;
if (mpt_config(ioc, &cfg) != 0)
return;
if (header.PageLength == 0)
return;
/* Read Header good, alloc memory
*/
iocpage1sz = header.PageLength * 4;
pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
if (!pIoc1)
return;
/* Read the Page and check coalescing timeout
*/
cfg.physAddr = ioc1_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
ioc->name, tmp));
if (tmp > MPT_COALESCING_TIMEOUT) {
pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
/* Write NVRAM and current
*/
cfg.dir = 1;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
ioc->name, MPT_COALESCING_TIMEOUT));
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
if (mpt_config(ioc, &cfg) == 0) {
dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
ioc->name, MPT_COALESCING_TIMEOUT));
} else {
dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
ioc->name));
}
} else {
dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
ioc->name));
}
}
} else {
dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
}
}
if (pIoc1) {
pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
pIoc1 = NULL;
}
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -4690,7 +4811,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
*/
in_isr = in_interrupt();
if (in_isr) {
dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
ioc->name));
return -EPERM;
}
......@@ -4698,7 +4819,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
/* Get and Populate a free Frame
*/
if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
ioc->name));
return -EAGAIN;
}
......@@ -4731,7 +4852,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
/* Append pCfg pointer to end of mf
......@@ -4778,7 +4899,7 @@ mpt_timer_expired(unsigned long data)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
/* Perform a FW reload */
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
......@@ -4788,7 +4909,7 @@ mpt_timer_expired(unsigned long data)
* Hard reset clean-up will wake up
* process and free all resources.
*/
dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
return;
}
......@@ -4829,7 +4950,7 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
} else {
CONFIGPARMS *pNext;
/* Search the configQ for internal commands.
/* Search the configQ for internal commands.
* Flush the Q, and wake up all suspended threads.
*/
#if 1
......@@ -5096,8 +5217,7 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
*/
if (isense_idx == ii)
len += sprintf(buf+len, " Fusion MPT isense driver\n");
} else
break;
}
}
MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
......@@ -5774,6 +5894,7 @@ EXPORT_SYMBOL(mpt_lan_index);
EXPORT_SYMBOL(mpt_stm_index);
EXPORT_SYMBOL(mpt_HardResetHandler);
EXPORT_SYMBOL(mpt_config);
EXPORT_SYMBOL(mpt_read_ioc_pg_3);
EXPORT_SYMBOL(mpt_alloc_fw_memory);
EXPORT_SYMBOL(mpt_free_fw_memory);
......@@ -5843,6 +5964,7 @@ static void
fusion_exit(void)
{
MPT_ADAPTER *this;
struct pci_dev *pdev = NULL;
dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
......@@ -5861,9 +5983,14 @@ fusion_exit(void)
this->active = 0;
pdev = (struct pci_dev *)this->pcidev;
mptscsih_sync_irq(pdev->irq);
/* Clear any lingering interrupt */
CHIPREG_WRITE32(&this->chip->IntStatus, 0);
CHIPREG_READ32(&this->chip->IntStatus);
Q_DEL_ITEM(this);
mpt_adapter_dispose(this);
}
......
......@@ -13,7 +13,7 @@
* (mailto:sjralston1@netscape.net)
* (mailto:Pam.Delaney@lsil.com)
*
* $Id: mptbase.h,v 1.136 2002/10/21 13:51:54 pdelaney Exp $
* $Id: mptbase.h,v 1.141 2002/12/03 21:26:32 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -80,8 +80,8 @@
#define COPYRIGHT "Copyright (c) 1999-2002 " MODULEAUTHOR
#endif
#define MPT_LINUX_VERSION_COMMON "2.03.00.02"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.03.00.02"
#define MPT_LINUX_VERSION_COMMON "2.03.01.01"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.03.01.01"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
......@@ -134,8 +134,10 @@
#define CAN_SLEEP 1
#define NO_SLEEP 0
/*
* SCSI transfer rate defines.
#define MPT_COALESCING_TIMEOUT 0x10
/*
* SCSI transfer rate defines.
*/
#define MPT_ULTRA320 0x08
#define MPT_ULTRA160 0x09
......@@ -524,7 +526,7 @@ typedef struct _mpt_ioctl_events {
#define MPT_SCSICFG_DV_PENDING 0x04 /* DV on this physical id pending */
#define MPT_SCSICFG_DV_NOT_DONE 0x08 /* DV has not been performed */
#define MPT_SCSICFG_BLK_NEGO 0x10 /* WriteSDP1 with WDTR and SDTR disabled */
#define MPT_SCSICFG_RELOAD_IOC_PG3 0x20 /* IOC Pg 3 data is obsolete */
/* Args passed to writeSDP1: */
#define MPT_SCSICFG_USE_NVRAM 0x01 /* WriteSDP1 using NVRAM */
#define MPT_SCSICFG_ALL_IDS 0x02 /* WriteSDP1 to all IDS */
......@@ -756,6 +758,12 @@ typedef struct _mpt_sge {
#define nehprintk(x)
#endif
#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
#define dcprintk(x) printk x
#else
#define dcprintk(x)
#endif
#define MPT_INDEX_2_MFPTR(ioc,idx) \
(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
......@@ -1009,6 +1017,7 @@ extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
extern void *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz);
extern void mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img);
extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
/*
* Public data decl's...
......
......@@ -34,7 +34,7 @@
* (mailto:sjralston1@netscape.net)
* (mailto:Pam.Delaney@lsil.com)
*
* $Id: mptctl.c,v 1.61 2002/10/17 20:15:57 pdelaney Exp $
* $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -2911,9 +2911,9 @@ int __init mptctl_init(void)
#endif /*} sparc */
/* Register this device */
if (misc_register(&mptctl_miscdev) == -1) {
err = misc_register(&mptctl_miscdev);
if (err < 0) {
printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR);
err = -EBUSY;
goto out_fail;
}
printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n");
......
......@@ -20,7 +20,7 @@
* (mailto:sjralston1@netscape.net)
* (mailto:Pam.Delaney@lsil.com)
*
* $Id: mptctl.h,v 1.12 2002/10/17 20:15:58 pdelaney Exp $
* $Id: mptctl.h,v 1.13 2002/12/03 21:26:33 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......
......@@ -26,7 +26,7 @@
* (mailto:sjralston1@netscape.net)
* (mailto:Pam.Delaney@lsil.com)
*
* $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 pdelaney Exp $
* $Id: mptscsih.c,v 1.104 2002/12/03 21:26:34 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -159,11 +159,9 @@ typedef struct _dv_parameters {
static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
static int mptscsih_io_direction(Scsi_Cmnd *cmd);
static int mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
SCSIIORequest_t *pReq, int req_idx);
static int mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
......@@ -274,180 +272,609 @@ static struct mptscsih_driver_setup
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_io_done - Main SCSI IO callback routine registered to
* Fusion MPT (base) driver
* @ioc: Pointer to MPT_ADAPTER structure
* @mf: Pointer to original MPT request frame
* @r: Pointer to MPT reply frame (NULL if TurboReply)
* Private inline routines...
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* 19991030 -sralston
* Return absolute SCSI data direction:
* 1 = _DATA_OUT
* 0 = _DIR_NONE
* -1 = _DATA_IN
*
* This routine is called from mpt.c::mpt_interrupt() at the completion
* of any SCSI IO request.
* This routine is registered with the Fusion MPT (base) driver at driver
* load/init time via the mpt_register() API call.
* Changed: 3-20-2002 pdelaney to use the default data
* direction and the defines set up in the
* 2.4 kernel series
* 1 = _DATA_OUT changed to SCSI_DATA_WRITE (1)
* 0 = _DIR_NONE changed to SCSI_DATA_NONE (3)
* -1 = _DATA_IN changed to SCSI_DATA_READ (2)
* If the direction is unknown, fall through to original code.
*
* Returns 1 indicating alloc'd request frame ptr should be freed.
* Mid-layer bug fix(): sg interface generates the wrong data
* direction in some cases. Set the direction the hard way for
* the most common commands.
*/
static int
mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
static inline int
mptscsih_io_direction(Scsi_Cmnd *cmd)
{
Scsi_Cmnd *sc;
MPT_SCSI_HOST *hd;
SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply;
#ifndef MPT_SCSI_USE_NEW_EH
unsigned long flags;
#endif
u16 req_idx;
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
if ((mf == NULL) ||
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
ioc->name, mf?"BAD":"NULL", (void *) mf);
/* return 1; CHECKME SteveR. Don't free. */
return 0;
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
return SCSI_DATA_WRITE;
break;
case READ_6:
case READ_10:
return SCSI_DATA_READ;
break;
}
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
sc = hd->ScsiLookup[req_idx];
if (sc == NULL) {
MPIHeader_t *hdr = (MPIHeader_t *)mf;
atomic_dec(&queue_depth);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
return cmd->sc_data_direction;
#endif
switch (cmd->cmnd[0]) {
/* _DATA_OUT commands */
case WRITE_6: case WRITE_10: case WRITE_12:
case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
case WRITE_VERIFY: case WRITE_VERIFY_12:
case COMPARE: case COPY: case COPY_VERIFY:
case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
case REASSIGN_BLOCKS:
case PERSISTENT_RESERVE_OUT:
case 0xea:
case 0xa3:
return SCSI_DATA_WRITE;
/* writeSDP1 will use the ScsiDoneCtx
* There is no processing for the reply.
* Just return to the calling function.
*/
if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
/* No data transfer commands */
case SEEK_6: case SEEK_10:
case RESERVE: case RELEASE:
case TEST_UNIT_READY:
case START_STOP:
case ALLOW_MEDIUM_REMOVAL:
return SCSI_DATA_NONE;
mptscsih_freeChainBuffers(hd, req_idx);
return 1;
}
/* Conditional data transfer commands */
case FORMAT_UNIT:
if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */
return SCSI_DATA_WRITE;
else
return SCSI_DATA_NONE;
dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
ioc->name, mf, mr, sc, req_idx));
case VERIFY:
if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */
return SCSI_DATA_WRITE;
else
return SCSI_DATA_NONE;
atomic_dec(&queue_depth);
case RESERVE_10:
if (cmd->cmnd[1] & 0x03) /* RESERVE:{LongID|Extent} (data out phase)? */
return SCSI_DATA_WRITE;
else
return SCSI_DATA_NONE;
sc->result = DID_OK << 16; /* Set default reply as OK */
pScsiReq = (SCSIIORequest_t *) mf;
pScsiReply = (SCSIIOReply_t *) mr;
/* Must be data _IN! */
default:
return SCSI_DATA_READ;
}
} /* mptscsih_io_direction() */
if (pScsiReply == NULL) {
/* special context reply handling */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_add_sge - Place a simple SGE at address pAddr.
* @pAddr: virtual address for SGE
* @flagslength: SGE flags and data transfer length
* @dma_addr: Physical address
*
* This routine places a MPT request frame back on the MPT adapter's
* FreeQ.
*/
static inline void
mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
{
if (sizeof(dma_addr_t) == sizeof(u64)) {
SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
u32 tmp = dma_addr & 0xFFFFFFFF;
/* If regular Inquiry cmd - save inquiry data
*/
if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
int dlen;
pSge->FlagsLength = cpu_to_le32(flagslength);
pSge->Address.Low = cpu_to_le32(tmp);
tmp = (u32) ((u64)dma_addr >> 32);
pSge->Address.High = cpu_to_le32(tmp);
dlen = le32_to_cpu(pScsiReq->DataLength);
if (dlen >= SCSI_STD_INQUIRY_BYTES) {
mptscsih_initTarget(hd,
hd->port,
sc->target,
pScsiReq->LUN[1],
sc->buffer,
dlen);
}
}
#ifdef MPT_SAVE_AUTOSENSE
clear_sense_flag(hd, pScsiReq);
#endif
} else {
u32 xfer_cnt;
u16 status;
u8 scsi_state;
SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
pSge->FlagsLength = cpu_to_le32(flagslength);
pSge->Address = cpu_to_le32(dma_addr);
}
} /* mptscsih_add_sge() */
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
scsi_state = pScsiReply->SCSIState;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_add_chain - Place a chain SGE at address pAddr.
* @pAddr: virtual address for SGE
* @next: nextChainOffset value (u32's)
* @length: length of next SGL segment
* @dma_addr: Physical address
*
* This routine places a MPT request frame back on the MPT adapter's
* FreeQ.
*/
static inline void
mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
{
if (sizeof(dma_addr_t) == sizeof(u64)) {
SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
u32 tmp = dma_addr & 0xFFFFFFFF;
dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
mf, mr, sc));
dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh"
", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
status, scsi_state, pScsiReply->SCSIStatus,
le32_to_cpu(pScsiReply->IOCLogInfo)));
pChain->Length = cpu_to_le16(length);
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
copy_sense_data(sc, hd, mf, pScsiReply);
pChain->NextChainOffset = next;
/*
* Look for + dump FCP ResponseInfo[]!
*/
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n",
le32_to_cpu(pScsiReply->ResponseInfo)));
}
pChain->Address.Low = cpu_to_le32(tmp);
tmp = (u32) ((u64)dma_addr >> 32);
pChain->Address.High = cpu_to_le32(tmp);
} else {
SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
pChain->Length = cpu_to_le16(length);
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
pChain->NextChainOffset = next;
pChain->Address = cpu_to_le32(dma_addr);
}
} /* mptscsih_add_chain() */
switch(status) {
case MPI_IOCSTATUS_BUSY: /* 0x0002 */
/* CHECKME!
* Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
* But not: DID_BUS_BUSY lest one risk
* killing interrupt handler:-(
*/
sc->result = STS_BUSY;
break;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_getFreeChainBuffes - Function to get a free chain
* from the MPT_SCSI_HOST FreeChainQ.
* @hd: Pointer to the MPT_SCSI_HOST instance
* @req_idx: Index of the SCSI IO request frame. (output)
*
* return SUCCESS or FAILED
*/
static inline int
mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
{
MPT_FRAME_HDR *chainBuf = NULL;
unsigned long flags;
int rc = FAILED;
int chain_idx = MPT_HOST_NO_CHAIN;
case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
sc->result = DID_BAD_TARGET << 16;
break;
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
/* Spoof to SCSI Selection Timeout! */
sc->result = DID_NO_CONNECT << 16;
int offset;
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
break;
chainBuf = hd->FreeChainQ.head;
Q_DEL_ITEM(&chainBuf->u.frame.linkage);
offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
chain_idx = offset / hd->ioc->req_sz;
rc = SUCCESS;
}
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
#ifndef MPT_SCSI_USE_NEW_EH
search_taskQ_for_cmd(sc, hd);
#endif
/* Linux handles an unsolicited DID_RESET better
* than an unsolicited DID_ABORT.
*/
sc->result = DID_RESET << 16;
/* GEM Workaround. */
if (hd->is_spi)
mptscsih_no_negotiate(hd, sc->target);
break;
*retIndex = chain_idx;
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
#ifndef MPT_SCSI_USE_NEW_EH
search_taskQ_for_cmd(sc, hd);
#endif
sc->result = DID_RESET << 16;
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
hd->ioc->name, *retIndex, chainBuf));
/* GEM Workaround. */
if (hd->is_spi)
mptscsih_no_negotiate(hd, sc->target);
break;
return rc;
} /* mptscsih_getFreeChainBuffer() */
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
/*
* YIKES! I just discovered that SCSI IO which
* returns check condition, SenseKey=05 (ILLEGAL REQUEST)
* and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
* comes down this path!
* Do upfront check for valid SenseData and give it
* precedence!
*/
sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
#ifdef MPT_SAVE_AUTOSENSE
clear_sense_flag(hd, pScsiReq);
#endif
if (scsi_state == 0) {
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
* SCSIIORequest_t Message Frame.
* @hd: Pointer to MPT_SCSI_HOST structure
* @SCpnt: Pointer to Scsi_Cmnd structure
* @pReq: Pointer to SCSIIORequest_t structure
*
* Returns ...
*/
static int
mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
SCSIIORequest_t *pReq, int req_idx)
{
char *psge;
char *chainSge;
struct scatterlist *sg;
int frm_sz;
int sges_left, sg_done;
int chain_idx = MPT_HOST_NO_CHAIN;
int sgeOffset;
int numSgeSlots, numSgeThisFrame;
u32 sgflags, sgdir, thisxfer = 0;
int chain_dma_off = 0;
int newIndex;
int ii;
dma_addr_t v2;
sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
sgdir = MPT_TRANSFER_HOST_TO_IOC;
} else {
sgdir = MPT_TRANSFER_IOC_TO_HOST;
}
psge = (char *) &pReq->SGL;
frm_sz = hd->ioc->req_sz;
/* Map the data portion, if any.
* sges_left = 0 if no data transfer.
*/
sges_left = SCpnt->use_sg;
if (SCpnt->use_sg) {
sges_left = pci_map_sg(hd->ioc->pcidev,
(struct scatterlist *) SCpnt->request_buffer,
SCpnt->use_sg,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
} else if (SCpnt->request_bufflen) {
dma_addr_t buf_dma_addr;
scPrivate *my_priv;
buf_dma_addr = pci_map_single(hd->ioc->pcidev,
SCpnt->request_buffer,
SCpnt->request_bufflen,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
/* We hide it here for later unmap. */
my_priv = (scPrivate *) &SCpnt->SCp;
my_priv->p1 = (void *)(ulong) buf_dma_addr;
dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
hd->ioc->name, SCpnt, SCpnt->request_bufflen));
mptscsih_add_sge((char *) &pReq->SGL,
0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
buf_dma_addr);
return SUCCESS;
}
/* Handle the SG case.
*/
sg = (struct scatterlist *) SCpnt->request_buffer;
sg_done = 0;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
chainSge = NULL;
/* Prior to entering this loop - the following must be set
* current MF: sgeOffset (bytes)
* chainSge (Null if original MF is not a chain buffer)
* sg_done (num SGE done for this MF)
*/
nextSGEset:
numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
/* Get first (num - 1) SG elements
* Skip any SG entries with a length of 0
* NOTE: at finish, sg and psge pointed to NEXT data/location positions
*/
for (ii=0; ii < (numSgeThisFrame-1); ii++) {
thisxfer = sg_dma_len(sg);
if (thisxfer == 0) {
sg ++; /* Get next SG element from the OS */
sg_done++;
continue;
}
v2 = sg_dma_address(sg);
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
sg++; /* Get next SG element from the OS */
psge += (sizeof(u32) + sizeof(dma_addr_t));
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
}
if (numSgeThisFrame == sges_left) {
/* Add last element, end of buffer and end of list flags.
*/
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
MPT_SGE_FLAGS_END_OF_BUFFER |
MPT_SGE_FLAGS_END_OF_LIST;
/* Add last SGE and set termination flags.
* Note: Last SGE may have a length of 0 - which should be ok.
*/
thisxfer = sg_dma_len(sg);
v2 = sg_dma_address(sg);
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
/*
sg++;
psge += (sizeof(u32) + sizeof(dma_addr_t));
*/
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
if (chainSge) {
/* The current buffer is a chain buffer,
* but there is not another one.
* Update the chain element
* Offset and Length fields.
*/
mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
} else {
/* The current buffer is the original MF
* and there is no Chain buffer.
*/
pReq->ChainOffset = 0;
}
} else {
/* At least one chain buffer is needed.
* Complete the first MF
* - last SGE element, set the LastElement bit
* - set ChainOffset (words) for orig MF
* (OR finish previous MF chain buffer)
* - update MFStructPtr ChainIndex
* - Populate chain element
* Also
* Loop until done.
*/
dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
hd->ioc->name, sg_done));
/* Set LAST_ELEMENT flag for last non-chain element
* in the buffer. Since psge points at the NEXT
* SGE element, go back one SGE element, update the flags
* and reset the pointer. (Note: sgflags & thisxfer are already
* set properly).
*/
if (sg_done) {
u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
sgflags = le32_to_cpu(*ptmp);
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
*ptmp = cpu_to_le32(sgflags);
}
if (chainSge) {
/* The current buffer is a chain buffer.
* chainSge points to the previous Chain Element.
* Update its chain element Offset and Length (must
* include chain element size) fields.
* Old chain element is now complete.
*/
u8 nextChain = (u8) (sgeOffset >> 2);
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
} else {
/* The original MF buffer requires a chain buffer -
* set the offset.
* Last element in this MF is a chain element.
*/
pReq->ChainOffset = (u8) (sgeOffset >> 2);
}
sges_left -= sg_done;
/* NOTE: psge points to the beginning of the chain element
* in current buffer. Get a chain buffer.
*/
if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
return FAILED;
/* Update the tracking arrays.
* If chainSge == NULL, update ReqToChain, else ChainToChain
*/
if (chainSge) {
hd->ChainToChain[chain_idx] = newIndex;
} else {
hd->ReqToChain[req_idx] = newIndex;
}
chain_idx = newIndex;
chain_dma_off = hd->ioc->req_sz * chain_idx;
/* Populate the chainSGE for the current buffer.
* - Set chain buffer pointer to psge and fill
* out the Address and Flags fields.
*/
chainSge = (char *) psge;
dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
psge, req_idx));
/* Start the SGE for the next buffer
*/
psge = (char *) (hd->ChainBuffer + chain_dma_off);
sgeOffset = 0;
sg_done = 0;
dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
psge, chain_idx));
/* Start the SGE for the next buffer
*/
goto nextSGEset;
}
return SUCCESS;
} /* mptscsih_AddSGE() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_io_done - Main SCSI IO callback routine registered to
* Fusion MPT (base) driver
* @ioc: Pointer to MPT_ADAPTER structure
* @mf: Pointer to original MPT request frame
* @r: Pointer to MPT reply frame (NULL if TurboReply)
*
* This routine is called from mpt.c::mpt_interrupt() at the completion
* of any SCSI IO request.
* This routine is registered with the Fusion MPT (base) driver at driver
* load/init time via the mpt_register() API call.
*
* Returns 1 indicating alloc'd request frame ptr should be freed.
*/
static int
mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
{
Scsi_Cmnd *sc;
MPT_SCSI_HOST *hd;
SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
unsigned long flags;
#endif
u16 req_idx;
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
if ((mf == NULL) ||
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
ioc->name, mf?"BAD":"NULL", (void *) mf);
return 0;
}
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
sc = hd->ScsiLookup[req_idx];
if (sc == NULL) {
MPIHeader_t *hdr = (MPIHeader_t *)mf;
atomic_dec(&queue_depth);
/* writeSDP1 will use the ScsiDoneCtx
* There is no processing for the reply.
* Just return to the calling function.
*/
if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
mptscsih_freeChainBuffers(hd, req_idx);
return 1;
}
dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
ioc->name, mf, mr, sc, req_idx));
atomic_dec(&queue_depth);
sc->result = DID_OK << 16; /* Set default reply as OK */
pScsiReq = (SCSIIORequest_t *) mf;
pScsiReply = (SCSIIOReply_t *) mr;
if (pScsiReply == NULL) {
/* special context reply handling */
/* If regular Inquiry cmd - save inquiry data
*/
if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
int dlen;
dlen = le32_to_cpu(pScsiReq->DataLength);
if (dlen >= SCSI_STD_INQUIRY_BYTES) {
mptscsih_initTarget(hd,
hd->port,
sc->target,
pScsiReq->LUN[1],
sc->buffer,
dlen);
}
}
#ifdef MPT_SAVE_AUTOSENSE
clear_sense_flag(hd, pScsiReq);
#endif
} else {
u32 xfer_cnt;
u16 status;
u8 scsi_state;
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
scsi_state = pScsiReply->SCSIState;
dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
mf, mr, sc));
dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh"
", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
status, scsi_state, pScsiReply->SCSIStatus,
le32_to_cpu(pScsiReply->IOCLogInfo)));
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
copy_sense_data(sc, hd, mf, pScsiReply);
/*
* Look for + dump FCP ResponseInfo[]!
*/
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n",
le32_to_cpu(pScsiReply->ResponseInfo)));
}
switch(status) {
case MPI_IOCSTATUS_BUSY: /* 0x0002 */
/* CHECKME!
* Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
* But not: DID_BUS_BUSY lest one risk
* killing interrupt handler:-(
*/
sc->result = STS_BUSY;
break;
case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
sc->result = DID_BAD_TARGET << 16;
break;
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
/* Spoof to SCSI Selection Timeout! */
sc->result = DID_NO_CONNECT << 16;
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
break;
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
#ifndef MPT_SCSI_USE_NEW_EH
search_taskQ_for_cmd(sc, hd);
#endif
/* Linux handles an unsolicited DID_RESET better
* than an unsolicited DID_ABORT.
*/
sc->result = DID_RESET << 16;
/* GEM Workaround. */
if (hd->is_spi)
mptscsih_no_negotiate(hd, sc->target);
break;
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
#ifndef MPT_SCSI_USE_NEW_EH
search_taskQ_for_cmd(sc, hd);
#endif
sc->result = DID_RESET << 16;
/* GEM Workaround. */
if (hd->is_spi)
mptscsih_no_negotiate(hd, sc->target);
break;
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
/*
* YIKES! I just discovered that SCSI IO which
* returns check condition, SenseKey=05 (ILLEGAL REQUEST)
* and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
* comes down this path!
* Do upfront check for valid SenseData and give it
* precedence!
*/
sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
#ifdef MPT_SAVE_AUTOSENSE
clear_sense_flag(hd, pScsiReq);
#endif
if (scsi_state == 0) {
;
} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
/* Have already saved the status and sense data
......@@ -506,7 +933,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
;
} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
/*
* If running agains circa 200003dd 909 MPT f/w,
* If running against circa 200003dd 909 MPT f/w,
* may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
* (QUEUE_FULL) returned from device! --> get 0x0000?128
* and with SenseBytes set to 0.
......@@ -625,7 +1052,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
hd->ScsiLookup[req_idx] = NULL;
sc->host_scribble = NULL; /* CHECKME! - Do we need to clear this??? */
#ifndef MPT_SCSI_USE_NEW_EH
sc->host_scribble = NULL;
#endif
MPT_HOST_LOCK(flags);
sc->scsi_done(sc); /* Issue the command callback */
......@@ -894,7 +1323,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
int ii;
int max = hd->ioc->req_depth;
#ifndef MPT_SCSI_USE_NEW_EH
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
unsigned long flags;
#endif
......@@ -911,7 +1340,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
search_taskQ_for_cmd(SCpnt, hd);
#endif
/* Search pendingQ, if found,
/* Search pendingQ, if found,
* delete from Q. If found, do not decrement
* queue_depth, command never posted.
*/
......@@ -1061,7 +1490,7 @@ mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init)
* of chain buffers to be allocated.
* index = chain_idx
*
* Calculate the number of chain buffers needed(plus 1) per I/O
* Calculate the number of chain buffers needed(plus 1) per I/O
* then multiply the the maximum number of simultaneous cmds
*
* num_sge = num sge in request frame + last chain buffer
......@@ -1175,6 +1604,7 @@ mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIOReque
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int BeenHereDoneThat = 0;
static char *info_kbuf = NULL;
/* SCSI host fops start here... */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
......@@ -1263,9 +1693,10 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
tpnt->proc_dir = &proc_mpt_scsihost;
#endif
tpnt->proc_info = mptscsih_proc_info;
sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
if (sh != NULL) {
mptscsih_lock(this, flags);
spin_lock_irqsave(&this->FreeQlock, flags);
sh->io_port = 0;
sh->n_io_port = 0;
sh->irq = 0;
......@@ -1326,7 +1757,7 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
} else {
numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
(this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
}
}
if (numSGE < sh->sg_tablesize) {
/* Reset this value */
......@@ -1340,7 +1771,7 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
*/
scsi_set_pci_device(sh, this->pcidev);
mptscsih_unlock(this, flags);
spin_unlock_irqrestore(&this->FreeQlock, flags);
hd = (MPT_SCSI_HOST *) sh->hostdata;
hd->ioc = this;
......@@ -1503,12 +1934,25 @@ mptscsih_detect(Scsi_Host_Template *tpnt)
done:
if (mpt_scsi_hosts > 0)
register_reboot_notifier(&mptscsih_notifier);
else {
mpt_reset_deregister(ScsiDoneCtx);
dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
mpt_event_deregister(ScsiDoneCtx);
dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
mpt_deregister(ScsiScanDvCtx);
mpt_deregister(ScsiTaskCtx);
mpt_deregister(ScsiDoneCtx);
if (info_kbuf != NULL)
kfree(info_kbuf);
}
return mpt_scsi_hosts;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static char *info_kbuf = NULL;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_release - Unregister SCSI host from linux scsi mid-layer
......@@ -1721,711 +2165,729 @@ mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_info - Return information about MPT adapter
* @SChost: Pointer to Scsi_Host structure
*
* (linux Scsi_Host_Template.info routine)
*
* Returns pointer to buffer where information was written.
*/
const char *
mptscsih_info(struct Scsi_Host *SChost)
{
MPT_SCSI_HOST *h;
int size = 0;
if (info_kbuf == NULL)
if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
return info_kbuf;
h = (MPT_SCSI_HOST *)SChost->hostdata;
info_kbuf[0] = '\0';
mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
info_kbuf[size-1] = '\0';
return info_kbuf;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int max_qd = 1;
#if 0
static int index_log[128];
static int index_ent = 0;
static __inline__ void ADD_INDEX_LOG(int req_ent)
{
int i = index_ent++;
index_log[i & (128 - 1)] = req_ent;
}
#else
#define ADD_INDEX_LOG(req_ent) do { } while(0)
#endif
#ifdef DROP_TEST
#define DROP_IOC 1 /* IOC to force failures */
#define DROP_TARGET 3 /* Target ID to force failures */
#define DROP_THIS_CMD 10000 /* iteration to drop command */
static int dropCounter = 0;
static int dropTestOK = 0; /* num did good */
static int dropTestBad = 0; /* num did bad */
static int dropTestNum = 0; /* total = good + bad + incomplete */
static int numTotCmds = 0;
static MPT_FRAME_HDR *dropMfPtr = NULL;
static int numTMrequested = 0;
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
* @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
* @id: IOC id number
* @mf: Pointer to message frame
*
* Handles the call to mptbase for posting request and queue depth
* tracking.
*
* Returns none.
*/
static void
mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
{
/* Main banana... */
atomic_inc(&queue_depth);
if (atomic_read(&queue_depth) > max_qd) {
max_qd = atomic_read(&queue_depth);
dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
}
mpt_put_msg_frame(context, id, mf);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
* @SCpnt: Pointer to Scsi_Cmnd structure
* @done: Pointer SCSI mid-layer IO completion function
* mptscsih_info - Return information about MPT adapter
* @SChost: Pointer to Scsi_Host structure
*
* (linux Scsi_Host_Template.queuecommand routine)
* This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
* from a linux Scsi_Cmnd request and send it to the IOC.
* (linux Scsi_Host_Template.info routine)
*
* Returns 0. (rtn value discarded by linux scsi mid-layer)
* Returns pointer to buffer where information was written.
*/
int
mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
const char *
mptscsih_info(struct Scsi_Host *SChost)
{
MPT_SCSI_HOST *hd;
MPT_FRAME_HDR *mf;
SCSIIORequest_t *pScsiReq;
VirtDevice *pTarget;
MPT_DONE_Q *buffer = NULL;
unsigned long flags;
int target;
int lun;
int datadir;
u32 datalen;
u32 scsictl;
u32 scsidir;
u32 qtag;
u32 cmd_len;
int my_idx;
int ii;
int rc;
int did_errcode;
int issueCmd;
did_errcode = 0;
hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
target = SCpnt->target;
lun = SCpnt->lun;
SCpnt->scsi_done = done;
pTarget = hd->Targets[target];
dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
MPT_SCSI_HOST *h = NULL;
int size = 0;
#ifdef MPT_SAVE_AUTOSENSE
/* 20000617 -sralston
* GRRRRR... Shouldn't have to do this but...
* Do explicit check for REQUEST_SENSE and cached SenseData.
* If yes, return cached SenseData.
*/
if (SCpnt->cmnd[0] == REQUEST_SENSE) {
u8 *dest = NULL;
int sz;
if (info_kbuf == NULL)
if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
return info_kbuf;
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; //sjr-moved-here
if (!SCpnt->use_sg) {
dest = SCpnt->request_buffer;
} else {
struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
if (sg)
dest = (u8 *)(ulong)sg_dma_address(sg);
}
h = (MPT_SCSI_HOST *)SChost->hostdata;
info_kbuf[0] = '\0';
if (h) {
mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
info_kbuf[size-1] = '\0';
}
if (dest) {
sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
memcpy(dest, pTarget->sense, sz);
return info_kbuf;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
SCpnt->resid = SCpnt->request_bufflen - sz;
#endif
SCpnt->result = 0;
SCpnt->scsi_done(SCpnt);
struct info_str {
char *buffer;
int length;
int offset;
int pos;
};
//sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
static void copy_mem_info(struct info_str *info, char *data, int len)
{
if (info->pos + len > info->length)
len = info->length - info->pos;
return 0;
}
}
if (info->pos + len < info->offset) {
info->pos += len;
return;
}
#endif
if (hd->resetPending) {
/* Prevent new commands from being issued
* while reloading the FW.
*/
did_errcode = 1;
goto did_error;
if (info->pos < info->offset) {
data += (info->offset - info->pos);
len -= (info->offset - info->pos);
}
/*
* Put together a MPT SCSI request...
*/
if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
hd->ioc->name));
did_errcode = 2;
goto did_error;
if (len > 0) {
memcpy(info->buffer + info->pos, data, len);
info->pos += len;
}
}
pScsiReq = (SCSIIORequest_t *) mf;
static int copy_info(struct info_str *info, char *fmt, ...)
{
va_list args;
char buf[81];
int len;
my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
va_start(args, fmt);
len = vsprintf(buf, fmt, args);
va_end(args);
ADD_INDEX_LOG(my_idx);
copy_mem_info(info, buf, len);
return len;
}
/*
* The scsi layer should be handling this stuff
* (In 2.3.x it does -DaveM)
*/
static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
{
struct info_str info;
/* BUG FIX! 19991030 -sralston
* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
* Seems we may receive a buffer (datalen>0) even when there
* will be no data transfer! GRRRRR...
*/
datadir = mptscsih_io_direction(SCpnt);
if (datadir == SCSI_DATA_READ) {
datalen = SCpnt->request_bufflen;
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
} else if (datadir == SCSI_DATA_WRITE) {
datalen = SCpnt->request_bufflen;
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
} else {
datalen = 0;
scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
}
info.buffer = pbuf;
info.length = len;
info.offset = offset;
info.pos = 0;
/* Default to untagged. Once a target structure has been allocated,
* use the Inquiry data to determine if device supports tagged.
*/
qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
&& (SCpnt->device->tagged_supported)) {
/*
* Some drives are too stupid to handle fairness issues
* with tagged queueing. We throw in the odd ordered
* tag to stop them starving themselves.
*/
if ((jiffies - hd->qtag_tick) > (5*HZ)) {
qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
hd->qtag_tick = jiffies;
copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
return ((info.pos > info.offset) ? info.pos - info.offset : 0);
}
struct mptscsih_usrcmd {
ulong target;
ulong lun;
ulong data;
ulong cmd;
};
#define UC_GET_SPEED 0x10
static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc)
{
CONFIGPARMS cfg;
dma_addr_t cfg_dma_addr = -1;
ConfigPageHeader_t header;
dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n",
ioc, uc->cmd, uc->target));
switch (uc->cmd) {
case UC_GET_SPEED:
{
SCSIDevicePage0_t *pData = NULL;
if (ioc->spi_data.sdp0length == 0)
return;
pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev,
ioc->spi_data.sdp0length * 4, &cfg_dma_addr);
if (pData == NULL)
return;
header.PageVersion = ioc->spi_data.sdp0version;
header.PageLength = ioc->spi_data.sdp0length;
header.PageNumber = 0;
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
cfg.hdr = &header;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */
cfg.physAddr = cfg_dma_addr;
if (mpt_config(ioc, &cfg) == 0) {
u32 np = le32_to_cpu(pData->NegotiatedParameters);
u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE;
printk("Target %d: %s;",
(u32) uc->target,
tmp ? "Wide" : "Narrow");
tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK;
if (tmp) {
u32 speed = 0;
printk(" Synchronous");
tmp = (tmp >> 16);
printk(" (Offset=0x%x", tmp);
tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK;
tmp = (tmp >> 8);
printk(" Factor=0x%x)", tmp);
if (tmp <= MPT_ULTRA320)
speed=160;
else if (tmp <= MPT_ULTRA160)
speed=80;
else if (tmp <= MPT_ULTRA2)
speed=40;
else if (tmp <= MPT_ULTRA)
speed=20;
else if (tmp <= MPT_FAST)
speed=10;
else if (tmp <= MPT_SCSI)
speed=5;
if (np & MPI_SCSIDEVPAGE0_NP_WIDE)
speed*=2;
printk(" %dMB/sec\n", speed);
} else
printk(" Asynchronous.\n");
} else {
printk("failed\n" );
}
pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4,
pData, cfg_dma_addr);
}
else
qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
break;
}
scsictl = scsidir | qtag;
}
/* Use the above information to set up the message frame
*/
pScsiReq->TargetID = target;
pScsiReq->Bus = hd->port;
pScsiReq->ChainOffset = 0;
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
pScsiReq->CDBLength = SCpnt->cmd_len;
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
pScsiReq->Reserved = 0;
pScsiReq->MsgFlags = mpt_msg_flags();
pScsiReq->LUN[0] = 0;
pScsiReq->LUN[1] = lun;
pScsiReq->LUN[2] = 0;
pScsiReq->LUN[3] = 0;
pScsiReq->LUN[4] = 0;
pScsiReq->LUN[5] = 0;
pScsiReq->LUN[6] = 0;
pScsiReq->LUN[7] = 0;
pScsiReq->Control = cpu_to_le32(scsictl);
#define is_digit(c) ((c) >= '0' && (c) <= '9')
#define digit_to_bin(c) ((c) - '0')
#define is_space(c) ((c) == ' ' || (c) == '\t')
/*
* Write SCSI CDB into the message
*/
cmd_len = SCpnt->cmd_len;
for (ii=0; ii < cmd_len; ii++)
pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
for (ii=cmd_len; ii < 16; ii++)
pScsiReq->CDB[ii] = 0;
static int skip_spaces(char *ptr, int len)
{
int cnt, c;
/* DataLength */
pScsiReq->DataLength = cpu_to_le32(datalen);
for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
/* SenseBuffer low address */
pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
return (len - cnt);
}
/* Now add the SG list
* Always have a SGE even if null length.
*/
rc = SUCCESS;
if (datalen == 0) {
/* Add a NULL SGE */
mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
(dma_addr_t) -1);
} else {
/* Add a 32 or 64 bit SGE */
rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
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;
if (rc == SUCCESS) {
hd->ScsiLookup[my_idx] = SCpnt;
SCpnt->host_scribble = NULL;
return (len - cnt);
}
#ifdef DROP_TEST
numTotCmds++;
/* If the IOC number and target match, increment
* counter. If counter matches DROP_THIS, do not
* issue command to FW to force a reset.
* Save the MF pointer so we can free resources
* when task mgmt completes.
*/
if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
dropCounter++;
if (dropCounter == DROP_THIS_CMD) {
dropCounter = 0;
static int is_keyword(char *ptr, int len, char *verb)
{
int verb_len = strlen(verb);
/* If global is set, then we are already
* doing something - so keep issuing commands.
*/
if (dropMfPtr == NULL) {
dropTestNum++;
dropMfPtr = mf;
atomic_inc(&queue_depth);
printk(MYIOC_s_INFO_FMT
"Dropped SCSI cmd (%p)\n",
hd->ioc->name, SCpnt);
printk("mf (%p) req (%4x) tot cmds (%d)\n",
mf, my_idx, numTotCmds);
if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
return verb_len;
else
return 0;
}
return 0;
}
}
}
#endif
#define SKIP_SPACES(min_spaces) \
if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \
return -EINVAL; \
ptr += arg_len; \
len -= arg_len;
/* SCSI specific processing */
issueCmd = 1;
if (hd->is_spi) {
int dvStatus = hd->ioc->spi_data.dvStatus[target];
#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;
struct mptscsih_usrcmd cmd, *uc = &cmd;
ulong target;
int arg_len;
int len = length;
uc->target = uc->cmd = uc->lun = uc->data = 0;
if ((len > 0) && (ptr[len -1] == '\n'))
--len;
if (dvStatus || hd->ioc->spi_data.forceDv) {
if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0)
uc->cmd = UC_GET_SPEED;
else
arg_len = 0;
/* Write SDP1 on this I/O to this target */
if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
hd->ioc->spi_data.dvStatus[target] = dvStatus;
} else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
hd->ioc->spi_data.dvStatus[target] = dvStatus;
}
dprintk(("user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd));
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) {
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);
MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
if (!arg_len)
return -EINVAL;
SCHEDULE_TASK(&mptscsih_dvTask);
} else {
spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
}
hd->ioc->spi_data.forceDv = 0;
}
ptr += arg_len;
len -= arg_len;
/* Trying to do DV to this target, extend timeout.
* Wait to issue intil flag is clear
*/
if (dvStatus & MPT_SCSICFG_DV_PENDING) {
mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
issueCmd = 0;
}
switch(uc->cmd) {
case UC_GET_SPEED:
SKIP_SPACES(1);
GET_INT_ARG(target);
uc->target = target;
break;
}
/* Set the DV flags.
*/
if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
mptscsih_set_dvflags(hd, pScsiReq);
#endif
}
}
dprintk(("user_command: target=%ld len=%d\n", uc->target, len));
if (issueCmd) {
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
hd->ioc->name, SCpnt, mf, my_idx));
} else {
ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
hd->ioc->name, SCpnt, my_idx));
/* Place this command on the pendingQ if possible */
spin_lock_irqsave(&hd->freedoneQlock, flags);
if (!Q_IS_EMPTY(&hd->freeQ)) {
buffer = hd->freeQ.head;
Q_DEL_ITEM(buffer);
if (len)
return -EINVAL;
else {
/* process this command ...
*/
mptscsih_exec_user_cmd(ioc, uc);
}
/* Not yet implemented */
return length;
}
/* Save the mf pointer
*/
buffer->argp = (void *)mf;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_proc_info - Return information about MPT adapter
*
* (linux Scsi_Host_Template.info routine)
*
* buffer: if write, user data; if read, buffer for user
* length: if write, return length;
* offset: if write, 0; if read, the current offset into the buffer from
* the previous read.
* hostno: scsi host number
* func: if write = 1; if read = 0
*/
int mptscsih_proc_info(char *buffer, char **start, off_t offset,
int length, int hostno, int func)
{
MPT_ADAPTER *ioc = NULL;
MPT_SCSI_HOST *hd = NULL;
int size = 0;
/* Add to the pendingQ
*/
Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
} else {
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
SCpnt->result = (DID_BUS_BUSY << 16);
SCpnt->scsi_done(SCpnt);
}
dprintk(("Called mptscsih_proc_info: hostno=%d, func=%d\n", hostno, func));
dprintk(("buffer %p, start=%p (%p) offset=%ld length = %d\n",
buffer, start, *start, offset, length));
for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
if ((ioc->sh) && (ioc->sh->host_no == hostno)) {
hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
break;
}
}
if ((ioc == NULL) || (ioc->sh == NULL) || (hd == NULL))
return 0;
if (func) {
size = mptscsih_user_command(ioc, buffer, length);
} else {
mptscsih_freeChainBuffers(hd, my_idx);
mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
did_errcode = 3;
goto did_error;
if (start)
*start = buffer;
size = mptscsih_host_info(ioc, buffer, offset, length);
}
return 0;
return size;
}
did_error:
dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
hd->ioc->name, did_errcode, SCpnt));
/* Just wish OS to issue a retry */
SCpnt->result = (DID_BUS_BUSY << 16);
spin_lock_irqsave(&hd->freedoneQlock, flags);
if (!Q_IS_EMPTY(&hd->freeQ)) {
buffer = hd->freeQ.head;
Q_DEL_ITEM(buffer);
/* Set the Scsi_Cmnd pointer
*/
buffer->argp = (void *)SCpnt;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int max_qd = 1;
#if 0
static int index_log[128];
static int index_ent = 0;
static __inline__ void ADD_INDEX_LOG(int req_ent)
{
int i = index_ent++;
/* Add to the doneQ
*/
Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
} else {
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
SCpnt->scsi_done(SCpnt);
index_log[i & (128 - 1)] = req_ent;
}
#else
#define ADD_INDEX_LOG(req_ent) do { } while(0)
#endif
#ifdef DROP_TEST
#define DROP_IOC 1 /* IOC to force failures */
#define DROP_TARGET 3 /* Target ID to force failures */
#define DROP_THIS_CMD 10000 /* iteration to drop command */
static int dropCounter = 0;
static int dropTestOK = 0; /* num did good */
static int dropTestBad = 0; /* num did bad */
static int dropTestNum = 0; /* total = good + bad + incomplete */
static int numTotCmds = 0;
static MPT_FRAME_HDR *dropMfPtr = NULL;
static int numTMrequested = 0;
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
* @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
* @id: IOC id number
* @mf: Pointer to message frame
*
* Handles the call to mptbase for posting request and queue depth
* tracking.
*
* Returns none.
*/
static inline void
mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
{
/* Main banana... */
atomic_inc(&queue_depth);
if (atomic_read(&queue_depth) > max_qd) {
max_qd = atomic_read(&queue_depth);
dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
}
return 0;
mpt_put_msg_frame(context, id, mf);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
* SCSIIORequest_t Message Frame.
* @hd: Pointer to MPT_SCSI_HOST structure
/**
* mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
* @SCpnt: Pointer to Scsi_Cmnd structure
* @pReq: Pointer to SCSIIORequest_t structure
* @done: Pointer SCSI mid-layer IO completion function
*
* Returns ...
* (linux Scsi_Host_Template.queuecommand routine)
* This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
* from a linux Scsi_Cmnd request and send it to the IOC.
*
* Returns 0. (rtn value discarded by linux scsi mid-layer)
*/
static int
mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
SCSIIORequest_t *pReq, int req_idx)
int
mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
char *psge;
char *chainSge;
struct scatterlist *sg;
int frm_sz;
int sges_left, sg_done;
int chain_idx = MPT_HOST_NO_CHAIN;
int sgeOffset;
int numSgeSlots, numSgeThisFrame;
u32 sgflags, sgdir, thisxfer = 0;
int chain_dma_off = 0;
int newIndex;
MPT_SCSI_HOST *hd;
MPT_FRAME_HDR *mf;
SCSIIORequest_t *pScsiReq;
VirtDevice *pTarget;
MPT_DONE_Q *buffer = NULL;
unsigned long flags;
int target;
int lun;
int datadir;
u32 datalen;
u32 scsictl;
u32 scsidir;
u32 qtag;
u32 cmd_len;
int my_idx;
int ii;
dma_addr_t v2;
int rc;
int did_errcode;
int issueCmd;
sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
sgdir = MPT_TRANSFER_HOST_TO_IOC;
} else {
sgdir = MPT_TRANSFER_IOC_TO_HOST;
}
did_errcode = 0;
hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
target = SCpnt->target;
lun = SCpnt->lun;
SCpnt->scsi_done = done;
psge = (char *) &pReq->SGL;
frm_sz = hd->ioc->req_sz;
pTarget = hd->Targets[target];
/* Map the data portion, if any.
* sges_left = 0 if no data transfer.
dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
#ifdef MPT_SAVE_AUTOSENSE
/* 20000617 -sralston
* GRRRRR... Shouldn't have to do this but...
* Do explicit check for REQUEST_SENSE and cached SenseData.
* If yes, return cached SenseData.
*/
sges_left = SCpnt->use_sg;
if (SCpnt->use_sg) {
sges_left = pci_map_sg(hd->ioc->pcidev,
(struct scatterlist *) SCpnt->request_buffer,
SCpnt->use_sg,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
} else if (SCpnt->request_bufflen) {
dma_addr_t buf_dma_addr;
scPrivate *my_priv;
if (SCpnt->cmnd[0] == REQUEST_SENSE) {
u8 *dest = NULL;
int sz;
buf_dma_addr = pci_map_single(hd->ioc->pcidev,
SCpnt->request_buffer,
SCpnt->request_bufflen,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE; //sjr-moved-here
if (!SCpnt->use_sg) {
dest = SCpnt->request_buffer;
} else {
struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
if (sg)
dest = (u8 *)(ulong)sg_dma_address(sg);
}
if (dest) {
sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
memcpy(dest, pTarget->sense, sz);
/* We hide it here for later unmap. */
my_priv = (scPrivate *) &SCpnt->SCp;
my_priv->p1 = (void *)(ulong) buf_dma_addr;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
SCpnt->resid = SCpnt->request_bufflen - sz;
#endif
SCpnt->result = 0;
SCpnt->scsi_done(SCpnt);
dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
hd->ioc->name, SCpnt, SCpnt->request_bufflen));
//sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
mpt_add_sge((char *) &pReq->SGL,
0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
buf_dma_addr);
return 0;
}
}
}
#endif
return SUCCESS;
if (hd->resetPending) {
/* Prevent new commands from being issued
* while reloading the FW.
*/
did_errcode = 1;
goto did_error;
}
/* Handle the SG case.
/*
* Put together a MPT SCSI request...
*/
sg = (struct scatterlist *) SCpnt->request_buffer;
sg_done = 0;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
chainSge = NULL;
if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
hd->ioc->name));
did_errcode = 2;
goto did_error;
}
/* Prior to entering this loop - the following must be set
* current MF: sgeOffset (bytes)
* chainSge (Null if original MF is not a chain buffer)
* sg_done (num SGE done for this MF)
*/
pScsiReq = (SCSIIORequest_t *) mf;
nextSGEset:
numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
ADD_INDEX_LOG(my_idx);
/* Get first (num - 1) SG elements
* Skip any SG entries with a length of 0
* NOTE: at finish, sg and psge pointed to NEXT data/location positions
/*
* The scsi layer should be handling this stuff
* (In 2.3.x it does -DaveM)
*/
for (ii=0; ii < (numSgeThisFrame-1); ii++) {
thisxfer = sg_dma_len(sg);
if (thisxfer == 0) {
sg ++; /* Get next SG element from the OS */
sg_done++;
continue;
}
v2 = sg_dma_address(sg);
mpt_add_sge(psge, sgflags | thisxfer, v2);
sg++; /* Get next SG element from the OS */
psge += (sizeof(u32) + sizeof(dma_addr_t));
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
/* BUG FIX! 19991030 -sralston
* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
* Seems we may receive a buffer (datalen>0) even when there
* will be no data transfer! GRRRRR...
*/
datadir = mptscsih_io_direction(SCpnt);
if (datadir == SCSI_DATA_READ) {
datalen = SCpnt->request_bufflen;
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
} else if (datadir == SCSI_DATA_WRITE) {
datalen = SCpnt->request_bufflen;
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
} else {
datalen = 0;
scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
}
if (numSgeThisFrame == sges_left) {
/* Add last element, end of buffer and end of list flags.
*/
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
MPT_SGE_FLAGS_END_OF_BUFFER |
MPT_SGE_FLAGS_END_OF_LIST;
/* Add last SGE and set termination flags.
* Note: Last SGE may have a length of 0 - which should be ok.
/* Default to untagged. Once a target structure has been allocated,
* use the Inquiry data to determine if device supports tagged.
*/
qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
&& (SCpnt->device->tagged_supported)) {
/*
* Some drives are too stupid to handle fairness issues
* with tagged queueing. We throw in the odd ordered
* tag to stop them starving themselves.
*/
thisxfer = sg_dma_len(sg);
if ((jiffies - hd->qtag_tick) > (5*HZ)) {
qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
hd->qtag_tick = jiffies;
}
else
qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
}
scsictl = scsidir | qtag;
v2 = sg_dma_address(sg);
mpt_add_sge(psge, sgflags | thisxfer, v2);
/*
sg++;
psge += (sizeof(u32) + sizeof(dma_addr_t));
*/
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
/* Use the above information to set up the message frame
*/
pScsiReq->TargetID = target;
pScsiReq->Bus = hd->port;
pScsiReq->ChainOffset = 0;
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
pScsiReq->CDBLength = SCpnt->cmd_len;
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
pScsiReq->Reserved = 0;
pScsiReq->MsgFlags = mpt_msg_flags();
pScsiReq->LUN[0] = 0;
pScsiReq->LUN[1] = lun;
pScsiReq->LUN[2] = 0;
pScsiReq->LUN[3] = 0;
pScsiReq->LUN[4] = 0;
pScsiReq->LUN[5] = 0;
pScsiReq->LUN[6] = 0;
pScsiReq->LUN[7] = 0;
pScsiReq->Control = cpu_to_le32(scsictl);
if (chainSge) {
/* The current buffer is a chain buffer,
* but there is not another one.
* Update the chain element
* Offset and Length fields.
*/
mpt_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
} else {
/* The current buffer is the original MF
* and there is no Chain buffer.
*/
pReq->ChainOffset = 0;
}
} else {
/* At least one chain buffer is needed.
* Complete the first MF
* - last SGE element, set the LastElement bit
* - set ChainOffset (words) for orig MF
* (OR finish previous MF chain buffer)
* - update MFStructPtr ChainIndex
* - Populate chain element
* Also
* Loop until done.
*/
/*
* Write SCSI CDB into the message
* Should write from cmd_len up to 16, but skip for performance reasons.
*/
cmd_len = SCpnt->cmd_len;
for (ii=0; ii < cmd_len; ii++)
pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
hd->ioc->name, sg_done));
/* DataLength */
pScsiReq->DataLength = cpu_to_le32(datalen);
/* Set LAST_ELEMENT flag for last non-chain element
* in the buffer. Since psge points at the NEXT
* SGE element, go back one SGE element, update the flags
* and reset the pointer. (Note: sgflags & thisxfer are already
* set properly).
*/
if (sg_done) {
u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
sgflags = le32_to_cpu(*ptmp);
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
*ptmp = cpu_to_le32(sgflags);
}
/* SenseBuffer low address */
pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
if (chainSge) {
/* The current buffer is a chain buffer.
* chainSge points to the previous Chain Element.
* Update its chain element Offset and Length (must
* include chain element size) fields.
* Old chain element is now complete.
*/
u8 nextChain = (u8) (sgeOffset >> 2);
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
} else {
/* The original MF buffer requires a chain buffer -
* set the offset.
* Last element in this MF is a chain element.
*/
pReq->ChainOffset = (u8) (sgeOffset >> 2);
}
/* 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 */
rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
}
sges_left -= sg_done;
if (rc == SUCCESS) {
hd->ScsiLookup[my_idx] = SCpnt;
SCpnt->host_scribble = NULL;
/* NOTE: psge points to the beginning of the chain element
* in current buffer. Get a chain buffer.
#ifdef DROP_TEST
numTotCmds++;
/* If the IOC number and target match, increment
* counter. If counter matches DROP_THIS, do not
* issue command to FW to force a reset.
* Save the MF pointer so we can free resources
* when task mgmt completes.
*/
if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
return FAILED;
if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
dropCounter++;
/* Update the tracking arrays.
* If chainSge == NULL, update ReqToChain, else ChainToChain
*/
if (chainSge) {
hd->ChainToChain[chain_idx] = newIndex;
} else {
hd->ReqToChain[req_idx] = newIndex;
if (dropCounter == DROP_THIS_CMD) {
dropCounter = 0;
/* If global is set, then we are already
* doing something - so keep issuing commands.
*/
if (dropMfPtr == NULL) {
dropTestNum++;
dropMfPtr = mf;
atomic_inc(&queue_depth);
printk(MYIOC_s_INFO_FMT
"Dropped SCSI cmd (%p)\n",
hd->ioc->name, SCpnt);
printk("mf (%p) req (%4x) tot cmds (%d)\n",
mf, my_idx, numTotCmds);
return 0;
}
}
}
chain_idx = newIndex;
chain_dma_off = hd->ioc->req_sz * chain_idx;
#endif
/* Populate the chainSGE for the current buffer.
* - Set chain buffer pointer to psge and fill
* out the Address and Flags fields.
*/
chainSge = (char *) psge;
dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
psge, req_idx));
/* SCSI specific processing */
issueCmd = 1;
if (hd->is_spi) {
int dvStatus = hd->ioc->spi_data.dvStatus[target];
/* Start the SGE for the next buffer
*/
psge = (char *) (hd->ChainBuffer + chain_dma_off);
sgeOffset = 0;
sg_done = 0;
if (dvStatus || hd->ioc->spi_data.forceDv) {
dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
psge, chain_idx));
/* Write SDP1 on this I/O to this target */
if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
hd->ioc->spi_data.dvStatus[target] = dvStatus;
} else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
hd->ioc->spi_data.dvStatus[target] = dvStatus;
}
/* Start the SGE for the next buffer
*/
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
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);
MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
goto nextSGEset;
}
SCHEDULE_TASK(&mptscsih_dvTask);
} else {
spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
}
hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
}
return SUCCESS;
}
/* Trying to do DV to this target, extend timeout.
* Wait to issue intil flag is clear
*/
if (dvStatus & MPT_SCSICFG_DV_PENDING) {
mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
issueCmd = 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_getFreeChainBuffes - Function to get a free chain
* from the MPT_SCSI_HOST FreeChainQ.
* @hd: Pointer to the MPT_SCSI_HOST instance
* @req_idx: Index of the SCSI IO request frame. (output)
*
* return SUCCESS or FAILED
*/
static int
mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
{
MPT_FRAME_HDR *chainBuf = NULL;
unsigned long flags;
int rc = FAILED;
int chain_idx = MPT_HOST_NO_CHAIN;
/* Set the DV flags.
*/
if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
mptscsih_set_dvflags(hd, pScsiReq);
#endif
}
}
//spin_lock_irqsave(&hd->FreeChainQlock, flags);
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
if (issueCmd) {
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
hd->ioc->name, SCpnt, mf, my_idx));
} else {
ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
hd->ioc->name, SCpnt, my_idx));
/* Place this command on the pendingQ if possible */
spin_lock_irqsave(&hd->freedoneQlock, flags);
if (!Q_IS_EMPTY(&hd->freeQ)) {
buffer = hd->freeQ.head;
Q_DEL_ITEM(buffer);
int offset;
/* Save the mf pointer
*/
buffer->argp = (void *)mf;
chainBuf = hd->FreeChainQ.head;
Q_DEL_ITEM(&chainBuf->u.frame.linkage);
offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
chain_idx = offset / hd->ioc->req_sz;
rc = SUCCESS;
/* Add to the pendingQ
*/
Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
} else {
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
SCpnt->result = (DID_BUS_BUSY << 16);
SCpnt->scsi_done(SCpnt);
}
}
} else {
mptscsih_freeChainBuffers(hd, my_idx);
mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
did_errcode = 3;
goto did_error;
}
//spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
return 0;
*retIndex = chain_idx;
did_error:
dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
hd->ioc->name, did_errcode, SCpnt));
/* Just wish OS to issue a retry */
SCpnt->result = (DID_BUS_BUSY << 16);
spin_lock_irqsave(&hd->freedoneQlock, flags);
if (!Q_IS_EMPTY(&hd->freeQ)) {
buffer = hd->freeQ.head;
Q_DEL_ITEM(buffer);
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
hd->ioc->name, *retIndex, chainBuf));
/* Set the Scsi_Cmnd pointer
*/
buffer->argp = (void *)SCpnt;
return rc;
/* Add to the doneQ
*/
Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
} else {
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
SCpnt->scsi_done(SCpnt);
}
return 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
......@@ -2547,8 +3009,8 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort,
#ifdef MPT_DEBUG_RESET
if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
printk(MYIOC_s_WARN_FMT
"TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n",
printk(MYIOC_s_WARN_FMT
"TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n",
hd->ioc->name, ioc_raw_state);
}
#endif
......@@ -2765,7 +3227,7 @@ mptscsih_abort(Scsi_Cmnd * SCpnt)
hd->abortSCpnt = SCpnt;
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
< 0) {
/* The TM request failed and the subsequent FW-reload failed!
......@@ -2830,7 +3292,7 @@ mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
}
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
SCpnt->target, 0, 0, NO_SLEEP)
SCpnt->target, 0, 0, NO_SLEEP)
< 0){
/* The TM request failed and the subsequent FW-reload failed!
* Fatal error case.
......@@ -2889,13 +3351,13 @@ mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
/* We are now ready to execute the task management request. */
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
0, 0, 0, NO_SLEEP)
0, 0, 0, NO_SLEEP)
< 0){
/* The TM request failed and the subsequent FW-reload failed!
* Fatal error case.
*/
printk(MYIOC_s_WARN_FMT
printk(MYIOC_s_WARN_FMT
"Error processing TaskMgmt request (sc=%p)\n",
hd->ioc->name, SCpnt);
hd->tmPending = 0;
......@@ -2941,8 +3403,8 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt)
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0){
status = FAILED;
} else {
/* Make sure TM pending is cleared and TM state is set to
* NONE.
/* Make sure TM pending is cleared and TM state is set to
* NONE.
*/
hd->tmPending = 0;
hd->tmState = TM_STATE_NONE;
......@@ -2958,7 +3420,7 @@ mptscsih_host_reset(Scsi_Cmnd *SCpnt)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_tm_pending_wait - wait for pending task management request to
* mptscsih_tm_pending_wait - wait for pending task management request to
* complete.
* @hd: Pointer to MPT host structure.
*
......@@ -3114,7 +3576,7 @@ mptscsih_old_abort(Scsi_Cmnd *SCpnt)
* (bottom/unused portion of) MPT request frame.
*/
ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
SCHEDULE_TASK(ptaskfoo);
} else {
......@@ -3245,7 +3707,7 @@ mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
* (bottom/unused portion of) MPT request frame.
*/
ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
SCHEDULE_TASK(ptaskfoo);
} else {
......@@ -3599,7 +4061,7 @@ mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
* Called once per device the bus scan. Use it to force the queue_depth
* member to 1 if a device does not support Q tags.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
int
mptscsih_slave_configure(Scsi_Device *device)
{
......@@ -3614,15 +4076,21 @@ mptscsih_slave_configure(Scsi_Device *device)
if (!device->tagged_supported ||
!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
scsi_adjust_queue_depth(device, 0, 1);
} else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)
&& (pTarget->inq_data[0] & 0x1f) == 0x00
&& (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
MPT_SCSI_CMD_PER_DEV_HIGH);
} else {
scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
device->host->can_queue >> 1);
scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
MPT_SCSI_CMD_PER_DEV_LOW);
}
}
}
return 0;
}
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) */
void
mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
{
......@@ -3648,113 +4116,32 @@ mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
for (ii=0; ii < max; ii++) {
pTarget = hd->Targets[ii];
if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
if (pTarget == NULL) {
continue;
}
if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
device->queue_depth = 1;
} else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)
&& (pTarget->inq_data[0] & 0x1f) == 0x00
&& (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
device->queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
} else {
device->queue_depth = MPT_SCSI_CMD_PER_DEV_LOW;
}
dprintk((MYIOC_s_INFO_FMT
"target = %d, sync factor = %#x, queue depth = %d\n",
hd->ioc->name, pTarget->target_id,
pTarget->minSyncFactor, device->queue_depth));
}
}
}
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52) */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Private routines...
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* 19991030 -sralston
* Return absolute SCSI data direction:
* 1 = _DATA_OUT
* 0 = _DIR_NONE
* -1 = _DATA_IN
*
* Changed: 3-20-2002 pdelaney to use the default data
* direction and the defines set up in the
* 2.4 kernel series
* 1 = _DATA_OUT changed to SCSI_DATA_WRITE (1)
* 0 = _DIR_NONE changed to SCSI_DATA_NONE (3)
* -1 = _DATA_IN changed to SCSI_DATA_READ (2)
* If the direction is unknown, fall through to original code.
*
* Mid-layer bug fix(): sg interface generates the wrong data
* direction in some cases. Set the direction the hard way for
* the most common commands.
*/
static int
mptscsih_io_direction(Scsi_Cmnd *cmd)
{
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
return SCSI_DATA_WRITE;
break;
case READ_6:
case READ_10:
return SCSI_DATA_READ;
break;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
return cmd->sc_data_direction;
#endif
switch (cmd->cmnd[0]) {
/* _DATA_OUT commands */
case WRITE_6: case WRITE_10: case WRITE_12:
case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
case WRITE_VERIFY: case WRITE_VERIFY_12:
case COMPARE: case COPY: case COPY_VERIFY:
case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
case REASSIGN_BLOCKS:
case PERSISTENT_RESERVE_OUT:
case 0xea:
case 0xa3:
return SCSI_DATA_WRITE;
/* No data transfer commands */
case SEEK_6: case SEEK_10:
case RESERVE: case RELEASE:
case TEST_UNIT_READY:
case START_STOP:
case ALLOW_MEDIUM_REMOVAL:
return SCSI_DATA_NONE;
/* Conditional data transfer commands */
case FORMAT_UNIT:
if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */
return SCSI_DATA_WRITE;
else
return SCSI_DATA_NONE;
case VERIFY:
if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */
return SCSI_DATA_WRITE;
else
return SCSI_DATA_NONE;
case RESERVE_10:
if (cmd->cmnd[1] & 0x03) /* RESERVE:{LongID|Extent} (data out phase)? */
return SCSI_DATA_WRITE;
else
return SCSI_DATA_NONE;
#if 0
case REZERO_UNIT: /* (or REWIND) */
case SPACE:
case ERASE: case ERASE_10:
case SYNCHRONIZE_CACHE:
case LOCK_UNLOCK_CACHE:
#endif
/* Must be data _IN! */
default:
return SCSI_DATA_READ;
}
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* Utility function to copy sense data from the scsi_cmnd buffer
......@@ -3803,7 +4190,7 @@ copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply
#ifdef ABORT_FIX
if (sz >= SCSI_STD_SENSE_BYTES) {
if ((sense_data[02] == ABORTED_COMMAND) &&
if ((sense_data[02] == ABORTED_COMMAND) &&
(sense_data[12] == 0x47) && (sense_data[13] == 0x00)){
target->numAborts++;
if ((target->raidVolume == 0) && (target->numAborts > 5)) {
......@@ -3896,7 +4283,7 @@ SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* Search the pendingQ for a command with specific index.
* If found, delete and return mf pointer
* If found, delete and return mf pointer
* If not found, return NULL
*/
static MPT_FRAME_HDR *
......@@ -4126,6 +4513,13 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
ioc->name));
/* 8. Set flag to force DV and re-read IOC Page 3
*/
ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
ddvtprintk(("Set reload IOC Pg3 Flag\n"));
}
return 1; /* currently means nothing really */
......@@ -4172,7 +4566,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
case MPI_EVENT_INTEGRATED_RAID: /* 0B */
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
/* negoNvram set to 0 if DV enabled and to USE_NVRAM if
/* negoNvram set to 0 if DV enabled and to USE_NVRAM if
* if DV disabled. Need to check for target mode.
*/
hd = NULL;
......@@ -4188,11 +4582,12 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
/* New or replaced disk.
/* New or replaced disk.
* Set DV flag and schedule DV.
*/
pSpi = &ioc->spi_data;
physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
if (pSpi->pIocPg3) {
pPDisk = pSpi->pIocPg3->PhysDisk;
numPDisk =pSpi->pIocPg3->NumPhysDisks;
......@@ -4207,6 +4602,16 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
pPDisk++;
numPDisk--;
}
if (numPDisk == 0) {
/* The physical disk that needs DV was not found
* in the stored IOC Page 3. The driver must reload
* this page. DV routine will set the NEED_DV flag for
* all phys disks that have DV_NOT_DONE set.
*/
pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
}
}
}
}
......@@ -4670,7 +5075,7 @@ int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
if (ioop->cdbPtr == NULL) {
return 0;
} else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) ||
(ioop->cdbPtr[0] == CMD_ReadCapacity) ||
(ioop->cdbPtr[0] == CMD_ReadCapacity) ||
(ioop->cdbPtr[0] == 0x43)) {
return 0;
}
......@@ -4794,7 +5199,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *
}
if (vdev && data) {
if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) ||
if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) ||
((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) {
/* Copy the inquiry data - if we haven't yet.
......@@ -4877,7 +5282,7 @@ void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byt
factor = MPT_ULTRA320;
/* If RAID, never disable QAS
* else if non RAID, do not disable
* else if non RAID, do not disable
* QAS if bit 1 is set
* bit 1 QAS support, non-raid only
* bit 0 IU support
......@@ -5000,8 +5405,8 @@ static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
#endif
/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
* Else set the NEED_DV flag after Read Capacity Issued (disks)
* or Mode Sense (cdroms).
* Else set the NEED_DV flag after Read Capacity Issued (disks)
* or Mode Sense (cdroms).
*
* Tapes, initTarget will set this flag on completion of Inquiry command.
* Called only if DV_NOT_DONE flag is set
......@@ -5037,7 +5442,7 @@ static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* If no Target, bus reset on 1st I/O. Set the flag to
* If no Target, bus reset on 1st I/O. Set the flag to
* prevent any future negotiations to this device.
*/
static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
......@@ -5286,9 +5691,9 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
pData->Reserved = 0;
pData->Configuration = cpu_to_le32(configuration);
dprintk((MYIOC_s_INFO_FMT
dprintk((MYIOC_s_INFO_FMT
"write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
ioc->name, id, (id | (bus<<8)),
ioc->name, id, (id | (bus<<8)),
requested, configuration));
mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
......@@ -5327,8 +5732,8 @@ static void mptscsih_taskmgmt_timeout(unsigned long data)
/* Because we have reset the IOC, no TM requests can be
* pending. So let's make sure the tmPending flag is reset.
*/
nehprintk((KERN_WARNING MYNAM
": %s: mptscsih_taskmgmt_timeout\n",
nehprintk((KERN_WARNING MYNAM
": %s: mptscsih_taskmgmt_timeout\n",
hd->ioc->name));
hd->tmPending = 0;
}
......@@ -5566,7 +5971,7 @@ static void mptscsih_timer_expired(unsigned long data)
if (hd->tmPending) {
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
return;
} else
} else
hd->tmPending = 1;
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
......@@ -5645,7 +6050,7 @@ mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
pReq->ActionDataWord = 0; /* Reserved for this action */
//pReq->ActionDataSGE = 0;
mpt_add_sge((char *)&pReq->ActionDataSGE,
mpt_add_sge((char *)&pReq->ActionDataSGE,
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
......@@ -5974,7 +6379,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
if (id == hostId)
id++;
/* Write SDP1 for all SCSI devices
/* Write SDP1 for all SCSI devices
* Alloc memory and set up config buffer
*/
if (hd->is_spi) {
......@@ -6097,7 +6502,7 @@ mptscsih_domainValidation(void *arg)
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
/* For this ioc, loop through all devices and do dv to each device.
* When complete with this ioc, search through the ioc list, and
* When complete with this ioc, search through the ioc list, and
* for each scsi ioc found, do dv for all devices. Exit when no
* device needs dv.
*/
......@@ -6128,6 +6533,23 @@ mptscsih_domainValidation(void *arg)
if (hd == NULL)
continue;
if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
mpt_read_ioc_pg_3(ioc);
if (ioc->spi_data.pIocPg3) {
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
while (numPDisk) {
if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
pPDisk++;
numPDisk--;
}
}
ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
}
maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
for (id = 0; id < maxid; id++) {
......@@ -6318,7 +6740,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
lun = 0;
bus = 0;
ddvtprintk((MYIOC_s_NOTE_FMT
ddvtprintk((MYIOC_s_NOTE_FMT
"DV started: numIOs %d bus=%d, id %d dv @ %p\n",
ioc->name, atomic_read(&queue_depth), bus, id, &dv));
......@@ -6423,7 +6845,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
/* Skip this ID? Set cfg.hdr to force config page write
*/
if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) &&
(!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) {
(!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) {
ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
ioc->name, bus, id, lun));
......@@ -6495,11 +6917,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
/* Wide - narrow - wide workaround case
*/
if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
/* Send an untagged command to reset disk Qs corrupted
* when a parity error occurs on a Request Sense.
*/
if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
(hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
......@@ -6535,7 +6957,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
rc = hd->pLocal->completion;
if (rc == MPT_SCANDV_GOOD) {
if (hd->pLocal->scsiStatus == STS_BUSY) {
retcode = 1;
if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
retcode = 1;
else
retcode = 0;
goto target_done;
}
} else if (rc == MPT_SCANDV_SENSE) {
......@@ -6607,7 +7033,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
* Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
* Resetart with a request for U160.
*/
if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
doFallback = 1;
} else {
dv.cmd = MPT_UPDATE_MAX;
......@@ -6631,7 +7057,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
}
} else if (rc == MPT_SCANDV_ISSUE_SENSE)
} else if (rc == MPT_SCANDV_ISSUE_SENSE)
doFallback = 1; /* set fallback flag */
else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
doFallback = 1; /* set fallback flag */
......@@ -6871,7 +7297,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
mdelay (2000);
notDone++;
} else {
ddvprintk((MYIOC_s_INFO_FMT
ddvprintk((MYIOC_s_INFO_FMT
"DV: Reserved Failed.", ioc->name));
goto target_done;
}
......@@ -6935,7 +7361,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
patt = -1;
continue;
}
}
}
goto target_done;
}
else
......@@ -7048,7 +7474,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
if (hd->pLocal->completion == MPT_SCANDV_GOOD)
iocmd.flags &= ~MPT_ICFLAG_RESERVED;
} else {
printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
ioc->name, id);
}
}
......@@ -7066,7 +7492,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
#if 0
/* Double writes to SDP1 can cause problems,
/* Double writes to SDP1 can cause problems,
* skip here since unnecessary
*/
/* Save the final negotiated settings to
......@@ -7222,7 +7648,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
case MPT_SET_MIN:
ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
hd->ioc->name));
/* Set page to asynchronous and narrow
/* Set page to asynchronous and narrow
* Do not update now, breaks fallback routine. */
width = MPT_NARROW;
offset = 0;
......@@ -7244,7 +7670,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
case MPT_FALLBACK:
ddvprintk((MYIOC_s_NOTE_FMT
"Fallback: Start: offset %d, factor %x, width %d \n",
hd->ioc->name, dv->now.offset,
hd->ioc->name, dv->now.offset,
dv->now.factor, dv->now.width));
width = dv->now.width;
offset = dv->now.offset;
......
......@@ -20,7 +20,7 @@
* (mailto:netscape.net)
* (mailto:Pam.Delaney@lsil.com)
*
* $Id: mptscsih.h,v 1.20 2002/10/17 20:16:00 pdelaney Exp $
* $Id: mptscsih.h,v 1.21 2002/12/03 21:26:35 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -73,9 +73,16 @@
* Try to keep these at 2^N-1
*/
#define MPT_FC_CAN_QUEUE 63
//#define MPT_SCSI_CAN_QUEUE 31
#define MPT_SCSI_CAN_QUEUE MPT_FC_CAN_QUEUE
#define MPT_SCSI_CMD_PER_LUN 7
#if defined MPT_SCSI_USE_NEW_EH
#define MPT_SCSI_CAN_QUEUE 127
#else
#define MPT_SCSI_CAN_QUEUE 63
#endif
#define MPT_SCSI_CMD_PER_DEV_HIGH 31
#define MPT_SCSI_CMD_PER_DEV_LOW 7
#define MPT_SCSI_CMD_PER_LUN 7
#define MPT_SCSI_MAX_SECTORS 8192
......@@ -206,11 +213,16 @@ struct mptscsih_driver_setup
#define x_scsi_dev_reset mptscsih_dev_reset
#define x_scsi_host_reset mptscsih_host_reset
#define x_scsi_bios_param mptscsih_bios_param
#define x_scsi_slave_configure mptscsih_slave_configure
#define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh
#define x_scsi_old_abort mptscsih_old_abort
#define x_scsi_old_reset mptscsih_old_reset
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
#define x_scsi_slave_configure mptscsih_slave_configure
#else
#define x_scsi_select_queue_depths mptscsih_select_queue_depths
#endif
#define x_scsi_proc_info mptscsih_proc_info
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
......@@ -237,8 +249,14 @@ extern int x_scsi_bios_param(Disk *, struct block_device *, int *);
#else
extern int x_scsi_bios_param(Disk *, kdev_t, int *);
#endif
extern int x_scsi_slave_configure(Scsi_Device *);
extern void x_scsi_taskmgmt_bh(void *);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
extern int x_scsi_slave_configure(Scsi_Device *);
#else
extern void x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
#endif
extern int x_scsi_proc_info(char *, char **, off_t, int, int, int);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#define PROC_SCSI_DECL
......@@ -248,14 +266,19 @@ extern void x_scsi_taskmgmt_bh(void *);
#ifdef MPT_SCSI_USE_NEW_EH
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
#define MPT_SCSIHOST { \
PROC_SCSI_DECL \
.proc_info = x_scsi_proc_info, \
.name = "MPT SCSI Host", \
.detect = x_scsi_detect, \
.release = x_scsi_release, \
.info = x_scsi_info, \
.command = NULL, \
.queuecommand = x_scsi_queuecommand, \
.slave_configure = x_scsi_slave_configure, \
.eh_strategy_handler = NULL, \
.eh_abort_handler = x_scsi_abort, \
.eh_device_reset_handler = x_scsi_dev_reset, \
.eh_bus_reset_handler = x_scsi_bus_reset, \
......@@ -275,6 +298,7 @@ extern void x_scsi_taskmgmt_bh(void *);
#define MPT_SCSIHOST { \
.next = NULL, \
PROC_SCSI_DECL \
.proc_info = x_scsi_proc_info, \
.name = "MPT SCSI Host", \
.detect = x_scsi_detect, \
.release = x_scsi_release, \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment