11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/drivers/message/fusion/mptscsih.c 30d0c7974SMoore, Eric Dean * For use with LSI Logic PCI chip/adapter(s) 41da177e4SLinus Torvalds * running LSI Logic Fusion MPT (Message Passing Technology) firmware. 51da177e4SLinus Torvalds * 69f4203b3SEric Moore * Copyright (c) 1999-2007 LSI Logic Corporation 716d20101SEric Moore * (mailto:DL-MPTFusionLinux@lsi.com) 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 111da177e4SLinus Torvalds /* 121da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify 131da177e4SLinus Torvalds it under the terms of the GNU General Public License as published by 141da177e4SLinus Torvalds the Free Software Foundation; version 2 of the License. 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds This program is distributed in the hope that it will be useful, 171da177e4SLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 181da177e4SLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 191da177e4SLinus Torvalds GNU General Public License for more details. 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds NO WARRANTY 221da177e4SLinus Torvalds THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 231da177e4SLinus Torvalds CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 241da177e4SLinus Torvalds LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 251da177e4SLinus Torvalds MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 261da177e4SLinus Torvalds solely responsible for determining the appropriateness of using and 271da177e4SLinus Torvalds distributing the Program and assumes all risks associated with its 281da177e4SLinus Torvalds exercise of rights under this Agreement, including but not limited to 291da177e4SLinus Torvalds the risks and costs of program errors, damage to or loss of data, 301da177e4SLinus Torvalds programs or equipment, and unavailability or interruption of operations. 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds DISCLAIMER OF LIABILITY 331da177e4SLinus Torvalds NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 341da177e4SLinus Torvalds DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 351da177e4SLinus Torvalds DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 361da177e4SLinus Torvalds ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 371da177e4SLinus Torvalds TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 381da177e4SLinus Torvalds USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 391da177e4SLinus Torvalds HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds You should have received a copy of the GNU General Public License 421da177e4SLinus Torvalds along with this program; if not, write to the Free Software 431da177e4SLinus Torvalds Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds #include <linux/module.h> 481da177e4SLinus Torvalds #include <linux/kernel.h> 491da177e4SLinus Torvalds #include <linux/init.h> 501da177e4SLinus Torvalds #include <linux/errno.h> 511da177e4SLinus Torvalds #include <linux/kdev_t.h> 521da177e4SLinus Torvalds #include <linux/blkdev.h> 531da177e4SLinus Torvalds #include <linux/delay.h> /* for mdelay */ 541da177e4SLinus Torvalds #include <linux/interrupt.h> /* needed for in_interrupt() proto */ 551da177e4SLinus Torvalds #include <linux/reboot.h> /* notifier code */ 561da177e4SLinus Torvalds #include <linux/workqueue.h> 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds #include <scsi/scsi.h> 591da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h> 601da177e4SLinus Torvalds #include <scsi/scsi_device.h> 611da177e4SLinus Torvalds #include <scsi/scsi_host.h> 621da177e4SLinus Torvalds #include <scsi/scsi_tcq.h> 63e0fc15beSMoore, Eric Dean #include <scsi/scsi_dbg.h> 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds #include "mptbase.h" 661da177e4SLinus Torvalds #include "mptscsih.h" 67bf451522SEric Moore #include "lsi/mpi_log_sas.h" 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 701da177e4SLinus Torvalds #define my_NAME "Fusion MPT SCSI Host driver" 711da177e4SLinus Torvalds #define my_VERSION MPT_LINUX_VERSION_COMMON 721da177e4SLinus Torvalds #define MYNAM "mptscsih" 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds MODULE_AUTHOR(MODULEAUTHOR); 751da177e4SLinus Torvalds MODULE_DESCRIPTION(my_NAME); 761da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 779f4203b3SEric Moore MODULE_VERSION(my_VERSION); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 801da177e4SLinus Torvalds /* 811da177e4SLinus Torvalds * Other private/forward protos... 821da177e4SLinus Torvalds */ 830d0c7974SMoore, Eric Dean int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); 841da177e4SLinus Torvalds static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); 850d0c7974SMoore, Eric Dean int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, 881da177e4SLinus Torvalds SCSIIORequest_t *pReq, int req_idx); 891da177e4SLinus Torvalds static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); 900d0c7974SMoore, Eric Dean static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); 911da177e4SLinus Torvalds static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); 921da177e4SLinus Torvalds static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); 933dc0b03fSEric Moore static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc); 941da177e4SLinus Torvalds 95793955f5SEric Moore static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); 961da177e4SLinus Torvalds 970d0c7974SMoore, Eric Dean int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); 980d0c7974SMoore, Eric Dean int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); 991da177e4SLinus Torvalds 1000d0c7974SMoore, Eric Dean int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); 1011da177e4SLinus Torvalds static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); 102c7c82987SMoore, Eric Dean static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); 1031da177e4SLinus Torvalds 1040d0c7974SMoore, Eric Dean void mptscsih_remove(struct pci_dev *); 105d18c3db5SGreg Kroah-Hartman void mptscsih_shutdown(struct pci_dev *); 1061da177e4SLinus Torvalds #ifdef CONFIG_PM 1070d0c7974SMoore, Eric Dean int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); 1080d0c7974SMoore, Eric Dean int mptscsih_resume(struct pci_dev *pdev); 1091da177e4SLinus Torvalds #endif 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds #define SNS_LEN(scp) sizeof((scp)->sense_buffer) 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1141da177e4SLinus Torvalds /** 1151da177e4SLinus Torvalds * mptscsih_add_sge - Place a simple SGE at address pAddr. 1161da177e4SLinus Torvalds * @pAddr: virtual address for SGE 1171da177e4SLinus Torvalds * @flagslength: SGE flags and data transfer length 1181da177e4SLinus Torvalds * @dma_addr: Physical address 1191da177e4SLinus Torvalds * 1201da177e4SLinus Torvalds * This routine places a MPT request frame back on the MPT adapter's 1211da177e4SLinus Torvalds * FreeQ. 1221da177e4SLinus Torvalds */ 1231da177e4SLinus Torvalds static inline void 1241da177e4SLinus Torvalds mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds if (sizeof(dma_addr_t) == sizeof(u64)) { 1271da177e4SLinus Torvalds SGESimple64_t *pSge = (SGESimple64_t *) pAddr; 1281da177e4SLinus Torvalds u32 tmp = dma_addr & 0xFFFFFFFF; 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds pSge->FlagsLength = cpu_to_le32(flagslength); 1311da177e4SLinus Torvalds pSge->Address.Low = cpu_to_le32(tmp); 1321da177e4SLinus Torvalds tmp = (u32) ((u64)dma_addr >> 32); 1331da177e4SLinus Torvalds pSge->Address.High = cpu_to_le32(tmp); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds } else { 1361da177e4SLinus Torvalds SGESimple32_t *pSge = (SGESimple32_t *) pAddr; 1371da177e4SLinus Torvalds pSge->FlagsLength = cpu_to_le32(flagslength); 1381da177e4SLinus Torvalds pSge->Address = cpu_to_le32(dma_addr); 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds } /* mptscsih_add_sge() */ 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1431da177e4SLinus Torvalds /** 1441da177e4SLinus Torvalds * mptscsih_add_chain - Place a chain SGE at address pAddr. 1451da177e4SLinus Torvalds * @pAddr: virtual address for SGE 1461da177e4SLinus Torvalds * @next: nextChainOffset value (u32's) 1471da177e4SLinus Torvalds * @length: length of next SGL segment 1481da177e4SLinus Torvalds * @dma_addr: Physical address 1491da177e4SLinus Torvalds * 1501da177e4SLinus Torvalds * This routine places a MPT request frame back on the MPT adapter's 1511da177e4SLinus Torvalds * FreeQ. 1521da177e4SLinus Torvalds */ 1531da177e4SLinus Torvalds static inline void 1541da177e4SLinus Torvalds mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds if (sizeof(dma_addr_t) == sizeof(u64)) { 1571da177e4SLinus Torvalds SGEChain64_t *pChain = (SGEChain64_t *) pAddr; 1581da177e4SLinus Torvalds u32 tmp = dma_addr & 0xFFFFFFFF; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds pChain->Length = cpu_to_le16(length); 1611da177e4SLinus Torvalds pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds pChain->NextChainOffset = next; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds pChain->Address.Low = cpu_to_le32(tmp); 1661da177e4SLinus Torvalds tmp = (u32) ((u64)dma_addr >> 32); 1671da177e4SLinus Torvalds pChain->Address.High = cpu_to_le32(tmp); 1681da177e4SLinus Torvalds } else { 1691da177e4SLinus Torvalds SGEChain32_t *pChain = (SGEChain32_t *) pAddr; 1701da177e4SLinus Torvalds pChain->Length = cpu_to_le16(length); 1711da177e4SLinus Torvalds pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); 1721da177e4SLinus Torvalds pChain->NextChainOffset = next; 1731da177e4SLinus Torvalds pChain->Address = cpu_to_le32(dma_addr); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds } /* mptscsih_add_chain() */ 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1781da177e4SLinus Torvalds /* 1791da177e4SLinus Torvalds * mptscsih_getFreeChainBuffer - Function to get a free chain 1801da177e4SLinus Torvalds * from the MPT_SCSI_HOST FreeChainQ. 1811da177e4SLinus Torvalds * @ioc: Pointer to MPT_ADAPTER structure 1821da177e4SLinus Torvalds * @req_idx: Index of the SCSI IO request frame. (output) 1831da177e4SLinus Torvalds * 1841da177e4SLinus Torvalds * return SUCCESS or FAILED 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds static inline int 1871da177e4SLinus Torvalds mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) 1881da177e4SLinus Torvalds { 1891da177e4SLinus Torvalds MPT_FRAME_HDR *chainBuf; 1901da177e4SLinus Torvalds unsigned long flags; 1911da177e4SLinus Torvalds int rc; 1921da177e4SLinus Torvalds int chain_idx; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n", 1951da177e4SLinus Torvalds ioc->name)); 1961da177e4SLinus Torvalds spin_lock_irqsave(&ioc->FreeQlock, flags); 1971da177e4SLinus Torvalds if (!list_empty(&ioc->FreeChainQ)) { 1981da177e4SLinus Torvalds int offset; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR, 2011da177e4SLinus Torvalds u.frame.linkage.list); 2021da177e4SLinus Torvalds list_del(&chainBuf->u.frame.linkage.list); 2031da177e4SLinus Torvalds offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; 2041da177e4SLinus Torvalds chain_idx = offset / ioc->req_sz; 2051da177e4SLinus Torvalds rc = SUCCESS; 206c6678e0cSChristoph Hellwig dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", 207c6678e0cSChristoph Hellwig ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); 2081da177e4SLinus Torvalds } else { 2091da177e4SLinus Torvalds rc = FAILED; 2101da177e4SLinus Torvalds chain_idx = MPT_HOST_NO_CHAIN; 211c6678e0cSChristoph Hellwig dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n", 2121da177e4SLinus Torvalds ioc->name)); 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds spin_unlock_irqrestore(&ioc->FreeQlock, flags); 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds *retIndex = chain_idx; 2171da177e4SLinus Torvalds return rc; 2181da177e4SLinus Torvalds } /* mptscsih_getFreeChainBuffer() */ 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 2211da177e4SLinus Torvalds /* 2221da177e4SLinus Torvalds * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the 2231da177e4SLinus Torvalds * SCSIIORequest_t Message Frame. 2241da177e4SLinus Torvalds * @ioc: Pointer to MPT_ADAPTER structure 2251da177e4SLinus Torvalds * @SCpnt: Pointer to scsi_cmnd structure 2261da177e4SLinus Torvalds * @pReq: Pointer to SCSIIORequest_t structure 2271da177e4SLinus Torvalds * 2281da177e4SLinus Torvalds * Returns ... 2291da177e4SLinus Torvalds */ 2301da177e4SLinus Torvalds static int 2311da177e4SLinus Torvalds mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, 2321da177e4SLinus Torvalds SCSIIORequest_t *pReq, int req_idx) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds char *psge; 2351da177e4SLinus Torvalds char *chainSge; 2361da177e4SLinus Torvalds struct scatterlist *sg; 2371da177e4SLinus Torvalds int frm_sz; 2381da177e4SLinus Torvalds int sges_left, sg_done; 2391da177e4SLinus Torvalds int chain_idx = MPT_HOST_NO_CHAIN; 2401da177e4SLinus Torvalds int sgeOffset; 2411da177e4SLinus Torvalds int numSgeSlots, numSgeThisFrame; 2421da177e4SLinus Torvalds u32 sgflags, sgdir, thisxfer = 0; 2431da177e4SLinus Torvalds int chain_dma_off = 0; 2441da177e4SLinus Torvalds int newIndex; 2451da177e4SLinus Torvalds int ii; 2461da177e4SLinus Torvalds dma_addr_t v2; 2471da177e4SLinus Torvalds u32 RequestNB; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK; 2501da177e4SLinus Torvalds if (sgdir == MPI_SCSIIO_CONTROL_WRITE) { 2511da177e4SLinus Torvalds sgdir = MPT_TRANSFER_HOST_TO_IOC; 2521da177e4SLinus Torvalds } else { 2531da177e4SLinus Torvalds sgdir = MPT_TRANSFER_IOC_TO_HOST; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds psge = (char *) &pReq->SGL; 2571da177e4SLinus Torvalds frm_sz = ioc->req_sz; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds /* Map the data portion, if any. 2601da177e4SLinus Torvalds * sges_left = 0 if no data transfer. 2611da177e4SLinus Torvalds */ 2621928d73fSFUJITA Tomonori sges_left = scsi_dma_map(SCpnt); 2631928d73fSFUJITA Tomonori if (sges_left < 0) 2641da177e4SLinus Torvalds return FAILED; 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* Handle the SG case. 2671da177e4SLinus Torvalds */ 2681928d73fSFUJITA Tomonori sg = scsi_sglist(SCpnt); 2691da177e4SLinus Torvalds sg_done = 0; 2701da177e4SLinus Torvalds sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION); 2711da177e4SLinus Torvalds chainSge = NULL; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds /* Prior to entering this loop - the following must be set 2741da177e4SLinus Torvalds * current MF: sgeOffset (bytes) 2751da177e4SLinus Torvalds * chainSge (Null if original MF is not a chain buffer) 2761da177e4SLinus Torvalds * sg_done (num SGE done for this MF) 2771da177e4SLinus Torvalds */ 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds nextSGEset: 2801da177e4SLinus Torvalds numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); 2811da177e4SLinus Torvalds numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds /* Get first (num - 1) SG elements 2861da177e4SLinus Torvalds * Skip any SG entries with a length of 0 2871da177e4SLinus Torvalds * NOTE: at finish, sg and psge pointed to NEXT data/location positions 2881da177e4SLinus Torvalds */ 2891da177e4SLinus Torvalds for (ii=0; ii < (numSgeThisFrame-1); ii++) { 2901da177e4SLinus Torvalds thisxfer = sg_dma_len(sg); 2911da177e4SLinus Torvalds if (thisxfer == 0) { 2921da177e4SLinus Torvalds sg ++; /* Get next SG element from the OS */ 2931da177e4SLinus Torvalds sg_done++; 2941da177e4SLinus Torvalds continue; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds v2 = sg_dma_address(sg); 2981da177e4SLinus Torvalds mptscsih_add_sge(psge, sgflags | thisxfer, v2); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds sg++; /* Get next SG element from the OS */ 3011da177e4SLinus Torvalds psge += (sizeof(u32) + sizeof(dma_addr_t)); 3021da177e4SLinus Torvalds sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); 3031da177e4SLinus Torvalds sg_done++; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds if (numSgeThisFrame == sges_left) { 3071da177e4SLinus Torvalds /* Add last element, end of buffer and end of list flags. 3081da177e4SLinus Torvalds */ 3091da177e4SLinus Torvalds sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT | 3101da177e4SLinus Torvalds MPT_SGE_FLAGS_END_OF_BUFFER | 3111da177e4SLinus Torvalds MPT_SGE_FLAGS_END_OF_LIST; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds /* Add last SGE and set termination flags. 3141da177e4SLinus Torvalds * Note: Last SGE may have a length of 0 - which should be ok. 3151da177e4SLinus Torvalds */ 3161da177e4SLinus Torvalds thisxfer = sg_dma_len(sg); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds v2 = sg_dma_address(sg); 3191da177e4SLinus Torvalds mptscsih_add_sge(psge, sgflags | thisxfer, v2); 3201da177e4SLinus Torvalds /* 3211da177e4SLinus Torvalds sg++; 3221da177e4SLinus Torvalds psge += (sizeof(u32) + sizeof(dma_addr_t)); 3231da177e4SLinus Torvalds */ 3241da177e4SLinus Torvalds sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); 3251da177e4SLinus Torvalds sg_done++; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds if (chainSge) { 3281da177e4SLinus Torvalds /* The current buffer is a chain buffer, 3291da177e4SLinus Torvalds * but there is not another one. 3301da177e4SLinus Torvalds * Update the chain element 3311da177e4SLinus Torvalds * Offset and Length fields. 3321da177e4SLinus Torvalds */ 3331da177e4SLinus Torvalds mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); 3341da177e4SLinus Torvalds } else { 3351da177e4SLinus Torvalds /* The current buffer is the original MF 3361da177e4SLinus Torvalds * and there is no Chain buffer. 3371da177e4SLinus Torvalds */ 3381da177e4SLinus Torvalds pReq->ChainOffset = 0; 3391da177e4SLinus Torvalds RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; 340c6678e0cSChristoph Hellwig dsgprintk((MYIOC_s_INFO_FMT 3411da177e4SLinus Torvalds "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); 3421da177e4SLinus Torvalds ioc->RequestNB[req_idx] = RequestNB; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds } else { 3451da177e4SLinus Torvalds /* At least one chain buffer is needed. 3461da177e4SLinus Torvalds * Complete the first MF 3471da177e4SLinus Torvalds * - last SGE element, set the LastElement bit 3481da177e4SLinus Torvalds * - set ChainOffset (words) for orig MF 3491da177e4SLinus Torvalds * (OR finish previous MF chain buffer) 3501da177e4SLinus Torvalds * - update MFStructPtr ChainIndex 3511da177e4SLinus Torvalds * - Populate chain element 3521da177e4SLinus Torvalds * Also 3531da177e4SLinus Torvalds * Loop until done. 3541da177e4SLinus Torvalds */ 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n", 3571da177e4SLinus Torvalds ioc->name, sg_done)); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds /* Set LAST_ELEMENT flag for last non-chain element 3601da177e4SLinus Torvalds * in the buffer. Since psge points at the NEXT 3611da177e4SLinus Torvalds * SGE element, go back one SGE element, update the flags 3621da177e4SLinus Torvalds * and reset the pointer. (Note: sgflags & thisxfer are already 3631da177e4SLinus Torvalds * set properly). 3641da177e4SLinus Torvalds */ 3651da177e4SLinus Torvalds if (sg_done) { 3661da177e4SLinus Torvalds u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); 3671da177e4SLinus Torvalds sgflags = le32_to_cpu(*ptmp); 3681da177e4SLinus Torvalds sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; 3691da177e4SLinus Torvalds *ptmp = cpu_to_le32(sgflags); 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds if (chainSge) { 3731da177e4SLinus Torvalds /* The current buffer is a chain buffer. 3741da177e4SLinus Torvalds * chainSge points to the previous Chain Element. 3751da177e4SLinus Torvalds * Update its chain element Offset and Length (must 3761da177e4SLinus Torvalds * include chain element size) fields. 3771da177e4SLinus Torvalds * Old chain element is now complete. 3781da177e4SLinus Torvalds */ 3791da177e4SLinus Torvalds u8 nextChain = (u8) (sgeOffset >> 2); 3801da177e4SLinus Torvalds sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); 3811da177e4SLinus Torvalds mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); 3821da177e4SLinus Torvalds } else { 3831da177e4SLinus Torvalds /* The original MF buffer requires a chain buffer - 3841da177e4SLinus Torvalds * set the offset. 3851da177e4SLinus Torvalds * Last element in this MF is a chain element. 3861da177e4SLinus Torvalds */ 3871da177e4SLinus Torvalds pReq->ChainOffset = (u8) (sgeOffset >> 2); 3881da177e4SLinus Torvalds RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; 3891da177e4SLinus Torvalds dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); 3901da177e4SLinus Torvalds ioc->RequestNB[req_idx] = RequestNB; 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds sges_left -= sg_done; 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds /* NOTE: psge points to the beginning of the chain element 3971da177e4SLinus Torvalds * in current buffer. Get a chain buffer. 3981da177e4SLinus Torvalds */ 399c6678e0cSChristoph Hellwig if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) { 400c6678e0cSChristoph Hellwig dfailprintk((MYIOC_s_INFO_FMT 401c6678e0cSChristoph Hellwig "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n", 4021da177e4SLinus Torvalds ioc->name, pReq->CDB[0], SCpnt)); 4031da177e4SLinus Torvalds return FAILED; 404c6678e0cSChristoph Hellwig } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds /* Update the tracking arrays. 4071da177e4SLinus Torvalds * If chainSge == NULL, update ReqToChain, else ChainToChain 4081da177e4SLinus Torvalds */ 4091da177e4SLinus Torvalds if (chainSge) { 4101da177e4SLinus Torvalds ioc->ChainToChain[chain_idx] = newIndex; 4111da177e4SLinus Torvalds } else { 4121da177e4SLinus Torvalds ioc->ReqToChain[req_idx] = newIndex; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds chain_idx = newIndex; 4151da177e4SLinus Torvalds chain_dma_off = ioc->req_sz * chain_idx; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds /* Populate the chainSGE for the current buffer. 4181da177e4SLinus Torvalds * - Set chain buffer pointer to psge and fill 4191da177e4SLinus Torvalds * out the Address and Flags fields. 4201da177e4SLinus Torvalds */ 4211da177e4SLinus Torvalds chainSge = (char *) psge; 4221da177e4SLinus Torvalds dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)", 4231da177e4SLinus Torvalds psge, req_idx)); 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds /* Start the SGE for the next buffer 4261da177e4SLinus Torvalds */ 4271da177e4SLinus Torvalds psge = (char *) (ioc->ChainBuffer + chain_dma_off); 4281da177e4SLinus Torvalds sgeOffset = 0; 4291da177e4SLinus Torvalds sg_done = 0; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n", 4321da177e4SLinus Torvalds psge, chain_idx)); 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds /* Start the SGE for the next buffer 4351da177e4SLinus Torvalds */ 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds goto nextSGEset; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds return SUCCESS; 4411da177e4SLinus Torvalds } /* mptscsih_AddSGE() */ 4421da177e4SLinus Torvalds 443786899b0SEric Moore static void 444786899b0SEric Moore mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget, 445786899b0SEric Moore U32 SlotStatus) 446786899b0SEric Moore { 447786899b0SEric Moore MPT_FRAME_HDR *mf; 448786899b0SEric Moore SEPRequest_t *SEPMsg; 449786899b0SEric Moore 450786899b0SEric Moore if (ioc->bus_type == FC) 451786899b0SEric Moore return; 452786899b0SEric Moore 453786899b0SEric Moore if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { 454786899b0SEric Moore dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n", 455786899b0SEric Moore ioc->name,__FUNCTION__)); 456786899b0SEric Moore return; 457786899b0SEric Moore } 458786899b0SEric Moore 459786899b0SEric Moore SEPMsg = (SEPRequest_t *)mf; 460786899b0SEric Moore SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; 461793955f5SEric Moore SEPMsg->Bus = vtarget->channel; 462793955f5SEric Moore SEPMsg->TargetID = vtarget->id; 463786899b0SEric Moore SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS; 464786899b0SEric Moore SEPMsg->SlotStatus = SlotStatus; 465786899b0SEric Moore devtverboseprintk((MYIOC_s_WARN_FMT 466793955f5SEric Moore "Sending SEP cmd=%x channel=%d id=%d\n", 467793955f5SEric Moore ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID)); 468786899b0SEric Moore mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); 469786899b0SEric Moore } 470786899b0SEric Moore 471c6c727a1SEric Moore #ifdef MPT_DEBUG_REPLY 472c6c727a1SEric Moore /** 473c6c727a1SEric Moore * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO 474c6c727a1SEric Moore * @ioc: Pointer to MPT_ADAPTER structure 475c6c727a1SEric Moore * @ioc_status: U32 IOCStatus word from IOC 476c6c727a1SEric Moore * @scsi_status: U8 sam status from target 477c6c727a1SEric Moore * @scsi_state: U8 scsi state 478c6c727a1SEric Moore * @sc: original scsi cmnd pointer 479c6c727a1SEric Moore * @mf: Pointer to MPT request frame 480c6c727a1SEric Moore * 481c6c727a1SEric Moore * Refer to lsi/mpi.h. 482c6c727a1SEric Moore **/ 483c6c727a1SEric Moore static void 484c6c727a1SEric Moore mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status, 485c6c727a1SEric Moore u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc) 486c6c727a1SEric Moore { 487c6c727a1SEric Moore char extend_desc[EVENT_DESCR_STR_SZ]; 488c6c727a1SEric Moore char *desc = NULL; 489c6c727a1SEric Moore 490c6c727a1SEric Moore switch (ioc_status) { 491c6c727a1SEric Moore 492c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ 493c6c727a1SEric Moore desc = "SCSI Invalid Bus"; 494c6c727a1SEric Moore break; 495c6c727a1SEric Moore 496c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ 497c6c727a1SEric Moore desc = "SCSI Invalid TargetID"; 498c6c727a1SEric Moore break; 499c6c727a1SEric Moore 500c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ 501c6c727a1SEric Moore /* 502c6c727a1SEric Moore * Inquiry is issued for device scanning 503c6c727a1SEric Moore */ 504c6c727a1SEric Moore if (sc->cmnd[0] != 0x12) 505c6c727a1SEric Moore desc = "SCSI Device Not There"; 506c6c727a1SEric Moore break; 507c6c727a1SEric Moore 508c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ 509c6c727a1SEric Moore desc = "SCSI Data Overrun"; 510c6c727a1SEric Moore break; 511c6c727a1SEric Moore 512c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ 513c6c727a1SEric Moore desc = "SCSI I/O Data Error"; 514c6c727a1SEric Moore break; 515c6c727a1SEric Moore 516c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ 517c6c727a1SEric Moore desc = "SCSI Protocol Error"; 518c6c727a1SEric Moore break; 519c6c727a1SEric Moore 520c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ 521c6c727a1SEric Moore desc = "SCSI Task Terminated"; 522c6c727a1SEric Moore break; 523c6c727a1SEric Moore 524c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ 525c6c727a1SEric Moore desc = "SCSI Residual Mismatch"; 526c6c727a1SEric Moore break; 527c6c727a1SEric Moore 528c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ 529c6c727a1SEric Moore desc = "SCSI Task Management Failed"; 530c6c727a1SEric Moore break; 531c6c727a1SEric Moore 532c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ 533c6c727a1SEric Moore desc = "SCSI IOC Terminated"; 534c6c727a1SEric Moore break; 535c6c727a1SEric Moore 536c6c727a1SEric Moore case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ 537c6c727a1SEric Moore desc = "SCSI Ext Terminated"; 538c6c727a1SEric Moore break; 539c6c727a1SEric Moore } 540c6c727a1SEric Moore 541c6c727a1SEric Moore if (!desc) 542c6c727a1SEric Moore return; 543c6c727a1SEric Moore 544c6c727a1SEric Moore snprintf(extend_desc, EVENT_DESCR_STR_SZ, 545c6c727a1SEric Moore "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh", 546c6c727a1SEric Moore sc->device->host->host_no, 547c6c727a1SEric Moore sc->device->channel, sc->device->id, sc->device->lun, 548c6c727a1SEric Moore sc->cmnd[0], scsi_status, scsi_state); 549c6c727a1SEric Moore 550c6c727a1SEric Moore printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n", 551c6c727a1SEric Moore ioc->name, ioc_status, desc, extend_desc); 552c6c727a1SEric Moore } 553c6c727a1SEric Moore #endif 554c6c727a1SEric Moore 5551da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 5561da177e4SLinus Torvalds /* 5571da177e4SLinus Torvalds * mptscsih_io_done - Main SCSI IO callback routine registered to 5581da177e4SLinus Torvalds * Fusion MPT (base) driver 5591da177e4SLinus Torvalds * @ioc: Pointer to MPT_ADAPTER structure 5601da177e4SLinus Torvalds * @mf: Pointer to original MPT request frame 5611da177e4SLinus Torvalds * @r: Pointer to MPT reply frame (NULL if TurboReply) 5621da177e4SLinus Torvalds * 5631da177e4SLinus Torvalds * This routine is called from mpt.c::mpt_interrupt() at the completion 5641da177e4SLinus Torvalds * of any SCSI IO request. 5651da177e4SLinus Torvalds * This routine is registered with the Fusion MPT (base) driver at driver 5661da177e4SLinus Torvalds * load/init time via the mpt_register() API call. 5671da177e4SLinus Torvalds * 5681da177e4SLinus Torvalds * Returns 1 indicating alloc'd request frame ptr should be freed. 5691da177e4SLinus Torvalds */ 5700d0c7974SMoore, Eric Dean int 5711da177e4SLinus Torvalds mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) 5721da177e4SLinus Torvalds { 5731da177e4SLinus Torvalds struct scsi_cmnd *sc; 5741da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 5751da177e4SLinus Torvalds SCSIIORequest_t *pScsiReq; 5761da177e4SLinus Torvalds SCSIIOReply_t *pScsiReply; 5772254c86dSMoore, Eric u16 req_idx, req_idx_MR; 578786899b0SEric Moore VirtDevice *vdev; 579786899b0SEric Moore VirtTarget *vtarget; 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); 5842254c86dSMoore, Eric req_idx_MR = (mr != NULL) ? 5852254c86dSMoore, Eric le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; 5862254c86dSMoore, Eric if ((req_idx != req_idx_MR) || 5872254c86dSMoore, Eric (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) { 5882254c86dSMoore, Eric printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n", 5892254c86dSMoore, Eric ioc->name); 5902254c86dSMoore, Eric printk (MYIOC_s_ERR_FMT 5912254c86dSMoore, Eric "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", 5922254c86dSMoore, Eric ioc->name, req_idx, req_idx_MR, mf, mr, 5932254c86dSMoore, Eric hd->ScsiLookup[req_idx_MR]); 5942254c86dSMoore, Eric return 0; 5952254c86dSMoore, Eric } 5962254c86dSMoore, Eric 5971da177e4SLinus Torvalds sc = hd->ScsiLookup[req_idx]; 5983dc0b03fSEric Moore hd->ScsiLookup[req_idx] = NULL; 5991da177e4SLinus Torvalds if (sc == NULL) { 6001da177e4SLinus Torvalds MPIHeader_t *hdr = (MPIHeader_t *)mf; 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* Remark: writeSDP1 will use the ScsiDoneCtx 6031da177e4SLinus Torvalds * If a SCSI I/O cmd, device disabled by OS and 6041da177e4SLinus Torvalds * completion done. Cannot touch sc struct. Just free mem. 6051da177e4SLinus Torvalds */ 6061da177e4SLinus Torvalds if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) 6071da177e4SLinus Torvalds printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", 6081da177e4SLinus Torvalds ioc->name); 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds mptscsih_freeChainBuffers(ioc, req_idx); 6111da177e4SLinus Torvalds return 1; 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds 6143dc0b03fSEric Moore if ((unsigned char *)mf != sc->host_scribble) { 6153dc0b03fSEric Moore mptscsih_freeChainBuffers(ioc, req_idx); 6163dc0b03fSEric Moore return 1; 6173dc0b03fSEric Moore } 6183dc0b03fSEric Moore 6193dc0b03fSEric Moore sc->host_scribble = NULL; 6201da177e4SLinus Torvalds sc->result = DID_OK << 16; /* Set default reply as OK */ 6211da177e4SLinus Torvalds pScsiReq = (SCSIIORequest_t *) mf; 6221da177e4SLinus Torvalds pScsiReply = (SCSIIOReply_t *) mr; 6231da177e4SLinus Torvalds 624c6678e0cSChristoph Hellwig if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){ 625c6678e0cSChristoph Hellwig dmfprintk((MYIOC_s_INFO_FMT 626c6678e0cSChristoph Hellwig "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n", 627c6678e0cSChristoph Hellwig ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag)); 628c6678e0cSChristoph Hellwig }else{ 629c6678e0cSChristoph Hellwig dmfprintk((MYIOC_s_INFO_FMT 630c6678e0cSChristoph Hellwig "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", 631c6678e0cSChristoph Hellwig ioc->name, mf, mr, sc, req_idx)); 632c6678e0cSChristoph Hellwig } 633c6678e0cSChristoph Hellwig 6341da177e4SLinus Torvalds if (pScsiReply == NULL) { 6351da177e4SLinus Torvalds /* special context reply handling */ 6361da177e4SLinus Torvalds ; 6371da177e4SLinus Torvalds } else { 6381da177e4SLinus Torvalds u32 xfer_cnt; 6391da177e4SLinus Torvalds u16 status; 6401da177e4SLinus Torvalds u8 scsi_state, scsi_status; 641c6c727a1SEric Moore u32 log_info; 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; 6441da177e4SLinus Torvalds scsi_state = pScsiReply->SCSIState; 6451da177e4SLinus Torvalds scsi_status = pScsiReply->SCSIStatus; 6461da177e4SLinus Torvalds xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); 6471928d73fSFUJITA Tomonori scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt); 648c6c727a1SEric Moore log_info = le32_to_cpu(pScsiReply->IOCLogInfo); 6491da177e4SLinus Torvalds 650466544d8SMoore, Eric Dean /* 651466544d8SMoore, Eric Dean * if we get a data underrun indication, yet no data was 652466544d8SMoore, Eric Dean * transferred and the SCSI status indicates that the 653466544d8SMoore, Eric Dean * command was never started, change the data underrun 654466544d8SMoore, Eric Dean * to success 655466544d8SMoore, Eric Dean */ 656466544d8SMoore, Eric Dean if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && 657466544d8SMoore, Eric Dean (scsi_status == MPI_SCSI_STATUS_BUSY || 658466544d8SMoore, Eric Dean scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT || 659466544d8SMoore, Eric Dean scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) { 660466544d8SMoore, Eric Dean status = MPI_IOCSTATUS_SUCCESS; 661466544d8SMoore, Eric Dean } 662466544d8SMoore, Eric Dean 6631da177e4SLinus Torvalds if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) 6640d0c7974SMoore, Eric Dean mptscsih_copy_sense_data(sc, hd, mf, pScsiReply); 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds /* 6671da177e4SLinus Torvalds * Look for + dump FCP ResponseInfo[]! 6681da177e4SLinus Torvalds */ 669466544d8SMoore, Eric Dean if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && 670466544d8SMoore, Eric Dean pScsiReply->ResponseInfo) { 671c6c727a1SEric Moore printk(KERN_NOTICE "[%d:%d:%d:%d] " 672466544d8SMoore, Eric Dean "FCP_ResponseInfo=%08xh\n", 673c6c727a1SEric Moore sc->device->host->host_no, sc->device->channel, 674c6c727a1SEric Moore sc->device->id, sc->device->lun, 6751da177e4SLinus Torvalds le32_to_cpu(pScsiReply->ResponseInfo)); 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds switch(status) { 6791da177e4SLinus Torvalds case MPI_IOCSTATUS_BUSY: /* 0x0002 */ 6801da177e4SLinus Torvalds /* CHECKME! 6811da177e4SLinus Torvalds * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) 6821da177e4SLinus Torvalds * But not: DID_BUS_BUSY lest one risk 6831da177e4SLinus Torvalds * killing interrupt handler:-( 6841da177e4SLinus Torvalds */ 6851da177e4SLinus Torvalds sc->result = SAM_STAT_BUSY; 6861da177e4SLinus Torvalds break; 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ 6891da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ 6901da177e4SLinus Torvalds sc->result = DID_BAD_TARGET << 16; 6911da177e4SLinus Torvalds break; 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ 6941da177e4SLinus Torvalds /* Spoof to SCSI Selection Timeout! */ 69565207fedSMoore, Eric if (ioc->bus_type != FC) 6961da177e4SLinus Torvalds sc->result = DID_NO_CONNECT << 16; 69765207fedSMoore, Eric /* else fibre, just stall until rescan event */ 69865207fedSMoore, Eric else 69965207fedSMoore, Eric sc->result = DID_REQUEUE << 16; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) 7021da177e4SLinus Torvalds hd->sel_timeout[pScsiReq->TargetID]++; 703786899b0SEric Moore 704786899b0SEric Moore vdev = sc->device->hostdata; 705786899b0SEric Moore if (!vdev) 706786899b0SEric Moore break; 707786899b0SEric Moore vtarget = vdev->vtarget; 708786899b0SEric Moore if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) { 709786899b0SEric Moore mptscsih_issue_sep_command(ioc, vtarget, 710786899b0SEric Moore MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED); 711786899b0SEric Moore vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON; 712786899b0SEric Moore } 7131da177e4SLinus Torvalds break; 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ 716bf451522SEric Moore if ( ioc->bus_type == SAS ) { 717bf451522SEric Moore u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus); 718bf451522SEric Moore if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { 719c6c727a1SEric Moore if ((log_info & SAS_LOGINFO_MASK) 720c6c727a1SEric Moore == SAS_LOGINFO_NEXUS_LOSS) { 721bf451522SEric Moore sc->result = (DID_BUS_BUSY << 16); 722bf451522SEric Moore break; 723bf451522SEric Moore } 724bf451522SEric Moore } 72586dd4242SEric Moore } else if (ioc->bus_type == FC) { 72686dd4242SEric Moore /* 72786dd4242SEric Moore * The FC IOC may kill a request for variety of 72886dd4242SEric Moore * reasons, some of which may be recovered by a 72986dd4242SEric Moore * retry, some which are unlikely to be 73086dd4242SEric Moore * recovered. Return DID_ERROR instead of 73186dd4242SEric Moore * DID_RESET to permit retry of the command, 73286dd4242SEric Moore * just not an infinite number of them 73386dd4242SEric Moore */ 73486dd4242SEric Moore sc->result = DID_ERROR << 16; 73586dd4242SEric Moore break; 736bf451522SEric Moore } 737bf451522SEric Moore 738bf451522SEric Moore /* 739bf451522SEric Moore * Allow non-SAS & non-NEXUS_LOSS to drop into below code 740bf451522SEric Moore */ 741bf451522SEric Moore 742bf451522SEric Moore case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ 7431da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ 7441da177e4SLinus Torvalds /* Linux handles an unsolicited DID_RESET better 7451da177e4SLinus Torvalds * than an unsolicited DID_ABORT. 7461da177e4SLinus Torvalds */ 7471da177e4SLinus Torvalds sc->result = DID_RESET << 16; 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds break; 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ 7521928d73fSFUJITA Tomonori scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt); 753466544d8SMoore, Eric Dean if((xfer_cnt==0)||(sc->underflow > xfer_cnt)) 7541da177e4SLinus Torvalds sc->result=DID_SOFT_ERROR << 16; 755466544d8SMoore, Eric Dean else /* Sufficient data transfer occurred */ 756466544d8SMoore, Eric Dean sc->result = (DID_OK << 16) | scsi_status; 757c6678e0cSChristoph Hellwig dreplyprintk((KERN_NOTICE 758c6c727a1SEric Moore "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n", 759c6c727a1SEric Moore sc->result, sc->device->channel, sc->device->id)); 7601da177e4SLinus Torvalds break; 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ 7631da177e4SLinus Torvalds /* 7641da177e4SLinus Torvalds * Do upfront check for valid SenseData and give it 7651da177e4SLinus Torvalds * precedence! 7661da177e4SLinus Torvalds */ 7671da177e4SLinus Torvalds sc->result = (DID_OK << 16) | scsi_status; 7681da177e4SLinus Torvalds if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { 7691da177e4SLinus Torvalds /* Have already saved the status and sense data 7701da177e4SLinus Torvalds */ 7711da177e4SLinus Torvalds ; 7721da177e4SLinus Torvalds } else { 7731da177e4SLinus Torvalds if (xfer_cnt < sc->underflow) { 774466544d8SMoore, Eric Dean if (scsi_status == SAM_STAT_BUSY) 775466544d8SMoore, Eric Dean sc->result = SAM_STAT_BUSY; 776466544d8SMoore, Eric Dean else 7771da177e4SLinus Torvalds sc->result = DID_SOFT_ERROR << 16; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { 7801da177e4SLinus Torvalds /* What to do? 7811da177e4SLinus Torvalds */ 7821da177e4SLinus Torvalds sc->result = DID_SOFT_ERROR << 16; 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { 7851da177e4SLinus Torvalds /* Not real sure here either... */ 7861da177e4SLinus Torvalds sc->result = DID_RESET << 16; 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", 7911da177e4SLinus Torvalds sc->underflow)); 7921da177e4SLinus Torvalds dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); 7931da177e4SLinus Torvalds /* Report Queue Full 7941da177e4SLinus Torvalds */ 7951da177e4SLinus Torvalds if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) 7961da177e4SLinus Torvalds mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds break; 7991da177e4SLinus Torvalds 8007e55147fSMoore, Eric case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ 8011928d73fSFUJITA Tomonori scsi_set_resid(sc, 0); 8021da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ 8031da177e4SLinus Torvalds case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ 8041da177e4SLinus Torvalds sc->result = (DID_OK << 16) | scsi_status; 8051da177e4SLinus Torvalds if (scsi_state == 0) { 8061da177e4SLinus Torvalds ; 8071da177e4SLinus Torvalds } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { 8081da177e4SLinus Torvalds /* 8091da177e4SLinus Torvalds * If running against circa 200003dd 909 MPT f/w, 8101da177e4SLinus Torvalds * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL 8111da177e4SLinus Torvalds * (QUEUE_FULL) returned from device! --> get 0x0000?128 8121da177e4SLinus Torvalds * and with SenseBytes set to 0. 8131da177e4SLinus Torvalds */ 8141da177e4SLinus Torvalds if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL) 8151da177e4SLinus Torvalds mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds else if (scsi_state & 8191da177e4SLinus Torvalds (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS) 8201da177e4SLinus Torvalds ) { 8211da177e4SLinus Torvalds /* 8221da177e4SLinus Torvalds * What to do? 8231da177e4SLinus Torvalds */ 8241da177e4SLinus Torvalds sc->result = DID_SOFT_ERROR << 16; 8251da177e4SLinus Torvalds } 8261da177e4SLinus Torvalds else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { 8271da177e4SLinus Torvalds /* Not real sure here either... */ 8281da177e4SLinus Torvalds sc->result = DID_RESET << 16; 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) { 8311da177e4SLinus Torvalds /* Device Inq. data indicates that it supports 8321da177e4SLinus Torvalds * QTags, but rejects QTag messages. 8331da177e4SLinus Torvalds * This command completed OK. 8341da177e4SLinus Torvalds * 8351da177e4SLinus Torvalds * Not real sure here either so do nothing... */ 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) 8391da177e4SLinus Torvalds mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* Add handling of: 8421da177e4SLinus Torvalds * Reservation Conflict, Busy, 8431da177e4SLinus Torvalds * Command Terminated, CHECK 8441da177e4SLinus Torvalds */ 8451da177e4SLinus Torvalds break; 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ 8481da177e4SLinus Torvalds sc->result = DID_SOFT_ERROR << 16; 8491da177e4SLinus Torvalds break; 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ 8521da177e4SLinus Torvalds case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ 8531da177e4SLinus Torvalds case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ 8541da177e4SLinus Torvalds case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ 8551da177e4SLinus Torvalds case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ 8561da177e4SLinus Torvalds case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ 8571da177e4SLinus Torvalds case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ 8581da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ 8591da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ 8601da177e4SLinus Torvalds default: 8611da177e4SLinus Torvalds /* 8621da177e4SLinus Torvalds * What to do? 8631da177e4SLinus Torvalds */ 8641da177e4SLinus Torvalds sc->result = DID_SOFT_ERROR << 16; 8651da177e4SLinus Torvalds break; 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds } /* switch(status) */ 8681da177e4SLinus Torvalds 869c6c727a1SEric Moore #ifdef MPT_DEBUG_REPLY 870c6c727a1SEric Moore if (sc->result) { 871c6c727a1SEric Moore 872c6c727a1SEric Moore mptscsih_iocstatus_info_scsiio(ioc, status, 873c6c727a1SEric Moore scsi_status, scsi_state, sc); 874c6c727a1SEric Moore 875c6c727a1SEric Moore dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x " 876c6c727a1SEric Moore "result=0x%08x\n\tiocstatus=0x%04X " 877c6c727a1SEric Moore "scsi_state=0x%02X scsi_status=0x%02X " 878c6c727a1SEric Moore "loginfo=0x%08X\n", __FUNCTION__, 879c6c727a1SEric Moore sc->device->host->host_no, sc->device->channel, sc->device->id, 880c6c727a1SEric Moore sc->device->lun, sc->cmnd[0], sc->result, status, 881c6c727a1SEric Moore scsi_state, scsi_status, log_info)); 882c6c727a1SEric Moore 883c6c727a1SEric Moore dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d " 884c6c727a1SEric Moore "bufflen=%d xfer_cnt=%d\n", __FUNCTION__, 8851928d73fSFUJITA Tomonori sc->device->host->host_no, 8861928d73fSFUJITA Tomonori sc->device->channel, sc->device->id, 8871928d73fSFUJITA Tomonori sc->device->lun, scsi_get_resid(sc), 8881928d73fSFUJITA Tomonori scsi_bufflen(sc), xfer_cnt)); 889c6c727a1SEric Moore } 890c6c727a1SEric Moore #endif 891c6c727a1SEric Moore 8921da177e4SLinus Torvalds } /* end of address reply case */ 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds /* Unmap the DMA buffers, if any. */ 8951928d73fSFUJITA Tomonori scsi_dma_unmap(sc); 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds sc->scsi_done(sc); /* Issue the command callback */ 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds /* Free Chain buffers */ 9001da177e4SLinus Torvalds mptscsih_freeChainBuffers(ioc, req_idx); 9011da177e4SLinus Torvalds return 1; 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds /* 9051da177e4SLinus Torvalds * mptscsih_flush_running_cmds - For each command found, search 9061da177e4SLinus Torvalds * Scsi_Host instance taskQ and reply to OS. 9071da177e4SLinus Torvalds * Called only if recovering from a FW reload. 9081da177e4SLinus Torvalds * @hd: Pointer to a SCSI HOST structure 9091da177e4SLinus Torvalds * 9101da177e4SLinus Torvalds * Returns: None. 9111da177e4SLinus Torvalds * 9121da177e4SLinus Torvalds * Must be called while new I/Os are being queued. 9131da177e4SLinus Torvalds */ 9141da177e4SLinus Torvalds static void 9151da177e4SLinus Torvalds mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds MPT_ADAPTER *ioc = hd->ioc; 9181da177e4SLinus Torvalds struct scsi_cmnd *SCpnt; 9191da177e4SLinus Torvalds MPT_FRAME_HDR *mf; 9201da177e4SLinus Torvalds int ii; 9211da177e4SLinus Torvalds int max = ioc->req_depth; 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); 9241da177e4SLinus Torvalds for (ii= 0; ii < max; ii++) { 9251da177e4SLinus Torvalds if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds /* Command found. 9281da177e4SLinus Torvalds */ 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds /* Null ScsiLookup index 9311da177e4SLinus Torvalds */ 9321da177e4SLinus Torvalds hd->ScsiLookup[ii] = NULL; 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds mf = MPT_INDEX_2_MFPTR(ioc, ii); 9351da177e4SLinus Torvalds dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", 9361da177e4SLinus Torvalds mf, SCpnt)); 9371da177e4SLinus Torvalds 9383dc0b03fSEric Moore /* Free Chain buffers */ 9393dc0b03fSEric Moore mptscsih_freeChainBuffers(ioc, ii); 9403dc0b03fSEric Moore 9413dc0b03fSEric Moore /* Free Message frames */ 9423dc0b03fSEric Moore mpt_free_msg_frame(ioc, mf); 9433dc0b03fSEric Moore 9443dc0b03fSEric Moore if ((unsigned char *)mf != SCpnt->host_scribble) 9453dc0b03fSEric Moore continue; 9463dc0b03fSEric Moore 9471da177e4SLinus Torvalds /* Set status, free OS resources (SG DMA buffers) 9481da177e4SLinus Torvalds * Do OS callback 9491da177e4SLinus Torvalds */ 9501928d73fSFUJITA Tomonori scsi_dma_unmap(SCpnt); 9511928d73fSFUJITA Tomonori 9521da177e4SLinus Torvalds SCpnt->result = DID_RESET << 16; 9531da177e4SLinus Torvalds SCpnt->host_scribble = NULL; 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds SCpnt->scsi_done(SCpnt); /* Issue the command callback */ 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds } 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds return; 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds /* 9631da177e4SLinus Torvalds * mptscsih_search_running_cmds - Delete any commands associated 9641da177e4SLinus Torvalds * with the specified target and lun. Function called only 9651da177e4SLinus Torvalds * when a lun is disable by mid-layer. 9661da177e4SLinus Torvalds * Do NOT access the referenced scsi_cmnd structure or 9671da177e4SLinus Torvalds * members. Will cause either a paging or NULL ptr error. 96805e8ec17SMichael Reed * (BUT, BUT, BUT, the code does reference it! - mdr) 9691da177e4SLinus Torvalds * @hd: Pointer to a SCSI HOST structure 970c7c82987SMoore, Eric Dean * @vdevice: per device private data 9711da177e4SLinus Torvalds * 9721da177e4SLinus Torvalds * Returns: None. 9731da177e4SLinus Torvalds * 9741da177e4SLinus Torvalds * Called from slave_destroy. 9751da177e4SLinus Torvalds */ 9761da177e4SLinus Torvalds static void 977c7c82987SMoore, Eric Dean mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) 9781da177e4SLinus Torvalds { 9791da177e4SLinus Torvalds SCSIIORequest_t *mf = NULL; 9801da177e4SLinus Torvalds int ii; 9811da177e4SLinus Torvalds int max = hd->ioc->req_depth; 982466544d8SMoore, Eric Dean struct scsi_cmnd *sc; 983793955f5SEric Moore struct scsi_lun lun; 9841da177e4SLinus Torvalds 985793955f5SEric Moore dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n", 986793955f5SEric Moore vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max)); 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds for (ii=0; ii < max; ii++) { 989466544d8SMoore, Eric Dean if ((sc = hd->ScsiLookup[ii]) != NULL) { 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); 9923dc0b03fSEric Moore if (mf == NULL) 9933dc0b03fSEric Moore continue; 994793955f5SEric Moore int_to_scsilun(vdevice->lun, &lun); 995793955f5SEric Moore if ((mf->Bus != vdevice->vtarget->channel) || 996793955f5SEric Moore (mf->TargetID != vdevice->vtarget->id) || 997793955f5SEric Moore memcmp(lun.scsi_lun, mf->LUN, 8)) 9981da177e4SLinus Torvalds continue; 999793955f5SEric Moore dsprintk(( "search_running: found (sc=%p, mf = %p) " 1000793955f5SEric Moore "channel %d id %d, lun %d \n", hd->ScsiLookup[ii], 1001793955f5SEric Moore mf, mf->Bus, mf->TargetID, vdevice->lun)); 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds /* Cleanup 10041da177e4SLinus Torvalds */ 10051da177e4SLinus Torvalds hd->ScsiLookup[ii] = NULL; 10061da177e4SLinus Torvalds mptscsih_freeChainBuffers(hd->ioc, ii); 10071da177e4SLinus Torvalds mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); 10083dc0b03fSEric Moore if ((unsigned char *)mf != sc->host_scribble) 10093dc0b03fSEric Moore continue; 10101928d73fSFUJITA Tomonori scsi_dma_unmap(sc); 10111928d73fSFUJITA Tomonori 1012466544d8SMoore, Eric Dean sc->host_scribble = NULL; 1013466544d8SMoore, Eric Dean sc->result = DID_NO_CONNECT << 16; 1014466544d8SMoore, Eric Dean sc->scsi_done(sc); 10151da177e4SLinus Torvalds } 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds return; 10181da177e4SLinus Torvalds } 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 10231da177e4SLinus Torvalds /* 10241da177e4SLinus Torvalds * mptscsih_report_queue_full - Report QUEUE_FULL status returned 10251da177e4SLinus Torvalds * from a SCSI target device. 10261da177e4SLinus Torvalds * @sc: Pointer to scsi_cmnd structure 10271da177e4SLinus Torvalds * @pScsiReply: Pointer to SCSIIOReply_t 10281da177e4SLinus Torvalds * @pScsiReq: Pointer to original SCSI request 10291da177e4SLinus Torvalds * 10301da177e4SLinus Torvalds * This routine periodically reports QUEUE_FULL status returned from a 10311da177e4SLinus Torvalds * SCSI target device. It reports this to the console via kernel 10321da177e4SLinus Torvalds * printk() API call, not more than once every 10 seconds. 10331da177e4SLinus Torvalds */ 10341da177e4SLinus Torvalds static void 10351da177e4SLinus Torvalds mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) 10361da177e4SLinus Torvalds { 10371da177e4SLinus Torvalds long time = jiffies; 10381da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 10391da177e4SLinus Torvalds 10400d0c7974SMoore, Eric Dean if (sc->device == NULL) 10410d0c7974SMoore, Eric Dean return; 10420d0c7974SMoore, Eric Dean if (sc->device->host == NULL) 10430d0c7974SMoore, Eric Dean return; 10440d0c7974SMoore, Eric Dean if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL) 10450d0c7974SMoore, Eric Dean return; 10461da177e4SLinus Torvalds 10470d0c7974SMoore, Eric Dean if (time - hd->last_queue_full > 10 * HZ) { 10480d0c7974SMoore, Eric Dean dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n", 10490d0c7974SMoore, Eric Dean hd->ioc->name, 0, sc->device->id, sc->device->lun)); 10500d0c7974SMoore, Eric Dean hd->last_queue_full = time; 10511da177e4SLinus Torvalds } 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds 10541da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 10551da177e4SLinus Torvalds /* 10561da177e4SLinus Torvalds * mptscsih_remove - Removed scsi devices 10571da177e4SLinus Torvalds * @pdev: Pointer to pci_dev structure 10581da177e4SLinus Torvalds * 10591da177e4SLinus Torvalds * 10601da177e4SLinus Torvalds */ 10610d0c7974SMoore, Eric Dean void 10621da177e4SLinus Torvalds mptscsih_remove(struct pci_dev *pdev) 10631da177e4SLinus Torvalds { 10641da177e4SLinus Torvalds MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 10651da177e4SLinus Torvalds struct Scsi_Host *host = ioc->sh; 10661da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 10670d0c7974SMoore, Eric Dean int sz1; 10681da177e4SLinus Torvalds 1069466544d8SMoore, Eric Dean if(!host) { 1070466544d8SMoore, Eric Dean mpt_detach(pdev); 10711da177e4SLinus Torvalds return; 1072466544d8SMoore, Eric Dean } 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds scsi_remove_host(host); 10751da177e4SLinus Torvalds 10760d0c7974SMoore, Eric Dean if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL) 10770d0c7974SMoore, Eric Dean return; 10780d0c7974SMoore, Eric Dean 1079d18c3db5SGreg Kroah-Hartman mptscsih_shutdown(pdev); 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds sz1=0; 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds if (hd->ScsiLookup != NULL) { 10841da177e4SLinus Torvalds sz1 = hd->ioc->req_depth * sizeof(void *); 10851da177e4SLinus Torvalds kfree(hd->ScsiLookup); 10861da177e4SLinus Torvalds hd->ScsiLookup = NULL; 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds 10891da177e4SLinus Torvalds dprintk((MYIOC_s_INFO_FMT 10901da177e4SLinus Torvalds "Free'd ScsiLookup (%d) memory\n", 10911da177e4SLinus Torvalds hd->ioc->name, sz1)); 10921da177e4SLinus Torvalds 10930d0c7974SMoore, Eric Dean kfree(hd->info_kbuf); 10940d0c7974SMoore, Eric Dean 10951da177e4SLinus Torvalds /* NULL the Scsi_Host pointer 10961da177e4SLinus Torvalds */ 10971da177e4SLinus Torvalds hd->ioc->sh = NULL; 10981da177e4SLinus Torvalds 10991da177e4SLinus Torvalds scsi_host_put(host); 11000d0c7974SMoore, Eric Dean 11010d0c7974SMoore, Eric Dean mpt_detach(pdev); 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds 11051da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 11061da177e4SLinus Torvalds /* 11071da177e4SLinus Torvalds * mptscsih_shutdown - reboot notifier 11081da177e4SLinus Torvalds * 11091da177e4SLinus Torvalds */ 11100d0c7974SMoore, Eric Dean void 1111d18c3db5SGreg Kroah-Hartman mptscsih_shutdown(struct pci_dev *pdev) 11121da177e4SLinus Torvalds { 1113d18c3db5SGreg Kroah-Hartman MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 11141da177e4SLinus Torvalds struct Scsi_Host *host = ioc->sh; 11151da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 11161da177e4SLinus Torvalds 11171da177e4SLinus Torvalds if(!host) 11181da177e4SLinus Torvalds return; 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds hd = (MPT_SCSI_HOST *)host->hostdata; 11211da177e4SLinus Torvalds 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds #ifdef CONFIG_PM 11251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 11261da177e4SLinus Torvalds /* 11270d0c7974SMoore, Eric Dean * mptscsih_suspend - Fusion MPT scsi driver suspend routine. 11281da177e4SLinus Torvalds * 11291da177e4SLinus Torvalds * 11301da177e4SLinus Torvalds */ 11310d0c7974SMoore, Eric Dean int 11328d189f72SPavel Machek mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) 11331da177e4SLinus Torvalds { 1134d18c3db5SGreg Kroah-Hartman mptscsih_shutdown(pdev); 11350d0c7974SMoore, Eric Dean return mpt_suspend(pdev,state); 11361da177e4SLinus Torvalds } 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 11391da177e4SLinus Torvalds /* 11401da177e4SLinus Torvalds * mptscsih_resume - Fusion MPT scsi driver resume routine. 11411da177e4SLinus Torvalds * 11421da177e4SLinus Torvalds * 11431da177e4SLinus Torvalds */ 11440d0c7974SMoore, Eric Dean int 11451da177e4SLinus Torvalds mptscsih_resume(struct pci_dev *pdev) 11461da177e4SLinus Torvalds { 1147b364fd50SHorms return mpt_resume(pdev); 11481da177e4SLinus Torvalds } 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds #endif 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 11531da177e4SLinus Torvalds /** 11541da177e4SLinus Torvalds * mptscsih_info - Return information about MPT adapter 11551da177e4SLinus Torvalds * @SChost: Pointer to Scsi_Host structure 11561da177e4SLinus Torvalds * 11571da177e4SLinus Torvalds * (linux scsi_host_template.info routine) 11581da177e4SLinus Torvalds * 11591da177e4SLinus Torvalds * Returns pointer to buffer where information was written. 11601da177e4SLinus Torvalds */ 11610d0c7974SMoore, Eric Dean const char * 11621da177e4SLinus Torvalds mptscsih_info(struct Scsi_Host *SChost) 11631da177e4SLinus Torvalds { 11641da177e4SLinus Torvalds MPT_SCSI_HOST *h; 11651da177e4SLinus Torvalds int size = 0; 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds h = (MPT_SCSI_HOST *)SChost->hostdata; 11680d0c7974SMoore, Eric Dean 11691da177e4SLinus Torvalds if (h) { 11700d0c7974SMoore, Eric Dean if (h->info_kbuf == NULL) 11710d0c7974SMoore, Eric Dean if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL) 11720d0c7974SMoore, Eric Dean return h->info_kbuf; 11730d0c7974SMoore, Eric Dean h->info_kbuf[0] = '\0'; 11740d0c7974SMoore, Eric Dean 11750d0c7974SMoore, Eric Dean mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0); 11760d0c7974SMoore, Eric Dean h->info_kbuf[size-1] = '\0'; 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds 11790d0c7974SMoore, Eric Dean return h->info_kbuf; 11801da177e4SLinus Torvalds } 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds struct info_str { 11831da177e4SLinus Torvalds char *buffer; 11841da177e4SLinus Torvalds int length; 11851da177e4SLinus Torvalds int offset; 11861da177e4SLinus Torvalds int pos; 11871da177e4SLinus Torvalds }; 11881da177e4SLinus Torvalds 11890d0c7974SMoore, Eric Dean static void 11900d0c7974SMoore, Eric Dean mptscsih_copy_mem_info(struct info_str *info, char *data, int len) 11911da177e4SLinus Torvalds { 11921da177e4SLinus Torvalds if (info->pos + len > info->length) 11931da177e4SLinus Torvalds len = info->length - info->pos; 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds if (info->pos + len < info->offset) { 11961da177e4SLinus Torvalds info->pos += len; 11971da177e4SLinus Torvalds return; 11981da177e4SLinus Torvalds } 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds if (info->pos < info->offset) { 12011da177e4SLinus Torvalds data += (info->offset - info->pos); 12021da177e4SLinus Torvalds len -= (info->offset - info->pos); 12031da177e4SLinus Torvalds } 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds if (len > 0) { 12061da177e4SLinus Torvalds memcpy(info->buffer + info->pos, data, len); 12071da177e4SLinus Torvalds info->pos += len; 12081da177e4SLinus Torvalds } 12091da177e4SLinus Torvalds } 12101da177e4SLinus Torvalds 12110d0c7974SMoore, Eric Dean static int 12120d0c7974SMoore, Eric Dean mptscsih_copy_info(struct info_str *info, char *fmt, ...) 12131da177e4SLinus Torvalds { 12141da177e4SLinus Torvalds va_list args; 12151da177e4SLinus Torvalds char buf[81]; 12161da177e4SLinus Torvalds int len; 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds va_start(args, fmt); 12191da177e4SLinus Torvalds len = vsprintf(buf, fmt, args); 12201da177e4SLinus Torvalds va_end(args); 12211da177e4SLinus Torvalds 12220d0c7974SMoore, Eric Dean mptscsih_copy_mem_info(info, buf, len); 12231da177e4SLinus Torvalds return len; 12241da177e4SLinus Torvalds } 12251da177e4SLinus Torvalds 12260d0c7974SMoore, Eric Dean static int 12270d0c7974SMoore, Eric Dean mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len) 12281da177e4SLinus Torvalds { 12291da177e4SLinus Torvalds struct info_str info; 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds info.buffer = pbuf; 12321da177e4SLinus Torvalds info.length = len; 12331da177e4SLinus Torvalds info.offset = offset; 12341da177e4SLinus Torvalds info.pos = 0; 12351da177e4SLinus Torvalds 12360d0c7974SMoore, Eric Dean mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name); 12370d0c7974SMoore, Eric Dean mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word); 12380d0c7974SMoore, Eric Dean mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts); 12390d0c7974SMoore, Eric Dean mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth); 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds return ((info.pos > info.offset) ? info.pos - info.offset : 0); 12421da177e4SLinus Torvalds } 12431da177e4SLinus Torvalds 12441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 12451da177e4SLinus Torvalds /** 12461da177e4SLinus Torvalds * mptscsih_proc_info - Return information about MPT adapter 1247d9489fb6SRandy Dunlap * @host: scsi host struct 1248d9489fb6SRandy Dunlap * @buffer: if write, user data; if read, buffer for user 1249d9489fb6SRandy Dunlap * @start: returns the buffer address 1250d9489fb6SRandy Dunlap * @offset: if write, 0; if read, the current offset into the buffer from 1251d9489fb6SRandy Dunlap * the previous read. 1252d9489fb6SRandy Dunlap * @length: if write, return length; 1253d9489fb6SRandy Dunlap * @func: write = 1; read = 0 12541da177e4SLinus Torvalds * 12551da177e4SLinus Torvalds * (linux scsi_host_template.info routine) 12561da177e4SLinus Torvalds */ 12570d0c7974SMoore, Eric Dean int 12581da177e4SLinus Torvalds mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 12591da177e4SLinus Torvalds int length, int func) 12601da177e4SLinus Torvalds { 12611da177e4SLinus Torvalds MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; 12621da177e4SLinus Torvalds MPT_ADAPTER *ioc = hd->ioc; 12631da177e4SLinus Torvalds int size = 0; 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds if (func) { 12661da177e4SLinus Torvalds /* 12671da177e4SLinus Torvalds * write is not supported 12681da177e4SLinus Torvalds */ 12691da177e4SLinus Torvalds } else { 12701da177e4SLinus Torvalds if (start) 12711da177e4SLinus Torvalds *start = buffer; 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds size = mptscsih_host_info(ioc, buffer, offset, length); 12741da177e4SLinus Torvalds } 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds return size; 12771da177e4SLinus Torvalds } 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 12801da177e4SLinus Torvalds #define ADD_INDEX_LOG(req_ent) do { } while(0) 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 12831da177e4SLinus Torvalds /** 12841da177e4SLinus Torvalds * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. 12851da177e4SLinus Torvalds * @SCpnt: Pointer to scsi_cmnd structure 12861da177e4SLinus Torvalds * @done: Pointer SCSI mid-layer IO completion function 12871da177e4SLinus Torvalds * 12881da177e4SLinus Torvalds * (linux scsi_host_template.queuecommand routine) 12891da177e4SLinus Torvalds * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest 12901da177e4SLinus Torvalds * from a linux scsi_cmnd request and send it to the IOC. 12911da177e4SLinus Torvalds * 12921da177e4SLinus Torvalds * Returns 0. (rtn value discarded by linux scsi mid-layer) 12931da177e4SLinus Torvalds */ 12940d0c7974SMoore, Eric Dean int 12951da177e4SLinus Torvalds mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) 12961da177e4SLinus Torvalds { 12971da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 12981da177e4SLinus Torvalds MPT_FRAME_HDR *mf; 12991da177e4SLinus Torvalds SCSIIORequest_t *pScsiReq; 1300c7c82987SMoore, Eric Dean VirtDevice *vdev = SCpnt->device->hostdata; 13011da177e4SLinus Torvalds int lun; 13021da177e4SLinus Torvalds u32 datalen; 13031da177e4SLinus Torvalds u32 scsictl; 13041da177e4SLinus Torvalds u32 scsidir; 13051da177e4SLinus Torvalds u32 cmd_len; 13061da177e4SLinus Torvalds int my_idx; 13071da177e4SLinus Torvalds int ii; 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; 13101da177e4SLinus Torvalds lun = SCpnt->device->lun; 13111da177e4SLinus Torvalds SCpnt->scsi_done = done; 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", 13141da177e4SLinus Torvalds (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); 13151da177e4SLinus Torvalds 13161da177e4SLinus Torvalds if (hd->resetPending) { 13171da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", 13181da177e4SLinus Torvalds (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); 13191da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 13201da177e4SLinus Torvalds } 13211da177e4SLinus Torvalds 13221da177e4SLinus Torvalds /* 13231da177e4SLinus Torvalds * Put together a MPT SCSI request... 13241da177e4SLinus Torvalds */ 13250d0c7974SMoore, Eric Dean if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) { 13261da177e4SLinus Torvalds dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", 13271da177e4SLinus Torvalds hd->ioc->name)); 13281da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 13291da177e4SLinus Torvalds } 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds pScsiReq = (SCSIIORequest_t *) mf; 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); 13341da177e4SLinus Torvalds 13351da177e4SLinus Torvalds ADD_INDEX_LOG(my_idx); 13361da177e4SLinus Torvalds 13370d0c7974SMoore, Eric Dean /* TUR's being issued with scsictl=0x02000000 (DATA_IN)! 13381da177e4SLinus Torvalds * Seems we may receive a buffer (datalen>0) even when there 13391da177e4SLinus Torvalds * will be no data transfer! GRRRRR... 13401da177e4SLinus Torvalds */ 13411da177e4SLinus Torvalds if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { 13421928d73fSFUJITA Tomonori datalen = scsi_bufflen(SCpnt); 13431da177e4SLinus Torvalds scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ 13441da177e4SLinus Torvalds } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { 13451928d73fSFUJITA Tomonori datalen = scsi_bufflen(SCpnt); 13461da177e4SLinus Torvalds scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ 13471da177e4SLinus Torvalds } else { 13481da177e4SLinus Torvalds datalen = 0; 13491da177e4SLinus Torvalds scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; 13501da177e4SLinus Torvalds } 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds /* Default to untagged. Once a target structure has been allocated, 13531da177e4SLinus Torvalds * use the Inquiry data to determine if device supports tagged. 13541da177e4SLinus Torvalds */ 1355c7c82987SMoore, Eric Dean if (vdev 1356c7c82987SMoore, Eric Dean && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) 13571da177e4SLinus Torvalds && (SCpnt->device->tagged_supported)) { 13581da177e4SLinus Torvalds scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; 13591da177e4SLinus Torvalds } else { 13601da177e4SLinus Torvalds scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED; 13611da177e4SLinus Torvalds } 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds /* Use the above information to set up the message frame 13641da177e4SLinus Torvalds */ 1365793955f5SEric Moore pScsiReq->TargetID = (u8) vdev->vtarget->id; 1366793955f5SEric Moore pScsiReq->Bus = vdev->vtarget->channel; 13671da177e4SLinus Torvalds pScsiReq->ChainOffset = 0; 1368c92f222eSJames Bottomley if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) 1369c92f222eSJames Bottomley pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; 1370c92f222eSJames Bottomley else 13711da177e4SLinus Torvalds pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; 13721da177e4SLinus Torvalds pScsiReq->CDBLength = SCpnt->cmd_len; 13731da177e4SLinus Torvalds pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; 13741da177e4SLinus Torvalds pScsiReq->Reserved = 0; 13751da177e4SLinus Torvalds pScsiReq->MsgFlags = mpt_msg_flags(); 1376793955f5SEric Moore int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); 13771da177e4SLinus Torvalds pScsiReq->Control = cpu_to_le32(scsictl); 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds /* 13801da177e4SLinus Torvalds * Write SCSI CDB into the message 13811da177e4SLinus Torvalds */ 13821da177e4SLinus Torvalds cmd_len = SCpnt->cmd_len; 13831da177e4SLinus Torvalds for (ii=0; ii < cmd_len; ii++) 13841da177e4SLinus Torvalds pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds for (ii=cmd_len; ii < 16; ii++) 13871da177e4SLinus Torvalds pScsiReq->CDB[ii] = 0; 13881da177e4SLinus Torvalds 13891da177e4SLinus Torvalds /* DataLength */ 13901da177e4SLinus Torvalds pScsiReq->DataLength = cpu_to_le32(datalen); 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds /* SenseBuffer low address */ 13931da177e4SLinus Torvalds pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma 13941da177e4SLinus Torvalds + (my_idx * MPT_SENSE_BUFFER_ALLOC)); 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds /* Now add the SG list 13971da177e4SLinus Torvalds * Always have a SGE even if null length. 13981da177e4SLinus Torvalds */ 13991da177e4SLinus Torvalds if (datalen == 0) { 14001da177e4SLinus Torvalds /* Add a NULL SGE */ 14011da177e4SLinus Torvalds mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, 14021da177e4SLinus Torvalds (dma_addr_t) -1); 14031da177e4SLinus Torvalds } else { 14041da177e4SLinus Torvalds /* Add a 32 or 64 bit SGE */ 14051da177e4SLinus Torvalds if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) 14061da177e4SLinus Torvalds goto fail; 14071da177e4SLinus Torvalds } 14081da177e4SLinus Torvalds 14093dc0b03fSEric Moore SCpnt->host_scribble = (unsigned char *)mf; 14101da177e4SLinus Torvalds hd->ScsiLookup[my_idx] = SCpnt; 14111da177e4SLinus Torvalds 14120d0c7974SMoore, Eric Dean mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf); 14131da177e4SLinus Torvalds dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", 14141da177e4SLinus Torvalds hd->ioc->name, SCpnt, mf, my_idx)); 14151da177e4SLinus Torvalds DBG_DUMP_REQUEST_FRAME(mf) 14161da177e4SLinus Torvalds return 0; 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds fail: 1419466544d8SMoore, Eric Dean hd->ScsiLookup[my_idx] = NULL; 14201da177e4SLinus Torvalds mptscsih_freeChainBuffers(hd->ioc, my_idx); 14211da177e4SLinus Torvalds mpt_free_msg_frame(hd->ioc, mf); 14221da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 14231da177e4SLinus Torvalds } 14241da177e4SLinus Torvalds 14251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 14261da177e4SLinus Torvalds /* 14271da177e4SLinus Torvalds * mptscsih_freeChainBuffers - Function to free chain buffers associated 14281da177e4SLinus Torvalds * with a SCSI IO request 14291da177e4SLinus Torvalds * @hd: Pointer to the MPT_SCSI_HOST instance 14301da177e4SLinus Torvalds * @req_idx: Index of the SCSI IO request frame. 14311da177e4SLinus Torvalds * 14321da177e4SLinus Torvalds * Called if SG chain buffer allocation fails and mptscsih callbacks. 14331da177e4SLinus Torvalds * No return. 14341da177e4SLinus Torvalds */ 14351da177e4SLinus Torvalds static void 14361da177e4SLinus Torvalds mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) 14371da177e4SLinus Torvalds { 14381da177e4SLinus Torvalds MPT_FRAME_HDR *chain; 14391da177e4SLinus Torvalds unsigned long flags; 14401da177e4SLinus Torvalds int chain_idx; 14411da177e4SLinus Torvalds int next; 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds /* Get the first chain index and reset 14441da177e4SLinus Torvalds * tracker state. 14451da177e4SLinus Torvalds */ 14461da177e4SLinus Torvalds chain_idx = ioc->ReqToChain[req_idx]; 14471da177e4SLinus Torvalds ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN; 14481da177e4SLinus Torvalds 14491da177e4SLinus Torvalds while (chain_idx != MPT_HOST_NO_CHAIN) { 14501da177e4SLinus Torvalds 14511da177e4SLinus Torvalds /* Save the next chain buffer index */ 14521da177e4SLinus Torvalds next = ioc->ChainToChain[chain_idx]; 14531da177e4SLinus Torvalds 14541da177e4SLinus Torvalds /* Free this chain buffer and reset 14551da177e4SLinus Torvalds * tracker 14561da177e4SLinus Torvalds */ 14571da177e4SLinus Torvalds ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN; 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer 14601da177e4SLinus Torvalds + (chain_idx * ioc->req_sz)); 14611da177e4SLinus Torvalds 14621da177e4SLinus Torvalds spin_lock_irqsave(&ioc->FreeQlock, flags); 14631da177e4SLinus Torvalds list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ); 14641da177e4SLinus Torvalds spin_unlock_irqrestore(&ioc->FreeQlock, flags); 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n", 14671da177e4SLinus Torvalds ioc->name, chain_idx)); 14681da177e4SLinus Torvalds 14691da177e4SLinus Torvalds /* handle next */ 14701da177e4SLinus Torvalds chain_idx = next; 14711da177e4SLinus Torvalds } 14721da177e4SLinus Torvalds return; 14731da177e4SLinus Torvalds } 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 14761da177e4SLinus Torvalds /* 14771da177e4SLinus Torvalds * Reset Handling 14781da177e4SLinus Torvalds */ 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1481cd2c6191SEric Moore /** 14821da177e4SLinus Torvalds * mptscsih_TMHandler - Generic handler for SCSI Task Management. 14831544d677SRandy Dunlap * @hd: Pointer to MPT SCSI HOST structure 14841da177e4SLinus Torvalds * @type: Task Management type 14851544d677SRandy Dunlap * @channel: channel number for task management 1486793955f5SEric Moore * @id: Logical Target ID for reset (if appropriate) 14871da177e4SLinus Torvalds * @lun: Logical Unit for reset (if appropriate) 14881da177e4SLinus Torvalds * @ctx2abort: Context for the task to be aborted (if appropriate) 14891544d677SRandy Dunlap * @timeout: timeout for task management control 14901544d677SRandy Dunlap * 14911544d677SRandy Dunlap * Fall through to mpt_HardResetHandler if: not operational, too many 14921544d677SRandy Dunlap * failed TM requests or handshake failure. 14931da177e4SLinus Torvalds * 14941da177e4SLinus Torvalds * Remark: Currently invoked from a non-interrupt thread (_bh). 14951da177e4SLinus Torvalds * 14961da177e4SLinus Torvalds * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC 14971da177e4SLinus Torvalds * will be active. 14981da177e4SLinus Torvalds * 14991544d677SRandy Dunlap * Returns 0 for SUCCESS, or %FAILED. 1500cd2c6191SEric Moore **/ 1501663e1aa1SJames Bottomley int 1502793955f5SEric Moore mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) 15031da177e4SLinus Torvalds { 15041da177e4SLinus Torvalds MPT_ADAPTER *ioc; 15051da177e4SLinus Torvalds int rc = -1; 15061da177e4SLinus Torvalds u32 ioc_raw_state; 15071da177e4SLinus Torvalds unsigned long flags; 15081da177e4SLinus Torvalds 15091da177e4SLinus Torvalds ioc = hd->ioc; 15101da177e4SLinus Torvalds dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); 15111da177e4SLinus Torvalds 15121da177e4SLinus Torvalds // SJR - CHECKME - Can we avoid this here? 15131da177e4SLinus Torvalds // (mpt_HardResetHandler has this check...) 15141da177e4SLinus Torvalds spin_lock_irqsave(&ioc->diagLock, flags); 15151da177e4SLinus Torvalds if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { 15161da177e4SLinus Torvalds spin_unlock_irqrestore(&ioc->diagLock, flags); 15171da177e4SLinus Torvalds return FAILED; 15181da177e4SLinus Torvalds } 15191da177e4SLinus Torvalds spin_unlock_irqrestore(&ioc->diagLock, flags); 15201da177e4SLinus Torvalds 15211da177e4SLinus Torvalds /* Wait a fixed amount of time for the TM pending flag to be cleared. 1522cd2c6191SEric Moore * If we time out and not bus reset, then we return a FAILED status 1523cd2c6191SEric Moore * to the caller. 1524cd2c6191SEric Moore * The call to mptscsih_tm_pending_wait() will set the pending flag 1525cd2c6191SEric Moore * if we are 15261da177e4SLinus Torvalds * successful. Otherwise, reload the FW. 15271da177e4SLinus Torvalds */ 15281da177e4SLinus Torvalds if (mptscsih_tm_pending_wait(hd) == FAILED) { 15291da177e4SLinus Torvalds if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { 1530c6678e0cSChristoph Hellwig dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: " 15311da177e4SLinus Torvalds "Timed out waiting for last TM (%d) to complete! \n", 15321da177e4SLinus Torvalds hd->ioc->name, hd->tmPending)); 15331da177e4SLinus Torvalds return FAILED; 15341da177e4SLinus Torvalds } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { 1535cd2c6191SEric Moore dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target " 1536cd2c6191SEric Moore "reset: Timed out waiting for last TM (%d) " 1537cd2c6191SEric Moore "to complete! \n", hd->ioc->name, 1538cd2c6191SEric Moore hd->tmPending)); 15391da177e4SLinus Torvalds return FAILED; 15401da177e4SLinus Torvalds } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { 1541c6678e0cSChristoph Hellwig dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: " 15421da177e4SLinus Torvalds "Timed out waiting for last TM (%d) to complete! \n", 15431da177e4SLinus Torvalds hd->ioc->name, hd->tmPending)); 15441da177e4SLinus Torvalds return FAILED; 15451da177e4SLinus Torvalds } 15461da177e4SLinus Torvalds } else { 15471da177e4SLinus Torvalds spin_lock_irqsave(&hd->ioc->FreeQlock, flags); 15481da177e4SLinus Torvalds hd->tmPending |= (1 << type); 15491da177e4SLinus Torvalds spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); 15501da177e4SLinus Torvalds } 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds ioc_raw_state = mpt_GetIocState(hd->ioc, 0); 15531da177e4SLinus Torvalds 15541da177e4SLinus Torvalds if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { 15551da177e4SLinus Torvalds printk(MYIOC_s_WARN_FMT 1556cd2c6191SEric Moore "TM Handler for type=%x: IOC Not operational (0x%x)!\n", 1557cd2c6191SEric Moore ioc->name, type, ioc_raw_state); 1558cd2c6191SEric Moore printk(KERN_WARNING " Issuing HardReset!!\n"); 1559cd2c6191SEric Moore if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) 1560cd2c6191SEric Moore printk((KERN_WARNING "TMHandler: HardReset " 1561cd2c6191SEric Moore "FAILED!!\n")); 1562cd2c6191SEric Moore return FAILED; 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds 1565cd2c6191SEric Moore if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { 1566cd2c6191SEric Moore printk(MYIOC_s_WARN_FMT 1567cd2c6191SEric Moore "TM Handler for type=%x: ioc_state: " 1568cd2c6191SEric Moore "DOORBELL_ACTIVE (0x%x)!\n", 1569cd2c6191SEric Moore ioc->name, type, ioc_raw_state); 1570cd2c6191SEric Moore return FAILED; 1571cd2c6191SEric Moore } 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds /* Isse the Task Mgmt request. 15741da177e4SLinus Torvalds */ 15751da177e4SLinus Torvalds if (hd->hard_resets < -1) 15761da177e4SLinus Torvalds hd->hard_resets++; 15771da177e4SLinus Torvalds 1578cd2c6191SEric Moore rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, 1579cd2c6191SEric Moore ctx2abort, timeout); 1580cd2c6191SEric Moore if (rc) 1581cd2c6191SEric Moore printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", 1582cd2c6191SEric Moore hd->ioc->name); 1583cd2c6191SEric Moore else 1584cd2c6191SEric Moore dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", 15851da177e4SLinus Torvalds hd->ioc->name)); 15863dc0b03fSEric Moore 15871da177e4SLinus Torvalds dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc)); 15881da177e4SLinus Torvalds 15891da177e4SLinus Torvalds return rc; 15901da177e4SLinus Torvalds } 15911da177e4SLinus Torvalds 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1594cd2c6191SEric Moore /** 15951da177e4SLinus Torvalds * mptscsih_IssueTaskMgmt - Generic send Task Management function. 15961da177e4SLinus Torvalds * @hd: Pointer to MPT_SCSI_HOST structure 15971da177e4SLinus Torvalds * @type: Task Management type 15981544d677SRandy Dunlap * @channel: channel number for task management 1599793955f5SEric Moore * @id: Logical Target ID for reset (if appropriate) 16001da177e4SLinus Torvalds * @lun: Logical Unit for reset (if appropriate) 16011da177e4SLinus Torvalds * @ctx2abort: Context for the task to be aborted (if appropriate) 16021544d677SRandy Dunlap * @timeout: timeout for task management control 16031da177e4SLinus Torvalds * 16041da177e4SLinus Torvalds * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) 16051da177e4SLinus Torvalds * or a non-interrupt thread. In the former, must not call schedule(). 16061da177e4SLinus Torvalds * 16071da177e4SLinus Torvalds * Not all fields are meaningfull for all task types. 16081da177e4SLinus Torvalds * 1609cd2c6191SEric Moore * Returns 0 for SUCCESS, or FAILED. 1610cd2c6191SEric Moore * 1611cd2c6191SEric Moore **/ 16121da177e4SLinus Torvalds static int 1613793955f5SEric Moore mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) 16141da177e4SLinus Torvalds { 16151da177e4SLinus Torvalds MPT_FRAME_HDR *mf; 16161da177e4SLinus Torvalds SCSITaskMgmt_t *pScsiTm; 16171da177e4SLinus Torvalds int ii; 16181da177e4SLinus Torvalds int retval; 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds /* Return Fail to calling function if no message frames available. 16211da177e4SLinus Torvalds */ 16220d0c7974SMoore, Eric Dean if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) { 16231da177e4SLinus Torvalds dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", 16241da177e4SLinus Torvalds hd->ioc->name)); 1625c6678e0cSChristoph Hellwig return FAILED; 16261da177e4SLinus Torvalds } 16271da177e4SLinus Torvalds dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", 16281da177e4SLinus Torvalds hd->ioc->name, mf)); 16291da177e4SLinus Torvalds 16301da177e4SLinus Torvalds /* Format the Request 16311da177e4SLinus Torvalds */ 16321da177e4SLinus Torvalds pScsiTm = (SCSITaskMgmt_t *) mf; 1633793955f5SEric Moore pScsiTm->TargetID = id; 16341da177e4SLinus Torvalds pScsiTm->Bus = channel; 16351da177e4SLinus Torvalds pScsiTm->ChainOffset = 0; 16361da177e4SLinus Torvalds pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; 16371da177e4SLinus Torvalds 16381da177e4SLinus Torvalds pScsiTm->Reserved = 0; 16391da177e4SLinus Torvalds pScsiTm->TaskType = type; 16401da177e4SLinus Torvalds pScsiTm->Reserved1 = 0; 16411da177e4SLinus Torvalds pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) 16421da177e4SLinus Torvalds ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; 16431da177e4SLinus Torvalds 1644793955f5SEric Moore int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); 16451da177e4SLinus Torvalds 16461da177e4SLinus Torvalds for (ii=0; ii < 7; ii++) 16471da177e4SLinus Torvalds pScsiTm->Reserved2[ii] = 0; 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds pScsiTm->TaskMsgContext = ctx2abort; 16501da177e4SLinus Torvalds 1651cd2c6191SEric Moore dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " 1652cd2c6191SEric Moore "type=%d\n", hd->ioc->name, ctx2abort, type)); 16531da177e4SLinus Torvalds 16541da177e4SLinus Torvalds DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); 16551da177e4SLinus Torvalds 16560d0c7974SMoore, Eric Dean if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc, 1657cd2c6191SEric Moore sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) { 1658cd2c6191SEric Moore dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!" 1659cd2c6191SEric Moore " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd, 1660cd2c6191SEric Moore hd->ioc, mf, retval)); 1661cd2c6191SEric Moore goto fail_out; 16621da177e4SLinus Torvalds } 16631da177e4SLinus Torvalds 16641da177e4SLinus Torvalds if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { 1665cd2c6191SEric Moore dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!" 16661da177e4SLinus Torvalds " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, 16671da177e4SLinus Torvalds hd->ioc, mf)); 16681da177e4SLinus Torvalds dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", 16691da177e4SLinus Torvalds hd->ioc->name)); 16701da177e4SLinus Torvalds retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP); 1671cd2c6191SEric Moore dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n", 1672cd2c6191SEric Moore hd->ioc->name, retval)); 1673cd2c6191SEric Moore goto fail_out; 16741da177e4SLinus Torvalds } 16751da177e4SLinus Torvalds 1676cd2c6191SEric Moore /* 1677cd2c6191SEric Moore * Handle success case, see if theres a non-zero ioc_status. 1678cd2c6191SEric Moore */ 1679cd2c6191SEric Moore if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || 1680cd2c6191SEric Moore hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || 1681cd2c6191SEric Moore hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) 1682cd2c6191SEric Moore retval = 0; 1683cd2c6191SEric Moore else 1684cd2c6191SEric Moore retval = FAILED; 1685cd2c6191SEric Moore 16861da177e4SLinus Torvalds return retval; 1687cd2c6191SEric Moore 1688cd2c6191SEric Moore fail_out: 1689cd2c6191SEric Moore 1690cd2c6191SEric Moore /* 1691cd2c6191SEric Moore * Free task managment mf, and corresponding tm flags 1692cd2c6191SEric Moore */ 1693cd2c6191SEric Moore mpt_free_msg_frame(hd->ioc, mf); 1694cd2c6191SEric Moore hd->tmPending = 0; 1695cd2c6191SEric Moore hd->tmState = TM_STATE_NONE; 1696cd2c6191SEric Moore return FAILED; 16971da177e4SLinus Torvalds } 16981da177e4SLinus Torvalds 1699d66c7a0fSChristoph Hellwig static int 1700d66c7a0fSChristoph Hellwig mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) 1701d66c7a0fSChristoph Hellwig { 1702d66c7a0fSChristoph Hellwig switch (ioc->bus_type) { 1703d66c7a0fSChristoph Hellwig case FC: 1704d66c7a0fSChristoph Hellwig return 40; 1705d66c7a0fSChristoph Hellwig case SAS: 1706d66c7a0fSChristoph Hellwig return 10; 1707d66c7a0fSChristoph Hellwig case SPI: 1708d66c7a0fSChristoph Hellwig default: 1709d66c7a0fSChristoph Hellwig return 2; 1710d66c7a0fSChristoph Hellwig } 1711d66c7a0fSChristoph Hellwig } 1712d66c7a0fSChristoph Hellwig 17131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 17141da177e4SLinus Torvalds /** 17151da177e4SLinus Torvalds * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant 17161da177e4SLinus Torvalds * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted 17171da177e4SLinus Torvalds * 17181da177e4SLinus Torvalds * (linux scsi_host_template.eh_abort_handler routine) 17191da177e4SLinus Torvalds * 17201da177e4SLinus Torvalds * Returns SUCCESS or FAILED. 1721cd2c6191SEric Moore **/ 17220d0c7974SMoore, Eric Dean int 17231da177e4SLinus Torvalds mptscsih_abort(struct scsi_cmnd * SCpnt) 17241da177e4SLinus Torvalds { 17251da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 17261da177e4SLinus Torvalds MPT_FRAME_HDR *mf; 17271da177e4SLinus Torvalds u32 ctx2abort; 17281da177e4SLinus Torvalds int scpnt_idx; 1729466544d8SMoore, Eric Dean int retval; 1730958d4a32SEric Moore VirtDevice *vdevice; 17313dc0b03fSEric Moore ulong sn = SCpnt->serial_number; 1732958d4a32SEric Moore MPT_ADAPTER *ioc; 17331da177e4SLinus Torvalds 17341da177e4SLinus Torvalds /* If we can't locate our host adapter structure, return FAILED status. 17351da177e4SLinus Torvalds */ 17361da177e4SLinus Torvalds if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { 17371da177e4SLinus Torvalds SCpnt->result = DID_RESET << 16; 17381da177e4SLinus Torvalds SCpnt->scsi_done(SCpnt); 1739958d4a32SEric Moore dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate " 1740958d4a32SEric Moore "host! (sc=%p)\n", SCpnt)); 17411da177e4SLinus Torvalds return FAILED; 17421da177e4SLinus Torvalds } 17431da177e4SLinus Torvalds 1744958d4a32SEric Moore ioc = hd->ioc; 1745958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n", 1746958d4a32SEric Moore ioc->name, SCpnt); 1747958d4a32SEric Moore scsi_print_command(SCpnt); 1748958d4a32SEric Moore 1749958d4a32SEric Moore vdevice = SCpnt->device->hostdata; 1750958d4a32SEric Moore if (!vdevice || !vdevice->vtarget) { 1751958d4a32SEric Moore dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been " 1752958d4a32SEric Moore "deleted (sc=%p)\n", ioc->name, SCpnt)); 1753958d4a32SEric Moore SCpnt->result = DID_NO_CONNECT << 16; 1754958d4a32SEric Moore SCpnt->scsi_done(SCpnt); 1755958d4a32SEric Moore retval = 0; 1756958d4a32SEric Moore goto out; 1757958d4a32SEric Moore } 1758958d4a32SEric Moore 17591da177e4SLinus Torvalds /* Find this command 17601da177e4SLinus Torvalds */ 17611da177e4SLinus Torvalds if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { 17621da177e4SLinus Torvalds /* Cmd not found in ScsiLookup. 17631da177e4SLinus Torvalds * Do OS callback. 17641da177e4SLinus Torvalds */ 17651da177e4SLinus Torvalds SCpnt->result = DID_RESET << 16; 1766466544d8SMoore, Eric Dean dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: " 1767958d4a32SEric Moore "Command not in the active list! (sc=%p)\n", ioc->name, 1768958d4a32SEric Moore SCpnt)); 1769958d4a32SEric Moore retval = 0; 1770958d4a32SEric Moore goto out; 17711da177e4SLinus Torvalds } 17721da177e4SLinus Torvalds 1773958d4a32SEric Moore if (hd->resetPending) { 1774958d4a32SEric Moore retval = FAILED; 1775958d4a32SEric Moore goto out; 1776958d4a32SEric Moore } 177765207fedSMoore, Eric 177865207fedSMoore, Eric if (hd->timeouts < -1) 177965207fedSMoore, Eric hd->timeouts++; 178065207fedSMoore, Eric 17811da177e4SLinus Torvalds /* Most important! Set TaskMsgContext to SCpnt's MsgContext! 17821da177e4SLinus Torvalds * (the IO to be ABORT'd) 17831da177e4SLinus Torvalds * 17841da177e4SLinus Torvalds * NOTE: Since we do not byteswap MsgContext, we do not 17851da177e4SLinus Torvalds * swap it here either. It is an opaque cookie to 17861da177e4SLinus Torvalds * the controller, so it does not matter. -DaveM 17871da177e4SLinus Torvalds */ 17881da177e4SLinus Torvalds mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); 17891da177e4SLinus Torvalds ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; 17901da177e4SLinus Torvalds 17911da177e4SLinus Torvalds hd->abortSCpnt = SCpnt; 17921da177e4SLinus Torvalds 1793466544d8SMoore, Eric Dean retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, 1794958d4a32SEric Moore vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, 1795958d4a32SEric Moore ctx2abort, mptscsih_get_tm_timeout(ioc)); 17961da177e4SLinus Torvalds 17973dc0b03fSEric Moore if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx && 1798cd2c6191SEric Moore SCpnt->serial_number == sn) 17993dc0b03fSEric Moore retval = FAILED; 18003dc0b03fSEric Moore 1801958d4a32SEric Moore out: 1802958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", 1803958d4a32SEric Moore ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); 18041da177e4SLinus Torvalds 1805466544d8SMoore, Eric Dean if (retval == 0) 1806466544d8SMoore, Eric Dean return SUCCESS; 1807cd2c6191SEric Moore else 18081da177e4SLinus Torvalds return FAILED; 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 18121da177e4SLinus Torvalds /** 18131da177e4SLinus Torvalds * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant 18141da177e4SLinus Torvalds * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to 18151da177e4SLinus Torvalds * 18161da177e4SLinus Torvalds * (linux scsi_host_template.eh_dev_reset_handler routine) 18171da177e4SLinus Torvalds * 18181da177e4SLinus Torvalds * Returns SUCCESS or FAILED. 1819cd2c6191SEric Moore **/ 18200d0c7974SMoore, Eric Dean int 18211da177e4SLinus Torvalds mptscsih_dev_reset(struct scsi_cmnd * SCpnt) 18221da177e4SLinus Torvalds { 18231da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 1824466544d8SMoore, Eric Dean int retval; 1825958d4a32SEric Moore VirtDevice *vdevice; 1826958d4a32SEric Moore MPT_ADAPTER *ioc; 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds /* If we can't locate our host adapter structure, return FAILED status. 18291da177e4SLinus Torvalds */ 18301da177e4SLinus Torvalds if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ 1831958d4a32SEric Moore dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't " 1832958d4a32SEric Moore "locate host! (sc=%p)\n", SCpnt)); 18331da177e4SLinus Torvalds return FAILED; 18341da177e4SLinus Torvalds } 18351da177e4SLinus Torvalds 1836958d4a32SEric Moore ioc = hd->ioc; 1837958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n", 1838958d4a32SEric Moore ioc->name, SCpnt); 1839466544d8SMoore, Eric Dean scsi_print_command(SCpnt); 18401da177e4SLinus Torvalds 1841958d4a32SEric Moore if (hd->resetPending) { 1842958d4a32SEric Moore retval = FAILED; 1843958d4a32SEric Moore goto out; 1844958d4a32SEric Moore } 1845466544d8SMoore, Eric Dean 1846958d4a32SEric Moore vdevice = SCpnt->device->hostdata; 1847958d4a32SEric Moore if (!vdevice || !vdevice->vtarget) { 1848958d4a32SEric Moore retval = 0; 1849958d4a32SEric Moore goto out; 1850958d4a32SEric Moore } 1851958d4a32SEric Moore 1852958d4a32SEric Moore retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 1853958d4a32SEric Moore vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0, 1854958d4a32SEric Moore mptscsih_get_tm_timeout(ioc)); 1855958d4a32SEric Moore 1856958d4a32SEric Moore out: 1857958d4a32SEric Moore printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", 1858958d4a32SEric Moore ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); 1859466544d8SMoore, Eric Dean 1860466544d8SMoore, Eric Dean if (retval == 0) 1861466544d8SMoore, Eric Dean return SUCCESS; 1862cd2c6191SEric Moore else 1863466544d8SMoore, Eric Dean return FAILED; 18641da177e4SLinus Torvalds } 18651da177e4SLinus Torvalds 1866cd2c6191SEric Moore 18671da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 18681da177e4SLinus Torvalds /** 18691da177e4SLinus Torvalds * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant 18701da177e4SLinus Torvalds * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to 18711da177e4SLinus Torvalds * 18721da177e4SLinus Torvalds * (linux scsi_host_template.eh_bus_reset_handler routine) 18731da177e4SLinus Torvalds * 18741da177e4SLinus Torvalds * Returns SUCCESS or FAILED. 1875cd2c6191SEric Moore **/ 18760d0c7974SMoore, Eric Dean int 18771da177e4SLinus Torvalds mptscsih_bus_reset(struct scsi_cmnd * SCpnt) 18781da177e4SLinus Torvalds { 18791da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 1880466544d8SMoore, Eric Dean int retval; 1881c7c82987SMoore, Eric Dean VirtDevice *vdev; 1882958d4a32SEric Moore MPT_ADAPTER *ioc; 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds /* If we can't locate our host adapter structure, return FAILED status. 18851da177e4SLinus Torvalds */ 18861da177e4SLinus Torvalds if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ 1887958d4a32SEric Moore dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't " 1888958d4a32SEric Moore "locate host! (sc=%p)\n", SCpnt )); 18891da177e4SLinus Torvalds return FAILED; 18901da177e4SLinus Torvalds } 18911da177e4SLinus Torvalds 1892958d4a32SEric Moore ioc = hd->ioc; 1893958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n", 1894958d4a32SEric Moore ioc->name, SCpnt); 1895466544d8SMoore, Eric Dean scsi_print_command(SCpnt); 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds if (hd->timeouts < -1) 18981da177e4SLinus Torvalds hd->timeouts++; 18991da177e4SLinus Torvalds 1900c7c82987SMoore, Eric Dean vdev = SCpnt->device->hostdata; 1901466544d8SMoore, Eric Dean retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 1902958d4a32SEric Moore vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); 19031da177e4SLinus Torvalds 1904958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n", 1905958d4a32SEric Moore ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); 1906466544d8SMoore, Eric Dean 1907466544d8SMoore, Eric Dean if (retval == 0) 1908466544d8SMoore, Eric Dean return SUCCESS; 1909cd2c6191SEric Moore else 1910466544d8SMoore, Eric Dean return FAILED; 19111da177e4SLinus Torvalds } 19121da177e4SLinus Torvalds 19131da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 19141da177e4SLinus Torvalds /** 1915d9489fb6SRandy Dunlap * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant) 19161da177e4SLinus Torvalds * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to 19171da177e4SLinus Torvalds * 19181da177e4SLinus Torvalds * (linux scsi_host_template.eh_host_reset_handler routine) 19191da177e4SLinus Torvalds * 19201da177e4SLinus Torvalds * Returns SUCCESS or FAILED. 19211da177e4SLinus Torvalds */ 19220d0c7974SMoore, Eric Dean int 19231da177e4SLinus Torvalds mptscsih_host_reset(struct scsi_cmnd *SCpnt) 19241da177e4SLinus Torvalds { 19251da177e4SLinus Torvalds MPT_SCSI_HOST * hd; 1926958d4a32SEric Moore int retval; 1927958d4a32SEric Moore MPT_ADAPTER *ioc; 19281da177e4SLinus Torvalds 19291da177e4SLinus Torvalds /* If we can't locate the host to reset, then we failed. */ 19301da177e4SLinus Torvalds if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ 1931958d4a32SEric Moore dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't " 1932958d4a32SEric Moore "locate host! (sc=%p)\n", SCpnt)); 19331da177e4SLinus Torvalds return FAILED; 19341da177e4SLinus Torvalds } 19351da177e4SLinus Torvalds 1936958d4a32SEric Moore ioc = hd->ioc; 1937958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n", 1938958d4a32SEric Moore ioc->name, SCpnt); 19391da177e4SLinus Torvalds 19401da177e4SLinus Torvalds /* If our attempts to reset the host failed, then return a failed 19411da177e4SLinus Torvalds * status. The host will be taken off line by the SCSI mid-layer. 19421da177e4SLinus Torvalds */ 19431da177e4SLinus Torvalds if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) { 1944958d4a32SEric Moore retval = FAILED; 19451da177e4SLinus Torvalds } else { 19461da177e4SLinus Torvalds /* Make sure TM pending is cleared and TM state is set to 19471da177e4SLinus Torvalds * NONE. 19481da177e4SLinus Torvalds */ 1949958d4a32SEric Moore retval = 0; 19501da177e4SLinus Torvalds hd->tmPending = 0; 19511da177e4SLinus Torvalds hd->tmState = TM_STATE_NONE; 19521da177e4SLinus Torvalds } 19531da177e4SLinus Torvalds 1954958d4a32SEric Moore printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n", 1955958d4a32SEric Moore ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); 19561da177e4SLinus Torvalds 1957958d4a32SEric Moore return retval; 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 19611da177e4SLinus Torvalds /** 1962d9489fb6SRandy Dunlap * mptscsih_tm_pending_wait - wait for pending task management request to complete 19631da177e4SLinus Torvalds * @hd: Pointer to MPT host structure. 19641da177e4SLinus Torvalds * 19651da177e4SLinus Torvalds * Returns {SUCCESS,FAILED}. 19661da177e4SLinus Torvalds */ 19671da177e4SLinus Torvalds static int 19681da177e4SLinus Torvalds mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) 19691da177e4SLinus Torvalds { 19701da177e4SLinus Torvalds unsigned long flags; 19711da177e4SLinus Torvalds int loop_count = 4 * 10; /* Wait 10 seconds */ 19721da177e4SLinus Torvalds int status = FAILED; 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds do { 19751da177e4SLinus Torvalds spin_lock_irqsave(&hd->ioc->FreeQlock, flags); 19761da177e4SLinus Torvalds if (hd->tmState == TM_STATE_NONE) { 19771da177e4SLinus Torvalds hd->tmState = TM_STATE_IN_PROGRESS; 19781da177e4SLinus Torvalds hd->tmPending = 1; 19791da177e4SLinus Torvalds spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); 1980c6678e0cSChristoph Hellwig status = SUCCESS; 19811da177e4SLinus Torvalds break; 19821da177e4SLinus Torvalds } 19831da177e4SLinus Torvalds spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); 19841da177e4SLinus Torvalds msleep(250); 19851da177e4SLinus Torvalds } while (--loop_count); 19861da177e4SLinus Torvalds 19871da177e4SLinus Torvalds return status; 19881da177e4SLinus Torvalds } 19891da177e4SLinus Torvalds 19901da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 19911da177e4SLinus Torvalds /** 19921da177e4SLinus Torvalds * mptscsih_tm_wait_for_completion - wait for completion of TM task 19931da177e4SLinus Torvalds * @hd: Pointer to MPT host structure. 19941544d677SRandy Dunlap * @timeout: timeout value 19951da177e4SLinus Torvalds * 19961da177e4SLinus Torvalds * Returns {SUCCESS,FAILED}. 19971da177e4SLinus Torvalds */ 19981da177e4SLinus Torvalds static int 19991da177e4SLinus Torvalds mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) 20001da177e4SLinus Torvalds { 20011da177e4SLinus Torvalds unsigned long flags; 20021da177e4SLinus Torvalds int loop_count = 4 * timeout; 20031da177e4SLinus Torvalds int status = FAILED; 20041da177e4SLinus Torvalds 20051da177e4SLinus Torvalds do { 20061da177e4SLinus Torvalds spin_lock_irqsave(&hd->ioc->FreeQlock, flags); 20071da177e4SLinus Torvalds if(hd->tmPending == 0) { 20081da177e4SLinus Torvalds status = SUCCESS; 20091da177e4SLinus Torvalds spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); 20101da177e4SLinus Torvalds break; 20111da177e4SLinus Torvalds } 20121da177e4SLinus Torvalds spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); 2013d6be06c8SMichael Reed msleep(250); 20141da177e4SLinus Torvalds } while (--loop_count); 20151da177e4SLinus Torvalds 20161da177e4SLinus Torvalds return status; 20171da177e4SLinus Torvalds } 20181da177e4SLinus Torvalds 20191da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 20209f63bb73SMoore, Eric static void 20219f63bb73SMoore, Eric mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) 20229f63bb73SMoore, Eric { 20239f63bb73SMoore, Eric char *desc; 20249f63bb73SMoore, Eric 20259f63bb73SMoore, Eric switch (response_code) { 20269f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_TM_COMPLETE: 20279f63bb73SMoore, Eric desc = "The task completed."; 20289f63bb73SMoore, Eric break; 20299f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_INVALID_FRAME: 20309f63bb73SMoore, Eric desc = "The IOC received an invalid frame status."; 20319f63bb73SMoore, Eric break; 20329f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: 20339f63bb73SMoore, Eric desc = "The task type is not supported."; 20349f63bb73SMoore, Eric break; 20359f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_TM_FAILED: 20369f63bb73SMoore, Eric desc = "The requested task failed."; 20379f63bb73SMoore, Eric break; 20389f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED: 20399f63bb73SMoore, Eric desc = "The task completed successfully."; 20409f63bb73SMoore, Eric break; 20419f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN: 20429f63bb73SMoore, Eric desc = "The LUN request is invalid."; 20439f63bb73SMoore, Eric break; 20449f63bb73SMoore, Eric case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: 20459f63bb73SMoore, Eric desc = "The task is in the IOC queue and has not been sent to target."; 20469f63bb73SMoore, Eric break; 20479f63bb73SMoore, Eric default: 20489f63bb73SMoore, Eric desc = "unknown"; 20499f63bb73SMoore, Eric break; 20509f63bb73SMoore, Eric } 20519f63bb73SMoore, Eric printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", 20529f63bb73SMoore, Eric ioc->name, response_code, desc); 20539f63bb73SMoore, Eric } 20549f63bb73SMoore, Eric 20559f63bb73SMoore, Eric /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 20561da177e4SLinus Torvalds /** 20571da177e4SLinus Torvalds * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver 20581da177e4SLinus Torvalds * @ioc: Pointer to MPT_ADAPTER structure 20591da177e4SLinus Torvalds * @mf: Pointer to SCSI task mgmt request frame 20601da177e4SLinus Torvalds * @mr: Pointer to SCSI task mgmt reply frame 20611da177e4SLinus Torvalds * 20621da177e4SLinus Torvalds * This routine is called from mptbase.c::mpt_interrupt() at the completion 20631da177e4SLinus Torvalds * of any SCSI task management request. 20641da177e4SLinus Torvalds * This routine is registered with the MPT (base) driver at driver 20651da177e4SLinus Torvalds * load/init time via the mpt_register() API call. 20661da177e4SLinus Torvalds * 20671da177e4SLinus Torvalds * Returns 1 indicating alloc'd request frame ptr should be freed. 2068cd2c6191SEric Moore **/ 20690d0c7974SMoore, Eric Dean int 20701da177e4SLinus Torvalds mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) 20711da177e4SLinus Torvalds { 20721da177e4SLinus Torvalds SCSITaskMgmtReply_t *pScsiTmReply; 20731da177e4SLinus Torvalds SCSITaskMgmt_t *pScsiTmReq; 20741da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 20751da177e4SLinus Torvalds unsigned long flags; 20761da177e4SLinus Torvalds u16 iocstatus; 20771da177e4SLinus Torvalds u8 tmType; 2078cd2c6191SEric Moore u32 termination_count; 20791da177e4SLinus Torvalds 20801da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", 20811da177e4SLinus Torvalds ioc->name, mf, mr)); 2082cd2c6191SEric Moore if (!ioc->sh) { 2083cd2c6191SEric Moore dtmprintk((MYIOC_s_WARN_FMT 2084cd2c6191SEric Moore "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); 20851da177e4SLinus Torvalds return 1; 20861da177e4SLinus Torvalds } 20871da177e4SLinus Torvalds 20881da177e4SLinus Torvalds if (mr == NULL) { 2089cd2c6191SEric Moore dtmprintk((MYIOC_s_WARN_FMT 2090cd2c6191SEric Moore "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); 20911da177e4SLinus Torvalds return 1; 2092cd2c6191SEric Moore } 2093cd2c6191SEric Moore 2094cd2c6191SEric Moore hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; 20951da177e4SLinus Torvalds pScsiTmReply = (SCSITaskMgmtReply_t*)mr; 20961da177e4SLinus Torvalds pScsiTmReq = (SCSITaskMgmt_t*)mf; 20971da177e4SLinus Torvalds tmType = pScsiTmReq->TaskType; 2098cd2c6191SEric Moore iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; 2099cd2c6191SEric Moore termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); 21001da177e4SLinus Torvalds 21019f63bb73SMoore, Eric if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && 21029f63bb73SMoore, Eric pScsiTmReply->ResponseCode) 21039f63bb73SMoore, Eric mptscsih_taskmgmt_response_code(ioc, 21049f63bb73SMoore, Eric pScsiTmReply->ResponseCode); 21051da177e4SLinus Torvalds DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); 21061da177e4SLinus Torvalds 2107cd2c6191SEric Moore #if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM) 2108cd2c6191SEric Moore printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " 2109cd2c6191SEric Moore "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " 2110cd2c6191SEric Moore "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus, 2111cd2c6191SEric Moore pScsiTmReply->TargetID, pScsiTmReq->TaskType, 2112cd2c6191SEric Moore le16_to_cpu(pScsiTmReply->IOCStatus), 2113cd2c6191SEric Moore le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, 2114cd2c6191SEric Moore le32_to_cpu(pScsiTmReply->TerminationCount)); 2115cd2c6191SEric Moore #endif 2116cd2c6191SEric Moore if (!iocstatus) { 2117cd2c6191SEric Moore dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); 2118cd2c6191SEric Moore hd->abortSCpnt = NULL; 2119cd2c6191SEric Moore goto out; 2120cd2c6191SEric Moore } 2121cd2c6191SEric Moore 21221da177e4SLinus Torvalds /* Error? (anything non-zero?) */ 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds /* clear flags and continue. 21251da177e4SLinus Torvalds */ 2126cd2c6191SEric Moore switch (tmType) { 2127cd2c6191SEric Moore 2128cd2c6191SEric Moore case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: 2129cd2c6191SEric Moore if (termination_count == 1) 2130cd2c6191SEric Moore iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED; 21311da177e4SLinus Torvalds hd->abortSCpnt = NULL; 2132cd2c6191SEric Moore break; 2133cd2c6191SEric Moore 2134cd2c6191SEric Moore case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: 21351da177e4SLinus Torvalds 21361da177e4SLinus Torvalds /* If an internal command is present 21371da177e4SLinus Torvalds * or the TM failed - reload the FW. 21381da177e4SLinus Torvalds * FC FW may respond FAILED to an ABORT 21391da177e4SLinus Torvalds */ 2140cd2c6191SEric Moore if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || 2141cd2c6191SEric Moore hd->cmdPtr) 2142cd2c6191SEric Moore if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) 2143cd2c6191SEric Moore printk((KERN_WARNING " Firmware Reload FAILED!!\n")); 2144cd2c6191SEric Moore break; 21451da177e4SLinus Torvalds 2146cd2c6191SEric Moore case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: 2147cd2c6191SEric Moore default: 2148cd2c6191SEric Moore break; 21491da177e4SLinus Torvalds } 21501da177e4SLinus Torvalds 2151cd2c6191SEric Moore out: 21521da177e4SLinus Torvalds spin_lock_irqsave(&ioc->FreeQlock, flags); 21531da177e4SLinus Torvalds hd->tmPending = 0; 21541da177e4SLinus Torvalds hd->tmState = TM_STATE_NONE; 2155cd2c6191SEric Moore hd->tm_iocstatus = iocstatus; 2156cd2c6191SEric Moore spin_unlock_irqrestore(&ioc->FreeQlock, flags); 21571da177e4SLinus Torvalds 21581da177e4SLinus Torvalds return 1; 21591da177e4SLinus Torvalds } 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 21621da177e4SLinus Torvalds /* 21631da177e4SLinus Torvalds * This is anyones guess quite frankly. 21641da177e4SLinus Torvalds */ 21650d0c7974SMoore, Eric Dean int 21661da177e4SLinus Torvalds mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, 21671da177e4SLinus Torvalds sector_t capacity, int geom[]) 21681da177e4SLinus Torvalds { 21691da177e4SLinus Torvalds int heads; 21701da177e4SLinus Torvalds int sectors; 21711da177e4SLinus Torvalds sector_t cylinders; 21721da177e4SLinus Torvalds ulong dummy; 21731da177e4SLinus Torvalds 21741da177e4SLinus Torvalds heads = 64; 21751da177e4SLinus Torvalds sectors = 32; 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds dummy = heads * sectors; 21781da177e4SLinus Torvalds cylinders = capacity; 21791da177e4SLinus Torvalds sector_div(cylinders,dummy); 21801da177e4SLinus Torvalds 21811da177e4SLinus Torvalds /* 21821da177e4SLinus Torvalds * Handle extended translation size for logical drives 21831da177e4SLinus Torvalds * > 1Gb 21841da177e4SLinus Torvalds */ 21851da177e4SLinus Torvalds if ((ulong)capacity >= 0x200000) { 21861da177e4SLinus Torvalds heads = 255; 21871da177e4SLinus Torvalds sectors = 63; 21881da177e4SLinus Torvalds dummy = heads * sectors; 21891da177e4SLinus Torvalds cylinders = capacity; 21901da177e4SLinus Torvalds sector_div(cylinders,dummy); 21911da177e4SLinus Torvalds } 21921da177e4SLinus Torvalds 21931da177e4SLinus Torvalds /* return result */ 21941da177e4SLinus Torvalds geom[0] = heads; 21951da177e4SLinus Torvalds geom[1] = sectors; 21961da177e4SLinus Torvalds geom[2] = cylinders; 21971da177e4SLinus Torvalds 21981da177e4SLinus Torvalds dprintk((KERN_NOTICE 21991da177e4SLinus Torvalds ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n", 22001da177e4SLinus Torvalds sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors)); 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds return 0; 22031da177e4SLinus Torvalds } 22041da177e4SLinus Torvalds 2205f44e5461SMoore, Eric /* Search IOC page 3 to determine if this is hidden physical disk 2206f44e5461SMoore, Eric * 2207f44e5461SMoore, Eric */ 2208f44e5461SMoore, Eric int 2209793955f5SEric Moore mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) 2210f44e5461SMoore, Eric { 2211b506ade9SEric Moore struct inactive_raid_component_info *component_info; 2212f44e5461SMoore, Eric int i; 2213793955f5SEric Moore int rc = 0; 2214f44e5461SMoore, Eric 2215793955f5SEric Moore if (!ioc->raid_data.pIocPg3) 2216793955f5SEric Moore goto out; 2217f44e5461SMoore, Eric for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { 2218793955f5SEric Moore if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && 2219793955f5SEric Moore (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { 2220793955f5SEric Moore rc = 1; 2221793955f5SEric Moore goto out; 2222f44e5461SMoore, Eric } 2223793955f5SEric Moore } 2224793955f5SEric Moore 2225b506ade9SEric Moore /* 2226b506ade9SEric Moore * Check inactive list for matching phys disks 2227b506ade9SEric Moore */ 2228b506ade9SEric Moore if (list_empty(&ioc->raid_data.inactive_list)) 2229b506ade9SEric Moore goto out; 2230b506ade9SEric Moore 2231b506ade9SEric Moore down(&ioc->raid_data.inactive_list_mutex); 2232b506ade9SEric Moore list_for_each_entry(component_info, &ioc->raid_data.inactive_list, 2233b506ade9SEric Moore list) { 2234b506ade9SEric Moore if ((component_info->d.PhysDiskID == id) && 2235b506ade9SEric Moore (component_info->d.PhysDiskBus == channel)) 2236b506ade9SEric Moore rc = 1; 2237b506ade9SEric Moore } 2238b506ade9SEric Moore up(&ioc->raid_data.inactive_list_mutex); 2239b506ade9SEric Moore 2240793955f5SEric Moore out: 2241793955f5SEric Moore return rc; 2242f44e5461SMoore, Eric } 2243f44e5461SMoore, Eric EXPORT_SYMBOL(mptscsih_is_phys_disk); 2244f44e5461SMoore, Eric 2245793955f5SEric Moore u8 2246793955f5SEric Moore mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) 2247c92f222eSJames Bottomley { 2248b506ade9SEric Moore struct inactive_raid_component_info *component_info; 2249c92f222eSJames Bottomley int i; 2250793955f5SEric Moore int rc = -ENXIO; 2251c92f222eSJames Bottomley 2252793955f5SEric Moore if (!ioc->raid_data.pIocPg3) 2253793955f5SEric Moore goto out; 2254793955f5SEric Moore for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { 2255793955f5SEric Moore if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && 2256793955f5SEric Moore (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { 2257793955f5SEric Moore rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; 2258793955f5SEric Moore goto out; 2259793955f5SEric Moore } 2260c92f222eSJames Bottomley } 2261c92f222eSJames Bottomley 2262b506ade9SEric Moore /* 2263b506ade9SEric Moore * Check inactive list for matching phys disks 2264b506ade9SEric Moore */ 2265b506ade9SEric Moore if (list_empty(&ioc->raid_data.inactive_list)) 2266b506ade9SEric Moore goto out; 2267b506ade9SEric Moore 2268b506ade9SEric Moore down(&ioc->raid_data.inactive_list_mutex); 2269b506ade9SEric Moore list_for_each_entry(component_info, &ioc->raid_data.inactive_list, 2270b506ade9SEric Moore list) { 2271b506ade9SEric Moore if ((component_info->d.PhysDiskID == id) && 2272b506ade9SEric Moore (component_info->d.PhysDiskBus == channel)) 2273b506ade9SEric Moore rc = component_info->d.PhysDiskNum; 2274b506ade9SEric Moore } 2275b506ade9SEric Moore up(&ioc->raid_data.inactive_list_mutex); 2276b506ade9SEric Moore 2277793955f5SEric Moore out: 2278793955f5SEric Moore return rc; 2279c92f222eSJames Bottomley } 2280c92f222eSJames Bottomley EXPORT_SYMBOL(mptscsih_raid_id_to_num); 2281c92f222eSJames Bottomley 2282c7c82987SMoore, Eric Dean /* 2283c7c82987SMoore, Eric Dean * OS entry point to allow for host driver to free allocated memory 2284c7c82987SMoore, Eric Dean * Called if no device present or device being unloaded 2285c7c82987SMoore, Eric Dean */ 2286c7c82987SMoore, Eric Dean void 2287c7c82987SMoore, Eric Dean mptscsih_slave_destroy(struct scsi_device *sdev) 2288c7c82987SMoore, Eric Dean { 2289c7c82987SMoore, Eric Dean struct Scsi_Host *host = sdev->host; 22901da177e4SLinus Torvalds MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; 2291c7c82987SMoore, Eric Dean VirtTarget *vtarget; 2292c7c82987SMoore, Eric Dean VirtDevice *vdevice; 2293c7c82987SMoore, Eric Dean struct scsi_target *starget; 22941da177e4SLinus Torvalds 2295c7c82987SMoore, Eric Dean starget = scsi_target(sdev); 2296c7c82987SMoore, Eric Dean vtarget = starget->hostdata; 2297c7c82987SMoore, Eric Dean vdevice = sdev->hostdata; 22981da177e4SLinus Torvalds 2299c7c82987SMoore, Eric Dean mptscsih_search_running_cmds(hd, vdevice); 2300c7c82987SMoore, Eric Dean vtarget->num_luns--; 2301c7c82987SMoore, Eric Dean mptscsih_synchronize_cache(hd, vdevice); 2302c7c82987SMoore, Eric Dean kfree(vdevice); 2303c7c82987SMoore, Eric Dean sdev->hostdata = NULL; 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 23066e3815baSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 23076e3815baSMoore, Eric Dean /* 23086e3815baSMoore, Eric Dean * mptscsih_change_queue_depth - This function will set a devices queue depth 23096e3815baSMoore, Eric Dean * @sdev: per scsi_device pointer 23106e3815baSMoore, Eric Dean * @qdepth: requested queue depth 23116e3815baSMoore, Eric Dean * 23126e3815baSMoore, Eric Dean * Adding support for new 'change_queue_depth' api. 23136e3815baSMoore, Eric Dean */ 23146e3815baSMoore, Eric Dean int 23156e3815baSMoore, Eric Dean mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) 23161da177e4SLinus Torvalds { 23176e3815baSMoore, Eric Dean MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; 2318c7c82987SMoore, Eric Dean VirtTarget *vtarget; 2319c7c82987SMoore, Eric Dean struct scsi_target *starget; 23201da177e4SLinus Torvalds int max_depth; 23211da177e4SLinus Torvalds int tagged; 23221da177e4SLinus Torvalds 2323c7c82987SMoore, Eric Dean starget = scsi_target(sdev); 2324c7c82987SMoore, Eric Dean vtarget = starget->hostdata; 23256e3815baSMoore, Eric Dean 2326a9b2937aSMoore, Eric Dean if (hd->ioc->bus_type == SPI) { 2327c7c82987SMoore, Eric Dean if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) 23281da177e4SLinus Torvalds max_depth = 1; 2329c92f222eSJames Bottomley else if (sdev->type == TYPE_DISK && 2330c92f222eSJames Bottomley vtarget->minSyncFactor <= MPT_ULTRA160) 23311da177e4SLinus Torvalds max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; 23321da177e4SLinus Torvalds else 23331da177e4SLinus Torvalds max_depth = MPT_SCSI_CMD_PER_DEV_LOW; 23341da177e4SLinus Torvalds } else 23351da177e4SLinus Torvalds max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds if (qdepth > max_depth) 23381da177e4SLinus Torvalds qdepth = max_depth; 23391da177e4SLinus Torvalds if (qdepth == 1) 23401da177e4SLinus Torvalds tagged = 0; 23411da177e4SLinus Torvalds else 23421da177e4SLinus Torvalds tagged = MSG_SIMPLE_TAG; 23431da177e4SLinus Torvalds 23446e3815baSMoore, Eric Dean scsi_adjust_queue_depth(sdev, tagged, qdepth); 23456e3815baSMoore, Eric Dean return sdev->queue_depth; 23461da177e4SLinus Torvalds } 23471da177e4SLinus Torvalds 23481da177e4SLinus Torvalds /* 23491da177e4SLinus Torvalds * OS entry point to adjust the queue_depths on a per-device basis. 23501da177e4SLinus Torvalds * Called once per device the bus scan. Use it to force the queue_depth 23511da177e4SLinus Torvalds * member to 1 if a device does not support Q tags. 23521da177e4SLinus Torvalds * Return non-zero if fails. 23531da177e4SLinus Torvalds */ 23540d0c7974SMoore, Eric Dean int 2355c7c82987SMoore, Eric Dean mptscsih_slave_configure(struct scsi_device *sdev) 23561da177e4SLinus Torvalds { 2357c7c82987SMoore, Eric Dean struct Scsi_Host *sh = sdev->host; 2358c7c82987SMoore, Eric Dean VirtTarget *vtarget; 2359c7c82987SMoore, Eric Dean VirtDevice *vdevice; 2360c7c82987SMoore, Eric Dean struct scsi_target *starget; 23611da177e4SLinus Torvalds MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; 23621da177e4SLinus Torvalds 2363c7c82987SMoore, Eric Dean starget = scsi_target(sdev); 2364c7c82987SMoore, Eric Dean vtarget = starget->hostdata; 2365c7c82987SMoore, Eric Dean vdevice = sdev->hostdata; 23661da177e4SLinus Torvalds 23671da177e4SLinus Torvalds dsprintk((MYIOC_s_INFO_FMT 2368793955f5SEric Moore "device @ %p, channel=%d, id=%d, lun=%d\n", 2369793955f5SEric Moore hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun)); 2370c7c82987SMoore, Eric Dean if (hd->ioc->bus_type == SPI) 23711da177e4SLinus Torvalds dsprintk((MYIOC_s_INFO_FMT 23721da177e4SLinus Torvalds "sdtr %d wdtr %d ppr %d inq length=%d\n", 2373c7c82987SMoore, Eric Dean hd->ioc->name, sdev->sdtr, sdev->wdtr, 2374c7c82987SMoore, Eric Dean sdev->ppr, sdev->inquiry_len)); 23751da177e4SLinus Torvalds 2376c7c82987SMoore, Eric Dean if (sdev->id > sh->max_id) { 23771da177e4SLinus Torvalds /* error case, should never happen */ 2378c7c82987SMoore, Eric Dean scsi_adjust_queue_depth(sdev, 0, 1); 23791da177e4SLinus Torvalds goto slave_configure_exit; 23801da177e4SLinus Torvalds } 23811da177e4SLinus Torvalds 2382c7c82987SMoore, Eric Dean vdevice->configured_lun = 1; 2383c7c82987SMoore, Eric Dean mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); 23841da177e4SLinus Torvalds 23851da177e4SLinus Torvalds dsprintk((MYIOC_s_INFO_FMT 23861da177e4SLinus Torvalds "Queue depth=%d, tflags=%x\n", 2387c7c82987SMoore, Eric Dean hd->ioc->name, sdev->queue_depth, vtarget->tflags)); 23881da177e4SLinus Torvalds 2389c7c82987SMoore, Eric Dean if (hd->ioc->bus_type == SPI) 23901da177e4SLinus Torvalds dsprintk((MYIOC_s_INFO_FMT 23911da177e4SLinus Torvalds "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", 2392c7c82987SMoore, Eric Dean hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset, 2393c7c82987SMoore, Eric Dean vtarget->minSyncFactor)); 23941da177e4SLinus Torvalds 23951da177e4SLinus Torvalds slave_configure_exit: 23961da177e4SLinus Torvalds 23971da177e4SLinus Torvalds dsprintk((MYIOC_s_INFO_FMT 23981da177e4SLinus Torvalds "tagged %d, simple %d, ordered %d\n", 2399c7c82987SMoore, Eric Dean hd->ioc->name,sdev->tagged_supported, sdev->simple_tags, 2400c7c82987SMoore, Eric Dean sdev->ordered_tags)); 24011da177e4SLinus Torvalds 24021da177e4SLinus Torvalds return 0; 24031da177e4SLinus Torvalds } 24041da177e4SLinus Torvalds 24051da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 24061da177e4SLinus Torvalds /* 24071da177e4SLinus Torvalds * Private routines... 24081da177e4SLinus Torvalds */ 24091da177e4SLinus Torvalds 24101da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 24111da177e4SLinus Torvalds /* Utility function to copy sense data from the scsi_cmnd buffer 24121da177e4SLinus Torvalds * to the FC and SCSI target structures. 24131da177e4SLinus Torvalds * 24141da177e4SLinus Torvalds */ 24151da177e4SLinus Torvalds static void 24160d0c7974SMoore, Eric Dean mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) 24171da177e4SLinus Torvalds { 2418c7c82987SMoore, Eric Dean VirtDevice *vdev; 24191da177e4SLinus Torvalds SCSIIORequest_t *pReq; 24201da177e4SLinus Torvalds u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); 24211da177e4SLinus Torvalds 24221da177e4SLinus Torvalds /* Get target structure 24231da177e4SLinus Torvalds */ 24241da177e4SLinus Torvalds pReq = (SCSIIORequest_t *) mf; 2425c7c82987SMoore, Eric Dean vdev = sc->device->hostdata; 24261da177e4SLinus Torvalds 24271da177e4SLinus Torvalds if (sense_count) { 24281da177e4SLinus Torvalds u8 *sense_data; 24291da177e4SLinus Torvalds int req_index; 24301da177e4SLinus Torvalds 24311da177e4SLinus Torvalds /* Copy the sense received into the scsi command block. */ 24321da177e4SLinus Torvalds req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); 24331da177e4SLinus Torvalds sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); 24341da177e4SLinus Torvalds memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); 24351da177e4SLinus Torvalds 24361da177e4SLinus Torvalds /* Log SMART data (asc = 0x5D, non-IM case only) if required. 24371da177e4SLinus Torvalds */ 24381da177e4SLinus Torvalds if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { 2439c7c82987SMoore, Eric Dean if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) { 24401da177e4SLinus Torvalds int idx; 24411da177e4SLinus Torvalds MPT_ADAPTER *ioc = hd->ioc; 24421da177e4SLinus Torvalds 24435b5ef4f6SMoore, Eric idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; 24441da177e4SLinus Torvalds ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE; 24451da177e4SLinus Torvalds ioc->events[idx].eventContext = ioc->eventContext; 24461da177e4SLinus Torvalds 24473d9780b9SDave Jones ioc->events[idx].data[0] = (pReq->LUN[1] << 24) | 24483d9780b9SDave Jones (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) | 24493d9780b9SDave Jones (sc->device->channel << 8) | sc->device->id; 24501da177e4SLinus Torvalds 24513d9780b9SDave Jones ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12]; 24521da177e4SLinus Torvalds 24531da177e4SLinus Torvalds ioc->eventContext++; 2454786899b0SEric Moore if (hd->ioc->pcidev->vendor == 2455786899b0SEric Moore PCI_VENDOR_ID_IBM) { 2456786899b0SEric Moore mptscsih_issue_sep_command(hd->ioc, 2457786899b0SEric Moore vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); 2458786899b0SEric Moore vdev->vtarget->tflags |= 2459786899b0SEric Moore MPT_TARGET_FLAGS_LED_ON; 2460786899b0SEric Moore } 24611da177e4SLinus Torvalds } 24621da177e4SLinus Torvalds } 24631da177e4SLinus Torvalds } else { 24641da177e4SLinus Torvalds dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n", 24651da177e4SLinus Torvalds hd->ioc->name)); 24661da177e4SLinus Torvalds } 24671da177e4SLinus Torvalds } 24681da177e4SLinus Torvalds 24693dc0b03fSEric Moore static int 24701da177e4SLinus Torvalds SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc) 24711da177e4SLinus Torvalds { 24721da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 24731da177e4SLinus Torvalds int i; 24741da177e4SLinus Torvalds 24751da177e4SLinus Torvalds hd = (MPT_SCSI_HOST *) sc->device->host->hostdata; 24761da177e4SLinus Torvalds 24771da177e4SLinus Torvalds for (i = 0; i < hd->ioc->req_depth; i++) { 24781da177e4SLinus Torvalds if (hd->ScsiLookup[i] == sc) { 24791da177e4SLinus Torvalds return i; 24801da177e4SLinus Torvalds } 24811da177e4SLinus Torvalds } 24821da177e4SLinus Torvalds 24831da177e4SLinus Torvalds return -1; 24841da177e4SLinus Torvalds } 24851da177e4SLinus Torvalds 24861da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 24870d0c7974SMoore, Eric Dean int 24881da177e4SLinus Torvalds mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 24891da177e4SLinus Torvalds { 24901da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 24911da177e4SLinus Torvalds unsigned long flags; 2492466544d8SMoore, Eric Dean int ii; 24931da177e4SLinus Torvalds 24941da177e4SLinus Torvalds dtmprintk((KERN_WARNING MYNAM 24951da177e4SLinus Torvalds ": IOC %s_reset routed to SCSI host driver!\n", 24961da177e4SLinus Torvalds reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( 24971da177e4SLinus Torvalds reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); 24981da177e4SLinus Torvalds 24991da177e4SLinus Torvalds /* If a FW reload request arrives after base installed but 25001da177e4SLinus Torvalds * before all scsi hosts have been attached, then an alt_ioc 25011da177e4SLinus Torvalds * may have a NULL sh pointer. 25021da177e4SLinus Torvalds */ 25031da177e4SLinus Torvalds if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) 25041da177e4SLinus Torvalds return 0; 25051da177e4SLinus Torvalds else 25061da177e4SLinus Torvalds hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; 25071da177e4SLinus Torvalds 25081da177e4SLinus Torvalds if (reset_phase == MPT_IOC_SETUP_RESET) { 25091da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name)); 25101da177e4SLinus Torvalds 25111da177e4SLinus Torvalds /* Clean Up: 25121da177e4SLinus Torvalds * 1. Set Hard Reset Pending Flag 25131da177e4SLinus Torvalds * All new commands go to doneQ 25141da177e4SLinus Torvalds */ 25151da177e4SLinus Torvalds hd->resetPending = 1; 25161da177e4SLinus Torvalds 25171da177e4SLinus Torvalds } else if (reset_phase == MPT_IOC_PRE_RESET) { 25181da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name)); 25191da177e4SLinus Torvalds 25201da177e4SLinus Torvalds /* 2. Flush running commands 25211da177e4SLinus Torvalds * Clean ScsiLookup (and associated memory) 25221da177e4SLinus Torvalds * AND clean mytaskQ 25231da177e4SLinus Torvalds */ 25241da177e4SLinus Torvalds 25251da177e4SLinus Torvalds /* 2b. Reply to OS all known outstanding I/O commands. 25261da177e4SLinus Torvalds */ 25271da177e4SLinus Torvalds mptscsih_flush_running_cmds(hd); 25281da177e4SLinus Torvalds 25291da177e4SLinus Torvalds /* 2c. If there was an internal command that 25301da177e4SLinus Torvalds * has not completed, configuration or io request, 25311da177e4SLinus Torvalds * free these resources. 25321da177e4SLinus Torvalds */ 25331da177e4SLinus Torvalds if (hd->cmdPtr) { 25341da177e4SLinus Torvalds del_timer(&hd->timer); 25351da177e4SLinus Torvalds mpt_free_msg_frame(ioc, hd->cmdPtr); 25361da177e4SLinus Torvalds } 25371da177e4SLinus Torvalds 25381da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name)); 25391da177e4SLinus Torvalds 25401da177e4SLinus Torvalds } else { 25411da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name)); 25421da177e4SLinus Torvalds 25431da177e4SLinus Torvalds /* Once a FW reload begins, all new OS commands are 25441da177e4SLinus Torvalds * redirected to the doneQ w/ a reset status. 25451da177e4SLinus Torvalds * Init all control structures. 25461da177e4SLinus Torvalds */ 25471da177e4SLinus Torvalds 25481da177e4SLinus Torvalds /* ScsiLookup initialization 25491da177e4SLinus Torvalds */ 25501da177e4SLinus Torvalds for (ii=0; ii < hd->ioc->req_depth; ii++) 25511da177e4SLinus Torvalds hd->ScsiLookup[ii] = NULL; 25521da177e4SLinus Torvalds 25531da177e4SLinus Torvalds /* 2. Chain Buffer initialization 25541da177e4SLinus Torvalds */ 25551da177e4SLinus Torvalds 2556a9b2937aSMoore, Eric Dean /* 4. Renegotiate to all devices, if SPI 25571da177e4SLinus Torvalds */ 25581da177e4SLinus Torvalds 25591da177e4SLinus Torvalds /* 5. Enable new commands to be posted 25601da177e4SLinus Torvalds */ 25611da177e4SLinus Torvalds spin_lock_irqsave(&ioc->FreeQlock, flags); 25621da177e4SLinus Torvalds hd->tmPending = 0; 25631da177e4SLinus Torvalds spin_unlock_irqrestore(&ioc->FreeQlock, flags); 25641da177e4SLinus Torvalds hd->resetPending = 0; 25651da177e4SLinus Torvalds hd->tmState = TM_STATE_NONE; 25661da177e4SLinus Torvalds 25671da177e4SLinus Torvalds /* 6. If there was an internal command, 25681da177e4SLinus Torvalds * wake this process up. 25691da177e4SLinus Torvalds */ 25701da177e4SLinus Torvalds if (hd->cmdPtr) { 25711da177e4SLinus Torvalds /* 25721da177e4SLinus Torvalds * Wake up the original calling thread 25731da177e4SLinus Torvalds */ 25741da177e4SLinus Torvalds hd->pLocal = &hd->localReply; 25751da177e4SLinus Torvalds hd->pLocal->completion = MPT_SCANDV_DID_RESET; 25760d0c7974SMoore, Eric Dean hd->scandv_wait_done = 1; 25770d0c7974SMoore, Eric Dean wake_up(&hd->scandv_waitq); 25781da177e4SLinus Torvalds hd->cmdPtr = NULL; 25791da177e4SLinus Torvalds } 25801da177e4SLinus Torvalds 25811da177e4SLinus Torvalds dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name)); 25821da177e4SLinus Torvalds 25831da177e4SLinus Torvalds } 25841da177e4SLinus Torvalds 25851da177e4SLinus Torvalds return 1; /* currently means nothing really */ 25861da177e4SLinus Torvalds } 25871da177e4SLinus Torvalds 25881da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 25890d0c7974SMoore, Eric Dean int 25901da177e4SLinus Torvalds mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) 25911da177e4SLinus Torvalds { 25921da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 25931da177e4SLinus Torvalds u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; 25941da177e4SLinus Torvalds 25953a892befSMoore, Eric devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", 25961da177e4SLinus Torvalds ioc->name, event)); 25971da177e4SLinus Torvalds 2598466544d8SMoore, Eric Dean if (ioc->sh == NULL || 2599466544d8SMoore, Eric Dean ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) 2600466544d8SMoore, Eric Dean return 1; 2601466544d8SMoore, Eric Dean 26021da177e4SLinus Torvalds switch (event) { 26031da177e4SLinus Torvalds case MPI_EVENT_UNIT_ATTENTION: /* 03 */ 26041da177e4SLinus Torvalds /* FIXME! */ 26051da177e4SLinus Torvalds break; 26061da177e4SLinus Torvalds case MPI_EVENT_IOC_BUS_RESET: /* 04 */ 26071da177e4SLinus Torvalds case MPI_EVENT_EXT_BUS_RESET: /* 05 */ 2608a9b2937aSMoore, Eric Dean if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1)) 26091da177e4SLinus Torvalds hd->soft_resets++; 26101da177e4SLinus Torvalds break; 26111da177e4SLinus Torvalds case MPI_EVENT_LOGOUT: /* 09 */ 26121da177e4SLinus Torvalds /* FIXME! */ 26131da177e4SLinus Torvalds break; 26141da177e4SLinus Torvalds 261505e8ec17SMichael Reed case MPI_EVENT_RESCAN: /* 06 */ 261605e8ec17SMichael Reed break; 261705e8ec17SMichael Reed 26181da177e4SLinus Torvalds /* 26191da177e4SLinus Torvalds * CHECKME! Don't think we need to do 26201da177e4SLinus Torvalds * anything for these, but... 26211da177e4SLinus Torvalds */ 26221da177e4SLinus Torvalds case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ 26231da177e4SLinus Torvalds case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ 26241da177e4SLinus Torvalds /* 26251da177e4SLinus Torvalds * CHECKME! Falling thru... 26261da177e4SLinus Torvalds */ 26271da177e4SLinus Torvalds break; 26281da177e4SLinus Torvalds 26291da177e4SLinus Torvalds case MPI_EVENT_INTEGRATED_RAID: /* 0B */ 26301da177e4SLinus Torvalds break; 26311da177e4SLinus Torvalds 26321da177e4SLinus Torvalds case MPI_EVENT_NONE: /* 00 */ 26331da177e4SLinus Torvalds case MPI_EVENT_LOG_DATA: /* 01 */ 26341da177e4SLinus Torvalds case MPI_EVENT_STATE_CHANGE: /* 02 */ 26351da177e4SLinus Torvalds case MPI_EVENT_EVENT_CHANGE: /* 0A */ 26361da177e4SLinus Torvalds default: 26371da177e4SLinus Torvalds dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event)); 26381da177e4SLinus Torvalds break; 26391da177e4SLinus Torvalds } 26401da177e4SLinus Torvalds 26411da177e4SLinus Torvalds return 1; /* currently means nothing really */ 26421da177e4SLinus Torvalds } 26431da177e4SLinus Torvalds 26441da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 26451da177e4SLinus Torvalds /* 26461da177e4SLinus Torvalds * Bus Scan and Domain Validation functionality ... 26471da177e4SLinus Torvalds */ 26481da177e4SLinus Torvalds 26491da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 26501da177e4SLinus Torvalds /* 26511da177e4SLinus Torvalds * mptscsih_scandv_complete - Scan and DV callback routine registered 26521da177e4SLinus Torvalds * to Fustion MPT (base) driver. 26531da177e4SLinus Torvalds * 26541da177e4SLinus Torvalds * @ioc: Pointer to MPT_ADAPTER structure 26551da177e4SLinus Torvalds * @mf: Pointer to original MPT request frame 26561da177e4SLinus Torvalds * @mr: Pointer to MPT reply frame (NULL if TurboReply) 26571da177e4SLinus Torvalds * 26581da177e4SLinus Torvalds * This routine is called from mpt.c::mpt_interrupt() at the completion 26591da177e4SLinus Torvalds * of any SCSI IO request. 26601da177e4SLinus Torvalds * This routine is registered with the Fusion MPT (base) driver at driver 26611da177e4SLinus Torvalds * load/init time via the mpt_register() API call. 26621da177e4SLinus Torvalds * 26631da177e4SLinus Torvalds * Returns 1 indicating alloc'd request frame ptr should be freed. 26641da177e4SLinus Torvalds * 26651da177e4SLinus Torvalds * Remark: Sets a completion code and (possibly) saves sense data 26661da177e4SLinus Torvalds * in the IOC member localReply structure. 26671da177e4SLinus Torvalds * Used ONLY for DV and other internal commands. 26681da177e4SLinus Torvalds */ 26690d0c7974SMoore, Eric Dean int 26701da177e4SLinus Torvalds mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) 26711da177e4SLinus Torvalds { 26721da177e4SLinus Torvalds MPT_SCSI_HOST *hd; 26731da177e4SLinus Torvalds SCSIIORequest_t *pReq; 26741da177e4SLinus Torvalds int completionCode; 26751da177e4SLinus Torvalds u16 req_idx; 26761da177e4SLinus Torvalds 26770d0c7974SMoore, Eric Dean hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; 26780d0c7974SMoore, Eric Dean 26791da177e4SLinus Torvalds if ((mf == NULL) || 26801da177e4SLinus Torvalds (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { 26811da177e4SLinus Torvalds printk(MYIOC_s_ERR_FMT 26821da177e4SLinus Torvalds "ScanDvComplete, %s req frame ptr! (=%p)\n", 26831da177e4SLinus Torvalds ioc->name, mf?"BAD":"NULL", (void *) mf); 26841da177e4SLinus Torvalds goto wakeup; 26851da177e4SLinus Torvalds } 26861da177e4SLinus Torvalds 26871da177e4SLinus Torvalds del_timer(&hd->timer); 26881da177e4SLinus Torvalds req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); 26891da177e4SLinus Torvalds hd->ScsiLookup[req_idx] = NULL; 26901da177e4SLinus Torvalds pReq = (SCSIIORequest_t *) mf; 26911da177e4SLinus Torvalds 26921da177e4SLinus Torvalds if (mf != hd->cmdPtr) { 26931da177e4SLinus Torvalds printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", 26941da177e4SLinus Torvalds hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); 26951da177e4SLinus Torvalds } 26961da177e4SLinus Torvalds hd->cmdPtr = NULL; 26971da177e4SLinus Torvalds 26981da177e4SLinus Torvalds ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", 26991da177e4SLinus Torvalds hd->ioc->name, mf, mr, req_idx)); 27001da177e4SLinus Torvalds 27011da177e4SLinus Torvalds hd->pLocal = &hd->localReply; 27021da177e4SLinus Torvalds hd->pLocal->scsiStatus = 0; 27031da177e4SLinus Torvalds 27041da177e4SLinus Torvalds /* If target struct exists, clear sense valid flag. 27051da177e4SLinus Torvalds */ 27061da177e4SLinus Torvalds if (mr == NULL) { 27071da177e4SLinus Torvalds completionCode = MPT_SCANDV_GOOD; 27081da177e4SLinus Torvalds } else { 27091da177e4SLinus Torvalds SCSIIOReply_t *pReply; 27101da177e4SLinus Torvalds u16 status; 27111da177e4SLinus Torvalds u8 scsi_status; 27121da177e4SLinus Torvalds 27131da177e4SLinus Torvalds pReply = (SCSIIOReply_t *) mr; 27141da177e4SLinus Torvalds 27151da177e4SLinus Torvalds status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; 27161da177e4SLinus Torvalds scsi_status = pReply->SCSIStatus; 27171da177e4SLinus Torvalds 27181da177e4SLinus Torvalds ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", 27191da177e4SLinus Torvalds status, pReply->SCSIState, scsi_status, 27201da177e4SLinus Torvalds le32_to_cpu(pReply->IOCLogInfo))); 27211da177e4SLinus Torvalds 27221da177e4SLinus Torvalds switch(status) { 27231da177e4SLinus Torvalds 27241da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ 27251da177e4SLinus Torvalds completionCode = MPT_SCANDV_SELECTION_TIMEOUT; 27261da177e4SLinus Torvalds break; 27271da177e4SLinus Torvalds 27281da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ 27291da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ 27301da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ 27311da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ 27321da177e4SLinus Torvalds completionCode = MPT_SCANDV_DID_RESET; 27331da177e4SLinus Torvalds break; 27341da177e4SLinus Torvalds 27351da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ 27361da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ 27371da177e4SLinus Torvalds case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ 27381da177e4SLinus Torvalds if (pReply->Function == MPI_FUNCTION_CONFIG) { 27391da177e4SLinus Torvalds ConfigReply_t *pr = (ConfigReply_t *)mr; 27401da177e4SLinus Torvalds completionCode = MPT_SCANDV_GOOD; 27411da177e4SLinus Torvalds hd->pLocal->header.PageVersion = pr->Header.PageVersion; 27421da177e4SLinus Torvalds hd->pLocal->header.PageLength = pr->Header.PageLength; 27431da177e4SLinus Torvalds hd->pLocal->header.PageNumber = pr->Header.PageNumber; 27441da177e4SLinus Torvalds hd->pLocal->header.PageType = pr->Header.PageType; 27451da177e4SLinus Torvalds 27461da177e4SLinus Torvalds } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { 27471da177e4SLinus Torvalds /* If the RAID Volume request is successful, 27481da177e4SLinus Torvalds * return GOOD, else indicate that 27491da177e4SLinus Torvalds * some type of error occurred. 27501da177e4SLinus Torvalds */ 27511da177e4SLinus Torvalds MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; 2752637fa99bSChristoph Hellwig if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) 27531da177e4SLinus Torvalds completionCode = MPT_SCANDV_GOOD; 27541da177e4SLinus Torvalds else 27551da177e4SLinus Torvalds completionCode = MPT_SCANDV_SOME_ERROR; 2756c92f222eSJames Bottomley memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense)); 27571da177e4SLinus Torvalds 27581da177e4SLinus Torvalds } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { 27591da177e4SLinus Torvalds u8 *sense_data; 27601da177e4SLinus Torvalds int sz; 27611da177e4SLinus Torvalds 27621da177e4SLinus Torvalds /* save sense data in global structure 27631da177e4SLinus Torvalds */ 27641da177e4SLinus Torvalds completionCode = MPT_SCANDV_SENSE; 27651da177e4SLinus Torvalds hd->pLocal->scsiStatus = scsi_status; 27661da177e4SLinus Torvalds sense_data = ((u8 *)hd->ioc->sense_buf_pool + 27671da177e4SLinus Torvalds (req_idx * MPT_SENSE_BUFFER_ALLOC)); 27681da177e4SLinus Torvalds 27691da177e4SLinus Torvalds sz = min_t(int, pReq->SenseBufferLength, 27701da177e4SLinus Torvalds SCSI_STD_SENSE_BYTES); 27711da177e4SLinus Torvalds memcpy(hd->pLocal->sense, sense_data, sz); 27721da177e4SLinus Torvalds 27731da177e4SLinus Torvalds ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n", 27741da177e4SLinus Torvalds sense_data)); 27751da177e4SLinus Torvalds } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { 27761da177e4SLinus Torvalds if (pReq->CDB[0] == INQUIRY) 27771da177e4SLinus Torvalds completionCode = MPT_SCANDV_ISSUE_SENSE; 27781da177e4SLinus Torvalds else 27791da177e4SLinus Torvalds completionCode = MPT_SCANDV_DID_RESET; 27801da177e4SLinus Torvalds } 27811da177e4SLinus Torvalds else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) 27821da177e4SLinus Torvalds completionCode = MPT_SCANDV_DID_RESET; 27831da177e4SLinus Torvalds else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) 27841da177e4SLinus Torvalds completionCode = MPT_SCANDV_DID_RESET; 27851da177e4SLinus Torvalds else { 27861da177e4SLinus Torvalds completionCode = MPT_SCANDV_GOOD; 27871da177e4SLinus Torvalds hd->pLocal->scsiStatus = scsi_status; 27881da177e4SLinus Torvalds } 27891da177e4SLinus Torvalds break; 27901da177e4SLinus Torvalds 27911da177e4SLinus Torvalds case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ 27921da177e4SLinus Torvalds if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) 27931da177e4SLinus Torvalds completionCode = MPT_SCANDV_DID_RESET; 27941da177e4SLinus Torvalds else 27951da177e4SLinus Torvalds completionCode = MPT_SCANDV_SOME_ERROR; 27961da177e4SLinus Torvalds break; 27971da177e4SLinus Torvalds 27981da177e4SLinus Torvalds default: 27991da177e4SLinus Torvalds completionCode = MPT_SCANDV_SOME_ERROR; 28001da177e4SLinus Torvalds break; 28011da177e4SLinus Torvalds 28021da177e4SLinus Torvalds } /* switch(status) */ 28031da177e4SLinus Torvalds 28041da177e4SLinus Torvalds ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n", 28051da177e4SLinus Torvalds completionCode)); 28061da177e4SLinus Torvalds } /* end of address reply case */ 28071da177e4SLinus Torvalds 28081da177e4SLinus Torvalds hd->pLocal->completion = completionCode; 28091da177e4SLinus Torvalds 28101da177e4SLinus Torvalds /* MF and RF are freed in mpt_interrupt 28111da177e4SLinus Torvalds */ 28121da177e4SLinus Torvalds wakeup: 28131da177e4SLinus Torvalds /* Free Chain buffers (will never chain) in scan or dv */ 28141da177e4SLinus Torvalds //mptscsih_freeChainBuffers(ioc, req_idx); 28151da177e4SLinus Torvalds 28161da177e4SLinus Torvalds /* 28171da177e4SLinus Torvalds * Wake up the original calling thread 28181da177e4SLinus Torvalds */ 28190d0c7974SMoore, Eric Dean hd->scandv_wait_done = 1; 28200d0c7974SMoore, Eric Dean wake_up(&hd->scandv_waitq); 28211da177e4SLinus Torvalds 28221da177e4SLinus Torvalds return 1; 28231da177e4SLinus Torvalds } 28241da177e4SLinus Torvalds 28251da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 28261da177e4SLinus Torvalds /* mptscsih_timer_expired - Call back for timer process. 28271da177e4SLinus Torvalds * Used only for dv functionality. 28281da177e4SLinus Torvalds * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long 28291da177e4SLinus Torvalds * 28301da177e4SLinus Torvalds */ 28310d0c7974SMoore, Eric Dean void 28320d0c7974SMoore, Eric Dean mptscsih_timer_expired(unsigned long data) 28331da177e4SLinus Torvalds { 28341da177e4SLinus Torvalds MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; 28351da177e4SLinus Torvalds 28361da177e4SLinus Torvalds ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr)); 28371da177e4SLinus Torvalds 28381da177e4SLinus Torvalds if (hd->cmdPtr) { 28391da177e4SLinus Torvalds MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; 28401da177e4SLinus Torvalds 28411da177e4SLinus Torvalds if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { 28421da177e4SLinus Torvalds /* Desire to issue a task management request here. 28431da177e4SLinus Torvalds * TM requests MUST be single threaded. 28441da177e4SLinus Torvalds * If old eh code and no TM current, issue request. 28451da177e4SLinus Torvalds * If new eh code, do nothing. Wait for OS cmd timeout 28461da177e4SLinus Torvalds * for bus reset. 28471da177e4SLinus Torvalds */ 28481da177e4SLinus Torvalds ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name)); 28491da177e4SLinus Torvalds } else { 28501da177e4SLinus Torvalds /* Perform a FW reload */ 28511da177e4SLinus Torvalds if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) { 28521da177e4SLinus Torvalds printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name); 28531da177e4SLinus Torvalds } 28541da177e4SLinus Torvalds } 28551da177e4SLinus Torvalds } else { 28561da177e4SLinus Torvalds /* This should NEVER happen */ 28571da177e4SLinus Torvalds printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name); 28581da177e4SLinus Torvalds } 28591da177e4SLinus Torvalds 28601da177e4SLinus Torvalds /* No more processing. 28611da177e4SLinus Torvalds * TM call will generate an interrupt for SCSI TM Management. 28621da177e4SLinus Torvalds * The FW will reply to all outstanding commands, callback will finish cleanup. 28631da177e4SLinus Torvalds * Hard reset clean-up will free all resources. 28641da177e4SLinus Torvalds */ 28651da177e4SLinus Torvalds ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name)); 28661da177e4SLinus Torvalds 28671da177e4SLinus Torvalds return; 28681da177e4SLinus Torvalds } 28691da177e4SLinus Torvalds 28701da177e4SLinus Torvalds 28711da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 28721da177e4SLinus Torvalds /** 28731da177e4SLinus Torvalds * mptscsih_do_cmd - Do internal command. 28741da177e4SLinus Torvalds * @hd: MPT_SCSI_HOST pointer 28751da177e4SLinus Torvalds * @io: INTERNAL_CMD pointer. 28761da177e4SLinus Torvalds * 28771da177e4SLinus Torvalds * Issue the specified internally generated command and do command 28781da177e4SLinus Torvalds * specific cleanup. For bus scan / DV only. 28791da177e4SLinus Torvalds * NOTES: If command is Inquiry and status is good, 28801da177e4SLinus Torvalds * initialize a target structure, save the data 28811da177e4SLinus Torvalds * 28821da177e4SLinus Torvalds * Remark: Single threaded access only. 28831da177e4SLinus Torvalds * 28841da177e4SLinus Torvalds * Return: 28851da177e4SLinus Torvalds * < 0 if an illegal command or no resources 28861da177e4SLinus Torvalds * 28871da177e4SLinus Torvalds * 0 if good 28881da177e4SLinus Torvalds * 28891da177e4SLinus Torvalds * > 0 if command complete but some type of completion error. 28901da177e4SLinus Torvalds */ 28911da177e4SLinus Torvalds static int 28921da177e4SLinus Torvalds mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) 28931da177e4SLinus Torvalds { 28941da177e4SLinus Torvalds MPT_FRAME_HDR *mf; 28951da177e4SLinus Torvalds SCSIIORequest_t *pScsiReq; 28961da177e4SLinus Torvalds SCSIIORequest_t ReqCopy; 28971da177e4SLinus Torvalds int my_idx, ii, dir; 28981da177e4SLinus Torvalds int rc, cmdTimeout; 28991da177e4SLinus Torvalds int in_isr; 29001da177e4SLinus Torvalds char cmdLen; 29011da177e4SLinus Torvalds char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 29021da177e4SLinus Torvalds char cmd = io->cmd; 29031da177e4SLinus Torvalds 29041da177e4SLinus Torvalds in_isr = in_interrupt(); 29051da177e4SLinus Torvalds if (in_isr) { 29061da177e4SLinus Torvalds dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n", 29071da177e4SLinus Torvalds hd->ioc->name)); 29081da177e4SLinus Torvalds return -EPERM; 29091da177e4SLinus Torvalds } 29101da177e4SLinus Torvalds 29111da177e4SLinus Torvalds 29121da177e4SLinus Torvalds /* Set command specific information 29131da177e4SLinus Torvalds */ 29141da177e4SLinus Torvalds switch (cmd) { 29151da177e4SLinus Torvalds case INQUIRY: 29161da177e4SLinus Torvalds cmdLen = 6; 29171da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29181da177e4SLinus Torvalds CDB[0] = cmd; 29191da177e4SLinus Torvalds CDB[4] = io->size; 29201da177e4SLinus Torvalds cmdTimeout = 10; 29211da177e4SLinus Torvalds break; 29221da177e4SLinus Torvalds 29231da177e4SLinus Torvalds case TEST_UNIT_READY: 29241da177e4SLinus Torvalds cmdLen = 6; 29251da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29261da177e4SLinus Torvalds cmdTimeout = 10; 29271da177e4SLinus Torvalds break; 29281da177e4SLinus Torvalds 29291da177e4SLinus Torvalds case START_STOP: 29301da177e4SLinus Torvalds cmdLen = 6; 29311da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29321da177e4SLinus Torvalds CDB[0] = cmd; 29331da177e4SLinus Torvalds CDB[4] = 1; /*Spin up the disk */ 29341da177e4SLinus Torvalds cmdTimeout = 15; 29351da177e4SLinus Torvalds break; 29361da177e4SLinus Torvalds 29371da177e4SLinus Torvalds case REQUEST_SENSE: 29381da177e4SLinus Torvalds cmdLen = 6; 29391da177e4SLinus Torvalds CDB[0] = cmd; 29401da177e4SLinus Torvalds CDB[4] = io->size; 29411da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29421da177e4SLinus Torvalds cmdTimeout = 10; 29431da177e4SLinus Torvalds break; 29441da177e4SLinus Torvalds 29451da177e4SLinus Torvalds case READ_BUFFER: 29461da177e4SLinus Torvalds cmdLen = 10; 29471da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29481da177e4SLinus Torvalds CDB[0] = cmd; 29491da177e4SLinus Torvalds if (io->flags & MPT_ICFLAG_ECHO) { 29501da177e4SLinus Torvalds CDB[1] = 0x0A; 29511da177e4SLinus Torvalds } else { 29521da177e4SLinus Torvalds CDB[1] = 0x02; 29531da177e4SLinus Torvalds } 29541da177e4SLinus Torvalds 29551da177e4SLinus Torvalds if (io->flags & MPT_ICFLAG_BUF_CAP) { 29561da177e4SLinus Torvalds CDB[1] |= 0x01; 29571da177e4SLinus Torvalds } 29581da177e4SLinus Torvalds CDB[6] = (io->size >> 16) & 0xFF; 29591da177e4SLinus Torvalds CDB[7] = (io->size >> 8) & 0xFF; 29601da177e4SLinus Torvalds CDB[8] = io->size & 0xFF; 29611da177e4SLinus Torvalds cmdTimeout = 10; 29621da177e4SLinus Torvalds break; 29631da177e4SLinus Torvalds 29641da177e4SLinus Torvalds case WRITE_BUFFER: 29651da177e4SLinus Torvalds cmdLen = 10; 29661da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_WRITE; 29671da177e4SLinus Torvalds CDB[0] = cmd; 29681da177e4SLinus Torvalds if (io->flags & MPT_ICFLAG_ECHO) { 29691da177e4SLinus Torvalds CDB[1] = 0x0A; 29701da177e4SLinus Torvalds } else { 29711da177e4SLinus Torvalds CDB[1] = 0x02; 29721da177e4SLinus Torvalds } 29731da177e4SLinus Torvalds CDB[6] = (io->size >> 16) & 0xFF; 29741da177e4SLinus Torvalds CDB[7] = (io->size >> 8) & 0xFF; 29751da177e4SLinus Torvalds CDB[8] = io->size & 0xFF; 29761da177e4SLinus Torvalds cmdTimeout = 10; 29771da177e4SLinus Torvalds break; 29781da177e4SLinus Torvalds 29791da177e4SLinus Torvalds case RESERVE: 29801da177e4SLinus Torvalds cmdLen = 6; 29811da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29821da177e4SLinus Torvalds CDB[0] = cmd; 29831da177e4SLinus Torvalds cmdTimeout = 10; 29841da177e4SLinus Torvalds break; 29851da177e4SLinus Torvalds 29861da177e4SLinus Torvalds case RELEASE: 29871da177e4SLinus Torvalds cmdLen = 6; 29881da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29891da177e4SLinus Torvalds CDB[0] = cmd; 29901da177e4SLinus Torvalds cmdTimeout = 10; 29911da177e4SLinus Torvalds break; 29921da177e4SLinus Torvalds 29931da177e4SLinus Torvalds case SYNCHRONIZE_CACHE: 29941da177e4SLinus Torvalds cmdLen = 10; 29951da177e4SLinus Torvalds dir = MPI_SCSIIO_CONTROL_READ; 29961da177e4SLinus Torvalds CDB[0] = cmd; 29971da177e4SLinus Torvalds // CDB[1] = 0x02; /* set immediate bit */ 29981da177e4SLinus Torvalds cmdTimeout = 10; 29991da177e4SLinus Torvalds break; 30001da177e4SLinus Torvalds 30011da177e4SLinus Torvalds default: 30021da177e4SLinus Torvalds /* Error Case */ 30031da177e4SLinus Torvalds return -EFAULT; 30041da177e4SLinus Torvalds } 30051da177e4SLinus Torvalds 30061da177e4SLinus Torvalds /* Get and Populate a free Frame 30071da177e4SLinus Torvalds */ 30080d0c7974SMoore, Eric Dean if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) { 30091da177e4SLinus Torvalds ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n", 30101da177e4SLinus Torvalds hd->ioc->name)); 30111da177e4SLinus Torvalds return -EBUSY; 30121da177e4SLinus Torvalds } 30131da177e4SLinus Torvalds 30141da177e4SLinus Torvalds pScsiReq = (SCSIIORequest_t *) mf; 30151da177e4SLinus Torvalds 30161da177e4SLinus Torvalds /* Get the request index */ 30171da177e4SLinus Torvalds my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); 30181da177e4SLinus Torvalds ADD_INDEX_LOG(my_idx); /* for debug */ 30191da177e4SLinus Torvalds 30201da177e4SLinus Torvalds if (io->flags & MPT_ICFLAG_PHYS_DISK) { 30211da177e4SLinus Torvalds pScsiReq->TargetID = io->physDiskNum; 30221da177e4SLinus Torvalds pScsiReq->Bus = 0; 30231da177e4SLinus Torvalds pScsiReq->ChainOffset = 0; 30241da177e4SLinus Torvalds pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; 30251da177e4SLinus Torvalds } else { 30261da177e4SLinus Torvalds pScsiReq->TargetID = io->id; 3027793955f5SEric Moore pScsiReq->Bus = io->channel; 30281da177e4SLinus Torvalds pScsiReq->ChainOffset = 0; 30291da177e4SLinus Torvalds pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; 30301da177e4SLinus Torvalds } 30311da177e4SLinus Torvalds 30321da177e4SLinus Torvalds pScsiReq->CDBLength = cmdLen; 30331da177e4SLinus Torvalds pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; 30341da177e4SLinus Torvalds 30351da177e4SLinus Torvalds pScsiReq->Reserved = 0; 30361da177e4SLinus Torvalds 30371da177e4SLinus Torvalds pScsiReq->MsgFlags = mpt_msg_flags(); 30381da177e4SLinus Torvalds /* MsgContext set in mpt_get_msg_fram call */ 30391da177e4SLinus Torvalds 3040793955f5SEric Moore int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN); 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds if (io->flags & MPT_ICFLAG_TAGGED_CMD) 30431da177e4SLinus Torvalds pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ); 30441da177e4SLinus Torvalds else 30451da177e4SLinus Torvalds pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); 30461da177e4SLinus Torvalds 30471da177e4SLinus Torvalds if (cmd == REQUEST_SENSE) { 30481da177e4SLinus Torvalds pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); 30491da177e4SLinus Torvalds ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n", 30501da177e4SLinus Torvalds hd->ioc->name, cmd)); 30511da177e4SLinus Torvalds } 30521da177e4SLinus Torvalds 30531da177e4SLinus Torvalds for (ii=0; ii < 16; ii++) 30541da177e4SLinus Torvalds pScsiReq->CDB[ii] = CDB[ii]; 30551da177e4SLinus Torvalds 30561da177e4SLinus Torvalds pScsiReq->DataLength = cpu_to_le32(io->size); 30571da177e4SLinus Torvalds pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma 30581da177e4SLinus Torvalds + (my_idx * MPT_SENSE_BUFFER_ALLOC)); 30591da177e4SLinus Torvalds 30601da177e4SLinus Torvalds ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n", 3061793955f5SEric Moore hd->ioc->name, cmd, io->channel, io->id, io->lun)); 30621da177e4SLinus Torvalds 30631da177e4SLinus Torvalds if (dir == MPI_SCSIIO_CONTROL_READ) { 30641da177e4SLinus Torvalds mpt_add_sge((char *) &pScsiReq->SGL, 30651da177e4SLinus Torvalds MPT_SGE_FLAGS_SSIMPLE_READ | io->size, 30661da177e4SLinus Torvalds io->data_dma); 30671da177e4SLinus Torvalds } else { 30681da177e4SLinus Torvalds mpt_add_sge((char *) &pScsiReq->SGL, 30691da177e4SLinus Torvalds MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, 30701da177e4SLinus Torvalds io->data_dma); 30711da177e4SLinus Torvalds } 30721da177e4SLinus Torvalds 30731da177e4SLinus Torvalds /* The ISR will free the request frame, but we need 30741da177e4SLinus Torvalds * the information to initialize the target. Duplicate. 30751da177e4SLinus Torvalds */ 30761da177e4SLinus Torvalds memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t)); 30771da177e4SLinus Torvalds 30781da177e4SLinus Torvalds /* Issue this command after: 30791da177e4SLinus Torvalds * finish init 30801da177e4SLinus Torvalds * add timer 30811da177e4SLinus Torvalds * Wait until the reply has been received 30821da177e4SLinus Torvalds * ScsiScanDvCtx callback function will 30831da177e4SLinus Torvalds * set hd->pLocal; 30841da177e4SLinus Torvalds * set scandv_wait_done and call wake_up 30851da177e4SLinus Torvalds */ 30861da177e4SLinus Torvalds hd->pLocal = NULL; 30871da177e4SLinus Torvalds hd->timer.expires = jiffies + HZ*cmdTimeout; 30880d0c7974SMoore, Eric Dean hd->scandv_wait_done = 0; 30891da177e4SLinus Torvalds 30901da177e4SLinus Torvalds /* Save cmd pointer, for resource free if timeout or 30911da177e4SLinus Torvalds * FW reload occurs 30921da177e4SLinus Torvalds */ 30931da177e4SLinus Torvalds hd->cmdPtr = mf; 30941da177e4SLinus Torvalds 30951da177e4SLinus Torvalds add_timer(&hd->timer); 30960d0c7974SMoore, Eric Dean mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf); 30970d0c7974SMoore, Eric Dean wait_event(hd->scandv_waitq, hd->scandv_wait_done); 30981da177e4SLinus Torvalds 30991da177e4SLinus Torvalds if (hd->pLocal) { 31001da177e4SLinus Torvalds rc = hd->pLocal->completion; 31011da177e4SLinus Torvalds hd->pLocal->skip = 0; 31021da177e4SLinus Torvalds 31031da177e4SLinus Torvalds /* Always set fatal error codes in some cases. 31041da177e4SLinus Torvalds */ 31051da177e4SLinus Torvalds if (rc == MPT_SCANDV_SELECTION_TIMEOUT) 31061da177e4SLinus Torvalds rc = -ENXIO; 31071da177e4SLinus Torvalds else if (rc == MPT_SCANDV_SOME_ERROR) 31081da177e4SLinus Torvalds rc = -rc; 31091da177e4SLinus Torvalds } else { 31101da177e4SLinus Torvalds rc = -EFAULT; 31111da177e4SLinus Torvalds /* This should never happen. */ 31121da177e4SLinus Torvalds ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n", 31131da177e4SLinus Torvalds hd->ioc->name)); 31141da177e4SLinus Torvalds } 31151da177e4SLinus Torvalds 31161da177e4SLinus Torvalds return rc; 31171da177e4SLinus Torvalds } 31181da177e4SLinus Torvalds 31191da177e4SLinus Torvalds /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 31201da177e4SLinus Torvalds /** 3121c7c82987SMoore, Eric Dean * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks. 3122c7c82987SMoore, Eric Dean * @hd: Pointer to a SCSI HOST structure 3123d9489fb6SRandy Dunlap * @vdevice: virtual target device 3124c7c82987SMoore, Eric Dean * 3125c7c82987SMoore, Eric Dean * Uses the ISR, but with special processing. 3126c7c82987SMoore, Eric Dean * MUST be single-threaded. 3127c7c82987SMoore, Eric Dean * 3128c7c82987SMoore, Eric Dean */ 3129c7c82987SMoore, Eric Dean static void 3130c7c82987SMoore, Eric Dean mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice) 3131c7c82987SMoore, Eric Dean { 3132c7c82987SMoore, Eric Dean INTERNAL_CMD iocmd; 31331da177e4SLinus Torvalds 31341da177e4SLinus Torvalds /* Following parameters will not change 31351da177e4SLinus Torvalds * in this routine. 31361da177e4SLinus Torvalds */ 31371da177e4SLinus Torvalds iocmd.cmd = SYNCHRONIZE_CACHE; 31381da177e4SLinus Torvalds iocmd.flags = 0; 31391da177e4SLinus Torvalds iocmd.physDiskNum = -1; 31401da177e4SLinus Torvalds iocmd.data = NULL; 31411da177e4SLinus Torvalds iocmd.data_dma = -1; 31421da177e4SLinus Torvalds iocmd.size = 0; 31431da177e4SLinus Torvalds iocmd.rsvd = iocmd.rsvd2 = 0; 3144793955f5SEric Moore iocmd.channel = vdevice->vtarget->channel; 3145793955f5SEric Moore iocmd.id = vdevice->vtarget->id; 3146793955f5SEric Moore iocmd.lun = vdevice->lun; 31471da177e4SLinus Torvalds 3148c92f222eSJames Bottomley if ((vdevice->vtarget->type == TYPE_DISK) && 3149c7c82987SMoore, Eric Dean (vdevice->configured_lun)) 3150c7c82987SMoore, Eric Dean mptscsih_do_cmd(hd, &iocmd); 31511da177e4SLinus Torvalds } 31521da177e4SLinus Torvalds 31530d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_remove); 31540d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_shutdown); 31550d0c7974SMoore, Eric Dean #ifdef CONFIG_PM 31560d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_suspend); 31570d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_resume); 31580d0c7974SMoore, Eric Dean #endif 31590d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_proc_info); 31600d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_info); 31610d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_qcmd); 31620d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_slave_destroy); 31630d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_slave_configure); 31640d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_abort); 31650d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_dev_reset); 31660d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_bus_reset); 31670d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_host_reset); 31680d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_bios_param); 31690d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_io_done); 31700d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_taskmgmt_complete); 31710d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_scandv_complete); 31720d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_event_process); 31730d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_ioc_reset); 31746e3815baSMoore, Eric Dean EXPORT_SYMBOL(mptscsih_change_queue_depth); 31750d0c7974SMoore, Eric Dean EXPORT_SYMBOL(mptscsih_timer_expired); 3176663e1aa1SJames Bottomley EXPORT_SYMBOL(mptscsih_TMHandler); 31771da177e4SLinus Torvalds 31780d0c7974SMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 3179