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