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,30 +246,12 @@ static __inline__ int __get_order(unsigned long size) ...@@ -246,30 +246,12 @@ 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)
...@@ -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);
...@@ -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;
...@@ -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,12 +1509,6 @@ mpt_adapter_install(struct pci_dev *pdev) ...@@ -1498,12 +1509,6 @@ 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.
*/ */
...@@ -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");
...@@ -1714,6 +1722,10 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ...@@ -1714,6 +1722,10 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
*/ */
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);
...@@ -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) {
...@@ -3254,11 +3271,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) ...@@ -3254,11 +3271,7 @@ 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);
} }
...@@ -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
...@@ -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);
...@@ -4446,6 +4458,11 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) ...@@ -4446,6 +4458,11 @@ 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;
} }
...@@ -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,6 +4554,35 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) ...@@ -4541,6 +4554,35 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
/* No physical disks. Done. /* No physical disks. Done.
*/ */
} else { } else {
mpt_read_ioc_pg_3(ioc);
}
done_and_free:
if (pIoc2) {
pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
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. /* There is at least one physical disk.
* Read and save IOC Page 3 * Read and save IOC Page 3
*/ */
...@@ -4555,17 +4597,17 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) ...@@ -4555,17 +4597,17 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
cfg.dir = 0; cfg.dir = 0;
cfg.timeout = 0; cfg.timeout = 0;
if (mpt_config(ioc, &cfg) != 0) if (mpt_config(ioc, &cfg) != 0)
goto done_and_free; return 0;
if (header.PageLength == 0) if (header.PageLength == 0)
goto done_and_free; return 0;
/* Read Header good, alloc memory /* Read Header good, alloc memory
*/ */
iocpage3sz = header.PageLength * 4; iocpage3sz = header.PageLength * 4;
pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma); pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
if (!pIoc3) if (!pIoc3)
goto done_and_free; return 0;
/* Read the Page and save the data /* Read the Page and save the data
* into malloc'd memory. * into malloc'd memory.
...@@ -4579,22 +4621,101 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) ...@@ -4579,22 +4621,101 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem; ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
} }
} }
}
done_and_free:
if (pIoc2) {
pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
pIoc2 = NULL;
}
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;
} }
...@@ -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,6 +134,8 @@ ...@@ -134,6 +134,8 @@
#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.
*/ */
...@@ -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);
...@@ -272,6 +270,436 @@ static int scandv_wait_done = 1; ...@@ -272,6 +270,436 @@ static int scandv_wait_done = 1;
static struct mptscsih_driver_setup static struct mptscsih_driver_setup
driver_setup = MPTSCSIH_DRIVER_SETUP; driver_setup = MPTSCSIH_DRIVER_SETUP;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Private inline 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 inline 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;
/* Must be data _IN! */
default:
return SCSI_DATA_READ;
}
} /* mptscsih_io_direction() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* 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;
pSge->FlagsLength = cpu_to_le32(flagslength);
pSge->Address.Low = cpu_to_le32(tmp);
tmp = (u32) ((u64)dma_addr >> 32);
pSge->Address.High = cpu_to_le32(tmp);
} else {
SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
pSge->FlagsLength = cpu_to_le32(flagslength);
pSge->Address = cpu_to_le32(dma_addr);
}
} /* mptscsih_add_sge() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* 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;
pChain->Length = cpu_to_le16(length);
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
pChain->NextChainOffset = next;
pChain->Address.Low = cpu_to_le32(tmp);
tmp = (u32) ((u64)dma_addr >> 32);
pChain->Address.High = cpu_to_le32(tmp);
} else {
SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
pChain->Length = cpu_to_le16(length);
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
pChain->NextChainOffset = next;
pChain->Address = cpu_to_le32(dma_addr);
}
} /* mptscsih_add_chain() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_getFreeChainBuffes - Function to get a free chain
* from the MPT_SCSI_HOST FreeChainQ.
* @hd: Pointer to the MPT_SCSI_HOST instance
* @req_idx: Index of the SCSI IO request frame. (output)
*
* return SUCCESS or FAILED
*/
static inline int
mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
{
MPT_FRAME_HDR *chainBuf = NULL;
unsigned long flags;
int rc = FAILED;
int chain_idx = MPT_HOST_NO_CHAIN;
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
int offset;
chainBuf = hd->FreeChainQ.head;
Q_DEL_ITEM(&chainBuf->u.frame.linkage);
offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
chain_idx = offset / hd->ioc->req_sz;
rc = SUCCESS;
}
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
*retIndex = chain_idx;
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
hd->ioc->name, *retIndex, chainBuf));
return rc;
} /* mptscsih_getFreeChainBuffer() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
* SCSIIORequest_t Message Frame.
* @hd: Pointer to MPT_SCSI_HOST structure
* @SCpnt: Pointer to Scsi_Cmnd structure
* @pReq: Pointer to SCSIIORequest_t structure
*
* Returns ...
*/
static int
mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
SCSIIORequest_t *pReq, int req_idx)
{
char *psge;
char *chainSge;
struct scatterlist *sg;
int frm_sz;
int sges_left, sg_done;
int chain_idx = MPT_HOST_NO_CHAIN;
int sgeOffset;
int numSgeSlots, numSgeThisFrame;
u32 sgflags, sgdir, thisxfer = 0;
int chain_dma_off = 0;
int newIndex;
int ii;
dma_addr_t v2;
sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
sgdir = MPT_TRANSFER_HOST_TO_IOC;
} else {
sgdir = MPT_TRANSFER_IOC_TO_HOST;
}
psge = (char *) &pReq->SGL;
frm_sz = hd->ioc->req_sz;
/* Map the data portion, if any.
* sges_left = 0 if no data transfer.
*/
sges_left = SCpnt->use_sg;
if (SCpnt->use_sg) {
sges_left = pci_map_sg(hd->ioc->pcidev,
(struct scatterlist *) SCpnt->request_buffer,
SCpnt->use_sg,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
} else if (SCpnt->request_bufflen) {
dma_addr_t buf_dma_addr;
scPrivate *my_priv;
buf_dma_addr = pci_map_single(hd->ioc->pcidev,
SCpnt->request_buffer,
SCpnt->request_bufflen,
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
/* We hide it here for later unmap. */
my_priv = (scPrivate *) &SCpnt->SCp;
my_priv->p1 = (void *)(ulong) buf_dma_addr;
dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
hd->ioc->name, SCpnt, SCpnt->request_bufflen));
mptscsih_add_sge((char *) &pReq->SGL,
0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
buf_dma_addr);
return SUCCESS;
}
/* Handle the SG case.
*/
sg = (struct scatterlist *) SCpnt->request_buffer;
sg_done = 0;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
chainSge = NULL;
/* Prior to entering this loop - the following must be set
* current MF: sgeOffset (bytes)
* chainSge (Null if original MF is not a chain buffer)
* sg_done (num SGE done for this MF)
*/
nextSGEset:
numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
/* Get first (num - 1) SG elements
* Skip any SG entries with a length of 0
* NOTE: at finish, sg and psge pointed to NEXT data/location positions
*/
for (ii=0; ii < (numSgeThisFrame-1); ii++) {
thisxfer = sg_dma_len(sg);
if (thisxfer == 0) {
sg ++; /* Get next SG element from the OS */
sg_done++;
continue;
}
v2 = sg_dma_address(sg);
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
sg++; /* Get next SG element from the OS */
psge += (sizeof(u32) + sizeof(dma_addr_t));
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
}
if (numSgeThisFrame == sges_left) {
/* Add last element, end of buffer and end of list flags.
*/
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
MPT_SGE_FLAGS_END_OF_BUFFER |
MPT_SGE_FLAGS_END_OF_LIST;
/* Add last SGE and set termination flags.
* Note: Last SGE may have a length of 0 - which should be ok.
*/
thisxfer = sg_dma_len(sg);
v2 = sg_dma_address(sg);
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
/*
sg++;
psge += (sizeof(u32) + sizeof(dma_addr_t));
*/
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
if (chainSge) {
/* The current buffer is a chain buffer,
* but there is not another one.
* Update the chain element
* Offset and Length fields.
*/
mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
} else {
/* The current buffer is the original MF
* and there is no Chain buffer.
*/
pReq->ChainOffset = 0;
}
} else {
/* At least one chain buffer is needed.
* Complete the first MF
* - last SGE element, set the LastElement bit
* - set ChainOffset (words) for orig MF
* (OR finish previous MF chain buffer)
* - update MFStructPtr ChainIndex
* - Populate chain element
* Also
* Loop until done.
*/
dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
hd->ioc->name, sg_done));
/* Set LAST_ELEMENT flag for last non-chain element
* in the buffer. Since psge points at the NEXT
* SGE element, go back one SGE element, update the flags
* and reset the pointer. (Note: sgflags & thisxfer are already
* set properly).
*/
if (sg_done) {
u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
sgflags = le32_to_cpu(*ptmp);
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
*ptmp = cpu_to_le32(sgflags);
}
if (chainSge) {
/* The current buffer is a chain buffer.
* chainSge points to the previous Chain Element.
* Update its chain element Offset and Length (must
* include chain element size) fields.
* Old chain element is now complete.
*/
u8 nextChain = (u8) (sgeOffset >> 2);
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
} else {
/* The original MF buffer requires a chain buffer -
* set the offset.
* Last element in this MF is a chain element.
*/
pReq->ChainOffset = (u8) (sgeOffset >> 2);
}
sges_left -= sg_done;
/* NOTE: psge points to the beginning of the chain element
* in current buffer. Get a chain buffer.
*/
if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
return FAILED;
/* Update the tracking arrays.
* If chainSge == NULL, update ReqToChain, else ChainToChain
*/
if (chainSge) {
hd->ChainToChain[chain_idx] = newIndex;
} else {
hd->ReqToChain[req_idx] = newIndex;
}
chain_idx = newIndex;
chain_dma_off = hd->ioc->req_sz * chain_idx;
/* Populate the chainSGE for the current buffer.
* - Set chain buffer pointer to psge and fill
* out the Address and Flags fields.
*/
chainSge = (char *) psge;
dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
psge, req_idx));
/* Start the SGE for the next buffer
*/
psge = (char *) (hd->ChainBuffer + chain_dma_off);
sgeOffset = 0;
sg_done = 0;
dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
psge, chain_idx));
/* Start the SGE for the next buffer
*/
goto nextSGEset;
}
return SUCCESS;
} /* mptscsih_AddSGE() */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* /*
* mptscsih_io_done - Main SCSI IO callback routine registered to * mptscsih_io_done - Main SCSI IO callback routine registered to
...@@ -294,7 +722,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -294,7 +722,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
MPT_SCSI_HOST *hd; MPT_SCSI_HOST *hd;
SCSIIORequest_t *pScsiReq; SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply; SCSIIOReply_t *pScsiReply;
#ifndef MPT_SCSI_USE_NEW_EH #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
unsigned long flags; unsigned long flags;
#endif #endif
u16 req_idx; u16 req_idx;
...@@ -305,7 +733,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -305,7 +733,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n", printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
ioc->name, mf?"BAD":"NULL", (void *) mf); ioc->name, mf?"BAD":"NULL", (void *) mf);
/* return 1; CHECKME SteveR. Don't free. */
return 0; return 0;
} }
...@@ -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
...@@ -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;
...@@ -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
...@@ -1708,724 +2152,742 @@ mptscsih_halt(struct notifier_block *nb, ulong event, void *buf) ...@@ -1708,724 +2152,742 @@ mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
/* Flush the cache of this adapter /* Flush the cache of this adapter
*/ */
if (ioc->sh) { if (ioc->sh) {
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
if (hd) { if (hd) {
mptscsih_synchronize_cache(hd, 0); mptscsih_synchronize_cache(hd, 0);
} }
} }
}
unregister_reboot_notifier(&mptscsih_notifier);
return NOTIFY_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_info - Return information about MPT adapter
* @SChost: Pointer to Scsi_Host structure
*
* (linux Scsi_Host_Template.info routine)
*
* Returns pointer to buffer where information was written.
*/
const char *
mptscsih_info(struct Scsi_Host *SChost)
{
MPT_SCSI_HOST *h;
int size = 0;
if (info_kbuf == NULL)
if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
return info_kbuf;
h = (MPT_SCSI_HOST *)SChost->hostdata;
info_kbuf[0] = '\0';
mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
info_kbuf[size-1] = '\0';
return info_kbuf;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int max_qd = 1;
#if 0
static int index_log[128];
static int index_ent = 0;
static __inline__ void ADD_INDEX_LOG(int req_ent)
{
int i = index_ent++;
index_log[i & (128 - 1)] = req_ent;
}
#else
#define ADD_INDEX_LOG(req_ent) do { } while(0)
#endif
#ifdef DROP_TEST
#define DROP_IOC 1 /* IOC to force failures */
#define DROP_TARGET 3 /* Target ID to force failures */
#define DROP_THIS_CMD 10000 /* iteration to drop command */
static int dropCounter = 0;
static int dropTestOK = 0; /* num did good */
static int dropTestBad = 0; /* num did bad */
static int dropTestNum = 0; /* total = good + bad + incomplete */
static int numTotCmds = 0;
static MPT_FRAME_HDR *dropMfPtr = NULL;
static int numTMrequested = 0;
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
* @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
* @id: IOC id number
* @mf: Pointer to message frame
*
* Handles the call to mptbase for posting request and queue depth
* tracking.
*
* Returns none.
*/
static void
mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
{
/* Main banana... */
atomic_inc(&queue_depth);
if (atomic_read(&queue_depth) > max_qd) {
max_qd = atomic_read(&queue_depth);
dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
} }
mpt_put_msg_frame(context, id, mf); unregister_reboot_notifier(&mptscsih_notifier);
return NOTIFY_OK;
return;
} }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/** /**
* mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. * mptscsih_info - Return information about MPT adapter
* @SCpnt: Pointer to Scsi_Cmnd structure * @SChost: Pointer to Scsi_Host 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); copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
if (datadir == SCSI_DATA_READ) { copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
datalen = SCpnt->request_bufflen; copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
} else if (datadir == SCSI_DATA_WRITE) {
datalen = SCpnt->request_bufflen; return ((info.pos > info.offset) ? info.pos - info.offset : 0);
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ }
struct mptscsih_usrcmd {
ulong target;
ulong lun;
ulong data;
ulong cmd;
};
#define UC_GET_SPEED 0x10
static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc)
{
CONFIGPARMS cfg;
dma_addr_t cfg_dma_addr = -1;
ConfigPageHeader_t header;
dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n",
ioc, uc->cmd, uc->target));
switch (uc->cmd) {
case UC_GET_SPEED:
{
SCSIDevicePage0_t *pData = NULL;
if (ioc->spi_data.sdp0length == 0)
return;
pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev,
ioc->spi_data.sdp0length * 4, &cfg_dma_addr);
if (pData == NULL)
return;
header.PageVersion = ioc->spi_data.sdp0version;
header.PageLength = ioc->spi_data.sdp0length;
header.PageNumber = 0;
header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
cfg.hdr = &header;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */
cfg.physAddr = cfg_dma_addr;
if (mpt_config(ioc, &cfg) == 0) {
u32 np = le32_to_cpu(pData->NegotiatedParameters);
u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE;
printk("Target %d: %s;",
(u32) uc->target,
tmp ? "Wide" : "Narrow");
tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK;
if (tmp) {
u32 speed = 0;
printk(" Synchronous");
tmp = (tmp >> 16);
printk(" (Offset=0x%x", tmp);
tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK;
tmp = (tmp >> 8);
printk(" Factor=0x%x)", tmp);
if (tmp <= MPT_ULTRA320)
speed=160;
else if (tmp <= MPT_ULTRA160)
speed=80;
else if (tmp <= MPT_ULTRA2)
speed=40;
else if (tmp <= MPT_ULTRA)
speed=20;
else if (tmp <= MPT_FAST)
speed=10;
else if (tmp <= MPT_SCSI)
speed=5;
if (np & MPI_SCSIDEVPAGE0_NP_WIDE)
speed*=2;
printk(" %dMB/sec\n", speed);
} else
printk(" Asynchronous.\n");
} else { } else {
datalen = 0; printk("failed\n" );
scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
} }
/* Default to untagged. Once a target structure has been allocated, pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4,
* use the Inquiry data to determine if device supports tagged. pData, cfg_dma_addr);
*/
qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
&& (SCpnt->device->tagged_supported)) {
/*
* Some drives are too stupid to handle fairness issues
* with tagged queueing. We throw in the odd ordered
* tag to stop them starving themselves.
*/
if ((jiffies - hd->qtag_tick) > (5*HZ)) {
qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
hd->qtag_tick = jiffies;
} }
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;
if (dvStatus || hd->ioc->spi_data.forceDv) { 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;
/* Write SDP1 on this I/O to this target */ uc->target = uc->cmd = uc->lun = uc->data = 0;
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 ((len > 0) && (ptr[len -1] == '\n'))
if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) { --len;
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); if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0)
} else { uc->cmd = UC_GET_SPEED;
spin_unlock_irqrestore(&dvtaskQ_lock, lflags); else
} arg_len = 0;
hd->ioc->spi_data.forceDv = 0;
}
/* Trying to do DV to this target, extend timeout. dprintk(("user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd));
* Wait to issue intil flag is clear
*/ if (!arg_len)
if (dvStatus & MPT_SCSICFG_DV_PENDING) { return -EINVAL;
mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
issueCmd = 0; ptr += arg_len;
len -= arg_len;
switch(uc->cmd) {
case UC_GET_SPEED:
SKIP_SPACES(1);
GET_INT_ARG(target);
uc->target = target;
break;
} }
/* Set the DV flags. dprintk(("user_command: target=%ld len=%d\n", uc->target, len));
if (len)
return -EINVAL;
else {
/* process this command ...
*/ */
if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) mptscsih_exec_user_cmd(ioc, uc);
mptscsih_set_dvflags(hd, pScsiReq);
#endif
}
} }
/* Not yet implemented */
return length;
}
if (issueCmd) { /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); /**
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", * mptscsih_proc_info - Return information about MPT adapter
hd->ioc->name, SCpnt, mf, my_idx)); *
} else { * (linux Scsi_Host_Template.info routine)
ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n", *
hd->ioc->name, SCpnt, my_idx)); * buffer: if write, user data; if read, buffer for user
/* Place this command on the pendingQ if possible */ * length: if write, return length;
spin_lock_irqsave(&hd->freedoneQlock, flags); * offset: if write, 0; if read, the current offset into the buffer from
if (!Q_IS_EMPTY(&hd->freeQ)) { * the previous read.
buffer = hd->freeQ.head; * hostno: scsi host number
Q_DEL_ITEM(buffer); * 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;
/* Save the mf pointer dprintk(("Called mptscsih_proc_info: hostno=%d, func=%d\n", hostno, func));
*/ dprintk(("buffer %p, start=%p (%p) offset=%ld length = %d\n",
buffer->argp = (void *)mf; buffer, start, *start, offset, length));
/* Add to the pendingQ for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
*/ if ((ioc->sh) && (ioc->sh->host_no == hostno)) {
Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q); hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
spin_unlock_irqrestore(&hd->freedoneQlock, flags); break;
} else {
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
SCpnt->result = (DID_BUS_BUSY << 16);
SCpnt->scsi_done(SCpnt);
} }
} }
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;
}
#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.
*/ */
Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); static inline void
spin_unlock_irqrestore(&hd->freedoneQlock, flags); mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
} else { {
spin_unlock_irqrestore(&hd->freedoneQlock, flags); /* Main banana... */
SCpnt->scsi_done(SCpnt); 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);
}
/* We hide it here for later unmap. */ if (dest) {
my_priv = (scPrivate *) &SCpnt->SCp; sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
my_priv->p1 = (void *)(ulong) buf_dma_addr; memcpy(dest, pTarget->sense, sz);
dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n", #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
hd->ioc->name, SCpnt, SCpnt->request_bufflen)); SCpnt->resid = SCpnt->request_bufflen - sz;
#endif
SCpnt->result = 0;
SCpnt->scsi_done(SCpnt);
mpt_add_sge((char *) &pReq->SGL, //sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
buf_dma_addr);
return SUCCESS; return 0;
}
}
} }
#endif
/* Handle the SG case. if (hd->resetPending) {
/* Prevent new commands from being issued
* while reloading the FW.
*/ */
sg = (struct scatterlist *) SCpnt->request_buffer; did_errcode = 1;
sg_done = 0; goto did_error;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); }
chainSge = NULL;
/* Prior to entering this loop - the following must be set /*
* current MF: sgeOffset (bytes) * Put together a MPT SCSI request...
* chainSge (Null if original MF is not a chain buffer)
* sg_done (num SGE done for this MF)
*/ */
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;
}
nextSGEset: pScsiReq = (SCSIIORequest_t *) mf;
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; my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
/* Get first (num - 1) SG elements ADD_INDEX_LOG(my_idx);
* 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); /*
mpt_add_sge(psge, sgflags | thisxfer, v2); * The scsi layer should be handling this stuff
* (In 2.3.x it does -DaveM)
*/
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)) {
/*
* Some drives are too stupid to handle fairness issues
* with tagged queueing. We throw in the odd ordered
* tag to stop them starving themselves.
*/
if ((jiffies - hd->qtag_tick) > (5*HZ)) {
qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;
hd->qtag_tick = jiffies;
}
else
qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
}
scsictl = scsidir | qtag;
/* Add last SGE and set termination flags. /* Use the above information to set up the message frame
* Note: Last SGE may have a length of 0 - which should be ok.
*/ */
thisxfer = sg_dma_len(sg); pScsiReq->TargetID = target;
pScsiReq->Bus = hd->port;
pScsiReq->ChainOffset = 0;
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
pScsiReq->CDBLength = SCpnt->cmd_len;
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
pScsiReq->Reserved = 0;
pScsiReq->MsgFlags = mpt_msg_flags();
pScsiReq->LUN[0] = 0;
pScsiReq->LUN[1] = lun;
pScsiReq->LUN[2] = 0;
pScsiReq->LUN[3] = 0;
pScsiReq->LUN[4] = 0;
pScsiReq->LUN[5] = 0;
pScsiReq->LUN[6] = 0;
pScsiReq->LUN[7] = 0;
pScsiReq->Control = cpu_to_le32(scsictl);
v2 = sg_dma_address(sg);
mpt_add_sge(psge, sgflags | thisxfer, v2);
/* /*
sg++; * Write SCSI CDB into the message
psge += (sizeof(u32) + sizeof(dma_addr_t)); * Should write from cmd_len up to 16, but skip for performance reasons.
*/ */
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); cmd_len = SCpnt->cmd_len;
sg_done++; for (ii=0; ii < cmd_len; ii++)
pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
if (chainSge) { /* DataLength */
/* The current buffer is a chain buffer, pScsiReq->DataLength = cpu_to_le32(datalen);
* but there is not another one.
* Update the chain element /* SenseBuffer low address */
* Offset and Length fields. pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
/* Now add the SG list
* Always have a SGE even if null length.
*/ */
mpt_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off); rc = SUCCESS;
if (datalen == 0) {
/* Add a NULL SGE */
mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
(dma_addr_t) -1);
} else { } else {
/* The current buffer is the original MF /* Add a 32 or 64 bit SGE */
* and there is no Chain buffer. rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
*/
pReq->ChainOffset = 0;
} }
} else {
/* At least one chain buffer is needed.
* Complete the first MF if (rc == SUCCESS) {
* - last SGE element, set the LastElement bit hd->ScsiLookup[my_idx] = SCpnt;
* - set ChainOffset (words) for orig MF SCpnt->host_scribble = NULL;
* (OR finish previous MF chain buffer)
* - update MFStructPtr ChainIndex #ifdef DROP_TEST
* - Populate chain element numTotCmds++;
* Also /* If the IOC number and target match, increment
* Loop until done. * 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++;
dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", if (dropCounter == DROP_THIS_CMD) {
hd->ioc->name, sg_done)); dropCounter = 0;
/* Set LAST_ELEMENT flag for last non-chain element /* If global is set, then we are already
* in the buffer. Since psge points at the NEXT * doing something - so keep issuing commands.
* SGE element, go back one SGE element, update the flags
* and reset the pointer. (Note: sgflags & thisxfer are already
* set properly).
*/ */
if (sg_done) { if (dropMfPtr == NULL) {
u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); dropTestNum++;
sgflags = le32_to_cpu(*ptmp); dropMfPtr = mf;
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; atomic_inc(&queue_depth);
*ptmp = cpu_to_le32(sgflags); 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;
}
} }
}
#endif
if (chainSge) { /* SCSI specific processing */
/* The current buffer is a chain buffer. issueCmd = 1;
* chainSge points to the previous Chain Element. if (hd->is_spi) {
* Update its chain element Offset and Length (must int dvStatus = hd->ioc->spi_data.dvStatus[target];
* include chain element size) fields.
* Old chain element is now complete. if (dvStatus || hd->ioc->spi_data.forceDv) {
*/
u8 nextChain = (u8) (sgeOffset >> 2); /* Write SDP1 on this I/O to this target */
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off); mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
} else { dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
/* The original MF buffer requires a chain buffer - hd->ioc->spi_data.dvStatus[target] = dvStatus;
* set the offset. } else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
* Last element in this MF is a chain element. mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
*/ dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
pReq->ChainOffset = (u8) (sgeOffset >> 2); hd->ioc->spi_data.dvStatus[target] = dvStatus;
} }
sges_left -= sg_done; #ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
(hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
/* NOTE: psge points to the beginning of the chain element unsigned long lflags;
* in current buffer. Get a chain buffer. /* Schedule DV if necessary */
*/ spin_lock_irqsave(&dvtaskQ_lock, lflags);
if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED) if (!dvtaskQ_active) {
return FAILED; dvtaskQ_active = 1;
spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
/* Update the tracking arrays. SCHEDULE_TASK(&mptscsih_dvTask);
* If chainSge == NULL, update ReqToChain, else ChainToChain
*/
if (chainSge) {
hd->ChainToChain[chain_idx] = newIndex;
} else { } else {
hd->ReqToChain[req_idx] = newIndex; spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
}
hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
} }
chain_idx = newIndex;
chain_dma_off = hd->ioc->req_sz * chain_idx;
/* Populate the chainSGE for the current buffer. /* Trying to do DV to this target, extend timeout.
* - Set chain buffer pointer to psge and fill * Wait to issue intil flag is clear
* out the Address and Flags fields.
*/ */
chainSge = (char *) psge; if (dvStatus & MPT_SCSICFG_DV_PENDING) {
dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
psge, req_idx)); issueCmd = 0;
}
/* Start the SGE for the next buffer /* Set the DV flags.
*/ */
psge = (char *) (hd->ChainBuffer + chain_dma_off); if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
sgeOffset = 0; mptscsih_set_dvflags(hd, pScsiReq);
sg_done = 0; #endif
}
}
dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", if (issueCmd) {
psge, chain_idx)); mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
hd->ioc->name, SCpnt, mf, my_idx));
} else {
ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
hd->ioc->name, SCpnt, my_idx));
/* Place this command on the pendingQ if possible */
spin_lock_irqsave(&hd->freedoneQlock, flags);
if (!Q_IS_EMPTY(&hd->freeQ)) {
buffer = hd->freeQ.head;
Q_DEL_ITEM(buffer);
/* Start the SGE for the next buffer /* Save the mf pointer
*/ */
buffer->argp = (void *)mf;
goto nextSGEset; /* Add to the pendingQ
*/
Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
} else {
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
SCpnt->result = (DID_BUS_BUSY << 16);
SCpnt->scsi_done(SCpnt);
}
}
} else {
mptscsih_freeChainBuffers(hd, my_idx);
mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
did_errcode = 3;
goto did_error;
} }
return SUCCESS; return 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_getFreeChainBuffes - Function to get a free chain
* from the MPT_SCSI_HOST FreeChainQ.
* @hd: Pointer to the MPT_SCSI_HOST instance
* @req_idx: Index of the SCSI IO request frame. (output)
*
* return SUCCESS or FAILED
*/
static int
mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
{
MPT_FRAME_HDR *chainBuf = NULL;
unsigned long flags;
int rc = FAILED;
int chain_idx = MPT_HOST_NO_CHAIN;
//spin_lock_irqsave(&hd->FreeChainQlock, flags); did_error:
spin_lock_irqsave(&hd->ioc->FreeQlock, flags); dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
if (!Q_IS_EMPTY(&hd->FreeChainQ)) { 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);
int offset; /* Set the Scsi_Cmnd pointer
*/
buffer->argp = (void *)SCpnt;
chainBuf = hd->FreeChainQ.head; /* Add to the doneQ
Q_DEL_ITEM(&chainBuf->u.frame.linkage); */
offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer; Q_ADD_TAIL(&hd->doneQ.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->scsi_done(SCpnt);
} }
//spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
*retIndex = chain_idx;
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
hd->ioc->name, *retIndex, chainBuf));
return rc; return 0;
} }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
...@@ -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
...@@ -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 */
...@@ -4193,6 +4587,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) ...@@ -4193,6 +4587,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
*/ */
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));
}
} }
} }
} }
...@@ -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++) {
...@@ -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) {
if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
retcode = 1; retcode = 1;
else
retcode = 0;
goto target_done; goto target_done;
} }
} else if (rc == MPT_SCANDV_SENSE) { } else if (rc == MPT_SCANDV_SENSE) {
......
...@@ -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,8 +73,15 @@ ...@@ -73,8 +73,15 @@
* 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
#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_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