2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* linux/drivers/message/fusion/mptscsih.c
|
2007-08-14 18:52:54 +08:00
|
|
|
* For use with LSI PCI chip/adapter(s)
|
|
|
|
* running LSI Fusion MPT (Message Passing Technology) firmware.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2008-05-21 03:26:41 +08:00
|
|
|
* Copyright (c) 1999-2008 LSI Corporation
|
2007-06-14 06:31:07 +08:00
|
|
|
* (mailto:DL-MPTFusionLinux@lsi.com)
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
NO WARRANTY
|
|
|
|
THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
|
|
CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
|
|
|
LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
|
|
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
|
|
|
solely responsible for determining the appropriateness of using and
|
|
|
|
distributing the Program and assumes all risks associated with its
|
|
|
|
exercise of rights under this Agreement, including but not limited to
|
|
|
|
the risks and costs of program errors, damage to or loss of data,
|
|
|
|
programs or equipment, and unavailability or interruption of operations.
|
|
|
|
|
|
|
|
DISCLAIMER OF LIABILITY
|
|
|
|
NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
|
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
|
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
|
|
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
|
|
USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
|
|
|
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/kdev_t.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/delay.h> /* for mdelay */
|
|
|
|
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
|
|
|
|
#include <linux/reboot.h> /* notifier code */
|
|
|
|
#include <linux/workqueue.h>
|
|
|
|
|
|
|
|
#include <scsi/scsi.h>
|
|
|
|
#include <scsi/scsi_cmnd.h>
|
|
|
|
#include <scsi/scsi_device.h>
|
|
|
|
#include <scsi/scsi_host.h>
|
|
|
|
#include <scsi/scsi_tcq.h>
|
2005-09-16 03:17:14 +08:00
|
|
|
#include <scsi/scsi_dbg.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include "mptbase.h"
|
|
|
|
#include "mptscsih.h"
|
2006-07-12 07:25:35 +08:00
|
|
|
#include "lsi/mpi_log_sas.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
#define my_NAME "Fusion MPT SCSI Host driver"
|
|
|
|
#define my_VERSION MPT_LINUX_VERSION_COMMON
|
|
|
|
#define MYNAM "mptscsih"
|
|
|
|
|
|
|
|
MODULE_AUTHOR(MODULEAUTHOR);
|
|
|
|
MODULE_DESCRIPTION(my_NAME);
|
|
|
|
MODULE_LICENSE("GPL");
|
2007-01-05 11:47:47 +08:00
|
|
|
MODULE_VERSION(my_VERSION);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* Other private/forward protos...
|
|
|
|
*/
|
2009-05-29 19:26:59 +08:00
|
|
|
struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
|
2007-09-30 00:16:53 +08:00
|
|
|
static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
|
|
|
|
static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
|
|
|
|
static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
|
2005-04-23 06:02:09 +08:00
|
|
|
int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
2005-04-17 06:20:36 +08:00
|
|
|
static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
|
2005-04-23 06:02:09 +08:00
|
|
|
int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
|
|
|
|
SCSIIORequest_t *pReq, int req_idx);
|
|
|
|
static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
|
2005-04-23 06:02:09 +08:00
|
|
|
static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
|
2014-06-25 21:27:36 +08:00
|
|
|
u64 lun, int ctx2abort, ulong timeout);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
|
|
|
|
int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:16:07 +08:00
|
|
|
void
|
2009-05-29 19:14:48 +08:00
|
|
|
mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
|
2009-05-29 19:14:06 +08:00
|
|
|
static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
|
|
|
|
MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
|
2005-04-23 06:02:09 +08:00
|
|
|
int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
2005-04-17 06:20:36 +08:00
|
|
|
static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
|
2005-11-17 09:54:25 +08:00
|
|
|
static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
static int
|
|
|
|
mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
|
|
|
|
SCSITaskMgmtReply_t *pScsiTmReply);
|
2005-04-23 06:02:09 +08:00
|
|
|
void mptscsih_remove(struct pci_dev *);
|
2005-06-24 08:35:56 +08:00
|
|
|
void mptscsih_shutdown(struct pci_dev *);
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef CONFIG_PM
|
2005-04-23 06:02:09 +08:00
|
|
|
int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
|
|
|
|
int mptscsih_resume(struct pci_dev *pdev);
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|
|
|
|
|
2008-01-13 14:46:13 +08:00
|
|
|
#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_getFreeChainBuffer - Function to get a free chain
|
|
|
|
* from the MPT_SCSI_HOST FreeChainQ.
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @req_idx: Index of the SCSI IO request frame. (output)
|
|
|
|
*
|
|
|
|
* return SUCCESS or FAILED
|
|
|
|
*/
|
|
|
|
static inline int
|
|
|
|
mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
|
|
|
|
{
|
|
|
|
MPT_FRAME_HDR *chainBuf;
|
|
|
|
unsigned long flags;
|
|
|
|
int rc;
|
|
|
|
int chain_idx;
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
|
2007-09-15 08:46:51 +08:00
|
|
|
ioc->name));
|
2005-04-17 06:20:36 +08:00
|
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
|
|
|
if (!list_empty(&ioc->FreeChainQ)) {
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
|
|
|
|
u.frame.linkage.list);
|
|
|
|
list_del(&chainBuf->u.frame.linkage.list);
|
|
|
|
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
|
|
|
|
chain_idx = offset / ioc->req_sz;
|
|
|
|
rc = SUCCESS;
|
2007-09-15 08:46:51 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
|
|
|
|
ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
|
|
|
rc = FAILED;
|
|
|
|
chain_idx = MPT_HOST_NO_CHAIN;
|
2007-09-15 08:46:51 +08:00
|
|
|
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
|
|
|
|
ioc->name));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
|
|
|
|
|
|
|
*retIndex = chain_idx;
|
|
|
|
return rc;
|
|
|
|
} /* mptscsih_getFreeChainBuffer() */
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
|
|
|
|
* SCSIIORequest_t Message Frame.
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @SCpnt: Pointer to scsi_cmnd structure
|
|
|
|
* @pReq: Pointer to SCSIIORequest_t structure
|
|
|
|
*
|
|
|
|
* Returns ...
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
|
|
|
|
SCSIIORequest_t *pReq, int req_idx)
|
|
|
|
{
|
|
|
|
char *psge;
|
|
|
|
char *chainSge;
|
|
|
|
struct scatterlist *sg;
|
|
|
|
int frm_sz;
|
|
|
|
int sges_left, sg_done;
|
|
|
|
int chain_idx = MPT_HOST_NO_CHAIN;
|
|
|
|
int sgeOffset;
|
|
|
|
int numSgeSlots, numSgeThisFrame;
|
|
|
|
u32 sgflags, sgdir, thisxfer = 0;
|
|
|
|
int chain_dma_off = 0;
|
|
|
|
int newIndex;
|
|
|
|
int ii;
|
|
|
|
dma_addr_t v2;
|
|
|
|
u32 RequestNB;
|
|
|
|
|
|
|
|
sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
|
|
|
|
if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
|
|
|
|
sgdir = MPT_TRANSFER_HOST_TO_IOC;
|
|
|
|
} else {
|
|
|
|
sgdir = MPT_TRANSFER_IOC_TO_HOST;
|
|
|
|
}
|
|
|
|
|
|
|
|
psge = (char *) &pReq->SGL;
|
|
|
|
frm_sz = ioc->req_sz;
|
|
|
|
|
|
|
|
/* Map the data portion, if any.
|
|
|
|
* sges_left = 0 if no data transfer.
|
|
|
|
*/
|
2007-05-25 23:37:15 +08:00
|
|
|
sges_left = scsi_dma_map(SCpnt);
|
|
|
|
if (sges_left < 0)
|
|
|
|
return FAILED;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Handle the SG case.
|
|
|
|
*/
|
2007-05-25 23:37:15 +08:00
|
|
|
sg = scsi_sglist(SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
sg_done = 0;
|
|
|
|
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
|
|
|
|
chainSge = NULL;
|
|
|
|
|
|
|
|
/* Prior to entering this loop - the following must be set
|
|
|
|
* current MF: sgeOffset (bytes)
|
|
|
|
* chainSge (Null if original MF is not a chain buffer)
|
|
|
|
* sg_done (num SGE done for this MF)
|
|
|
|
*/
|
|
|
|
|
|
|
|
nextSGEset:
|
2009-05-29 19:07:04 +08:00
|
|
|
numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
|
2005-04-17 06:20:36 +08:00
|
|
|
numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
|
|
|
|
|
2009-05-29 19:07:04 +08:00
|
|
|
sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Get first (num - 1) SG elements
|
|
|
|
* Skip any SG entries with a length of 0
|
|
|
|
* NOTE: at finish, sg and psge pointed to NEXT data/location positions
|
|
|
|
*/
|
|
|
|
for (ii=0; ii < (numSgeThisFrame-1); ii++) {
|
|
|
|
thisxfer = sg_dma_len(sg);
|
|
|
|
if (thisxfer == 0) {
|
2009-05-29 19:22:37 +08:00
|
|
|
/* Get next SG element from the OS */
|
|
|
|
sg = sg_next(sg);
|
2005-04-17 06:20:36 +08:00
|
|
|
sg_done++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
v2 = sg_dma_address(sg);
|
2009-05-29 19:07:04 +08:00
|
|
|
ioc->add_sge(psge, sgflags | thisxfer, v2);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
/* Get next SG element from the OS */
|
|
|
|
sg = sg_next(sg);
|
2009-05-29 19:07:04 +08:00
|
|
|
psge += ioc->SGE_size;
|
|
|
|
sgeOffset += ioc->SGE_size;
|
2005-04-17 06:20:36 +08:00
|
|
|
sg_done++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numSgeThisFrame == sges_left) {
|
|
|
|
/* Add last element, end of buffer and end of list flags.
|
|
|
|
*/
|
|
|
|
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
|
|
|
|
MPT_SGE_FLAGS_END_OF_BUFFER |
|
|
|
|
MPT_SGE_FLAGS_END_OF_LIST;
|
|
|
|
|
|
|
|
/* Add last SGE and set termination flags.
|
|
|
|
* Note: Last SGE may have a length of 0 - which should be ok.
|
|
|
|
*/
|
|
|
|
thisxfer = sg_dma_len(sg);
|
|
|
|
|
|
|
|
v2 = sg_dma_address(sg);
|
2009-05-29 19:07:04 +08:00
|
|
|
ioc->add_sge(psge, sgflags | thisxfer, v2);
|
|
|
|
sgeOffset += ioc->SGE_size;
|
2005-04-17 06:20:36 +08:00
|
|
|
sg_done++;
|
|
|
|
|
|
|
|
if (chainSge) {
|
|
|
|
/* The current buffer is a chain buffer,
|
|
|
|
* but there is not another one.
|
|
|
|
* Update the chain element
|
|
|
|
* Offset and Length fields.
|
|
|
|
*/
|
2009-05-29 19:07:04 +08:00
|
|
|
ioc->add_chain((char *)chainSge, 0, sgeOffset,
|
|
|
|
ioc->ChainBufferDMA + chain_dma_off);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
|
|
|
/* The current buffer is the original MF
|
|
|
|
* and there is no Chain buffer.
|
|
|
|
*/
|
|
|
|
pReq->ChainOffset = 0;
|
|
|
|
RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
|
2007-07-25 13:44:01 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-04-17 06:20:36 +08:00
|
|
|
"Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
|
|
|
|
ioc->RequestNB[req_idx] = RequestNB;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* At least one chain buffer is needed.
|
|
|
|
* Complete the first MF
|
|
|
|
* - last SGE element, set the LastElement bit
|
|
|
|
* - set ChainOffset (words) for orig MF
|
|
|
|
* (OR finish previous MF chain buffer)
|
|
|
|
* - update MFStructPtr ChainIndex
|
|
|
|
* - Populate chain element
|
|
|
|
* Also
|
|
|
|
* Loop until done.
|
|
|
|
*/
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
ioc->name, sg_done));
|
|
|
|
|
|
|
|
/* Set LAST_ELEMENT flag for last non-chain element
|
|
|
|
* in the buffer. Since psge points at the NEXT
|
|
|
|
* SGE element, go back one SGE element, update the flags
|
|
|
|
* and reset the pointer. (Note: sgflags & thisxfer are already
|
|
|
|
* set properly).
|
|
|
|
*/
|
|
|
|
if (sg_done) {
|
2009-05-29 19:07:04 +08:00
|
|
|
u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
|
2005-04-17 06:20:36 +08:00
|
|
|
sgflags = le32_to_cpu(*ptmp);
|
|
|
|
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
|
|
|
|
*ptmp = cpu_to_le32(sgflags);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chainSge) {
|
|
|
|
/* The current buffer is a chain buffer.
|
|
|
|
* chainSge points to the previous Chain Element.
|
|
|
|
* Update its chain element Offset and Length (must
|
|
|
|
* include chain element size) fields.
|
|
|
|
* Old chain element is now complete.
|
|
|
|
*/
|
|
|
|
u8 nextChain = (u8) (sgeOffset >> 2);
|
2009-05-29 19:07:04 +08:00
|
|
|
sgeOffset += ioc->SGE_size;
|
|
|
|
ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
|
|
|
|
ioc->ChainBufferDMA + chain_dma_off);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
|
|
|
/* The original MF buffer requires a chain buffer -
|
|
|
|
* set the offset.
|
|
|
|
* Last element in this MF is a chain element.
|
|
|
|
*/
|
|
|
|
pReq->ChainOffset = (u8) (sgeOffset >> 2);
|
|
|
|
RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
|
2007-07-25 13:44:01 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
|
2005-04-17 06:20:36 +08:00
|
|
|
ioc->RequestNB[req_idx] = RequestNB;
|
|
|
|
}
|
|
|
|
|
|
|
|
sges_left -= sg_done;
|
|
|
|
|
|
|
|
|
|
|
|
/* NOTE: psge points to the beginning of the chain element
|
|
|
|
* in current buffer. Get a chain buffer.
|
|
|
|
*/
|
2005-08-18 22:24:53 +08:00
|
|
|
if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
|
2007-07-25 13:44:01 +08:00
|
|
|
dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-08-18 22:24:53 +08:00
|
|
|
"getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
|
|
|
|
ioc->name, pReq->CDB[0], SCpnt));
|
2005-04-17 06:20:36 +08:00
|
|
|
return FAILED;
|
2005-08-18 22:24:53 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Update the tracking arrays.
|
|
|
|
* If chainSge == NULL, update ReqToChain, else ChainToChain
|
|
|
|
*/
|
|
|
|
if (chainSge) {
|
|
|
|
ioc->ChainToChain[chain_idx] = newIndex;
|
|
|
|
} else {
|
|
|
|
ioc->ReqToChain[req_idx] = newIndex;
|
|
|
|
}
|
|
|
|
chain_idx = newIndex;
|
|
|
|
chain_dma_off = ioc->req_sz * chain_idx;
|
|
|
|
|
|
|
|
/* Populate the chainSGE for the current buffer.
|
|
|
|
* - Set chain buffer pointer to psge and fill
|
|
|
|
* out the Address and Flags fields.
|
|
|
|
*/
|
|
|
|
chainSge = (char *) psge;
|
2007-09-15 08:46:51 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
|
|
|
|
ioc->name, psge, req_idx));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Start the SGE for the next buffer
|
|
|
|
*/
|
|
|
|
psge = (char *) (ioc->ChainBuffer + chain_dma_off);
|
|
|
|
sgeOffset = 0;
|
|
|
|
sg_done = 0;
|
|
|
|
|
2007-09-15 08:46:51 +08:00
|
|
|
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
|
|
|
|
ioc->name, psge, chain_idx));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Start the SGE for the next buffer
|
|
|
|
*/
|
|
|
|
|
|
|
|
goto nextSGEset;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
} /* mptscsih_AddSGE() */
|
|
|
|
|
2006-07-12 07:22:22 +08:00
|
|
|
static void
|
|
|
|
mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
|
|
|
|
U32 SlotStatus)
|
|
|
|
{
|
|
|
|
MPT_FRAME_HDR *mf;
|
|
|
|
SEPRequest_t *SEPMsg;
|
|
|
|
|
2007-06-16 07:27:21 +08:00
|
|
|
if (ioc->bus_type != SAS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Not supported for hidden raid components
|
|
|
|
*/
|
|
|
|
if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
|
2006-07-12 07:22:22 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
|
2007-07-25 13:44:01 +08:00
|
|
|
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
|
2008-07-04 14:47:27 +08:00
|
|
|
ioc->name,__func__));
|
2006-07-12 07:22:22 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SEPMsg = (SEPRequest_t *)mf;
|
|
|
|
SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
|
2007-01-30 00:42:20 +08:00
|
|
|
SEPMsg->Bus = vtarget->channel;
|
|
|
|
SEPMsg->TargetID = vtarget->id;
|
2006-07-12 07:22:22 +08:00
|
|
|
SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
|
|
|
|
SEPMsg->SlotStatus = SlotStatus;
|
2007-07-25 13:44:01 +08:00
|
|
|
devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2007-01-30 00:42:20 +08:00
|
|
|
"Sending SEP cmd=%x channel=%d id=%d\n",
|
|
|
|
ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
|
2006-07-12 07:22:22 +08:00
|
|
|
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
|
|
|
|
}
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
#ifdef CONFIG_FUSION_LOGGING
|
2007-01-30 00:44:54 +08:00
|
|
|
/**
|
2007-07-25 13:44:01 +08:00
|
|
|
* mptscsih_info_scsiio - debug print info on reply frame
|
2007-01-30 00:44:54 +08:00
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @sc: original scsi cmnd pointer
|
2007-07-25 13:44:01 +08:00
|
|
|
* @pScsiReply: Pointer to MPT reply frame
|
|
|
|
*
|
|
|
|
* MPT_DEBUG_REPLY needs to be enabled to obtain this info
|
2007-01-30 00:44:54 +08:00
|
|
|
*
|
|
|
|
* Refer to lsi/mpi.h.
|
|
|
|
**/
|
|
|
|
static void
|
2007-07-25 13:44:01 +08:00
|
|
|
mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
|
2007-01-30 00:44:54 +08:00
|
|
|
{
|
2007-07-25 13:44:01 +08:00
|
|
|
char *desc = NULL;
|
|
|
|
char *desc1 = NULL;
|
|
|
|
u16 ioc_status;
|
|
|
|
u8 skey, asc, ascq;
|
|
|
|
|
|
|
|
ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
2007-01-30 00:44:54 +08:00
|
|
|
|
|
|
|
switch (ioc_status) {
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SUCCESS:
|
|
|
|
desc = "success";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_INVALID_BUS:
|
|
|
|
desc = "invalid bus";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
|
|
|
|
desc = "invalid target_id";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
|
|
|
|
desc = "device not there";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
|
|
|
|
desc = "data overrun";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
|
|
|
|
desc = "data underrun";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
|
|
|
|
desc = "I/O data error";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
|
|
|
|
desc = "protocol error";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
|
|
|
|
desc = "task terminated";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
|
|
|
|
desc = "residual mismatch";
|
|
|
|
break;
|
|
|
|
case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
|
|
|
|
desc = "task management failed";
|
|
|
|
break;
|
|
|
|
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
|
|
|
|
desc = "IOC terminated";
|
|
|
|
break;
|
|
|
|
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
|
|
|
|
desc = "ext terminated";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
2007-07-25 13:44:01 +08:00
|
|
|
default:
|
|
|
|
desc = "";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (pScsiReply->SCSIStatus)
|
|
|
|
{
|
2007-01-30 00:44:54 +08:00
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
case MPI_SCSI_STATUS_SUCCESS:
|
|
|
|
desc1 = "success";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_CHECK_CONDITION:
|
|
|
|
desc1 = "check condition";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_CONDITION_MET:
|
|
|
|
desc1 = "condition met";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_BUSY:
|
|
|
|
desc1 = "busy";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_INTERMEDIATE:
|
|
|
|
desc1 = "intermediate";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
|
|
|
|
desc1 = "intermediate condmet";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
|
|
|
|
desc1 = "reservation conflict";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_COMMAND_TERMINATED:
|
|
|
|
desc1 = "command terminated";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_TASK_SET_FULL:
|
|
|
|
desc1 = "task set full";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_ACA_ACTIVE:
|
|
|
|
desc1 = "aca active";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
|
|
|
|
desc1 = "fcpext device logged out";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
|
|
|
|
desc1 = "fcpext no link";
|
|
|
|
break;
|
|
|
|
case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
|
|
|
|
desc1 = "fcpext unassigned";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
desc1 = "";
|
2007-01-30 00:44:54 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
scsi_print_command(sc);
|
2014-06-25 21:27:36 +08:00
|
|
|
printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %llu\n",
|
2009-05-29 19:22:37 +08:00
|
|
|
ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
|
|
|
|
"resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
|
|
|
|
scsi_get_resid(sc));
|
|
|
|
printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
|
|
|
|
"sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
|
2007-07-25 13:44:01 +08:00
|
|
|
le32_to_cpu(pScsiReply->TransferCount), sc->result);
|
2009-05-29 19:22:37 +08:00
|
|
|
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
|
2007-07-25 13:44:01 +08:00
|
|
|
"scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
|
2007-09-15 08:46:51 +08:00
|
|
|
ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
|
2007-07-25 13:44:01 +08:00
|
|
|
pScsiReply->SCSIState);
|
2007-01-30 00:44:54 +08:00
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
|
|
|
|
skey = sc->sense_buffer[2] & 0x0F;
|
|
|
|
asc = sc->sense_buffer[12];
|
|
|
|
ascq = sc->sense_buffer[13];
|
|
|
|
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
|
|
|
|
"[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
|
2007-07-25 13:44:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for + dump FCP ResponseInfo[]!
|
|
|
|
*/
|
|
|
|
if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
|
|
|
|
pScsiReply->ResponseInfo)
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
|
|
|
|
ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
|
2007-01-30 00:44:54 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_io_done - Main SCSI IO callback routine registered to
|
|
|
|
* Fusion MPT (base) driver
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @mf: Pointer to original MPT request frame
|
|
|
|
* @r: Pointer to MPT reply frame (NULL if TurboReply)
|
|
|
|
*
|
|
|
|
* This routine is called from mpt.c::mpt_interrupt() at the completion
|
|
|
|
* of any SCSI IO request.
|
|
|
|
* This routine is registered with the Fusion MPT (base) driver at driver
|
|
|
|
* load/init time via the mpt_register() API call.
|
|
|
|
*
|
|
|
|
* Returns 1 indicating alloc'd request frame ptr should be freed.
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
|
|
|
{
|
|
|
|
struct scsi_cmnd *sc;
|
|
|
|
MPT_SCSI_HOST *hd;
|
|
|
|
SCSIIORequest_t *pScsiReq;
|
|
|
|
SCSIIOReply_t *pScsiReply;
|
2006-01-18 08:06:29 +08:00
|
|
|
u16 req_idx, req_idx_MR;
|
2007-09-15 08:48:19 +08:00
|
|
|
VirtDevice *vdevice;
|
2006-07-12 07:22:22 +08:00
|
|
|
VirtTarget *vtarget;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:15:59 +08:00
|
|
|
hd = shost_priv(ioc->sh);
|
2005-04-17 06:20:36 +08:00
|
|
|
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
2006-01-18 08:06:29 +08:00
|
|
|
req_idx_MR = (mr != NULL) ?
|
|
|
|
le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
|
2009-05-29 19:22:37 +08:00
|
|
|
|
|
|
|
/* Special case, where already freed message frame is received from
|
|
|
|
* Firmware. It happens with Resetting IOC.
|
|
|
|
* Return immediately. Do not care
|
|
|
|
*/
|
2006-01-18 08:06:29 +08:00
|
|
|
if ((req_idx != req_idx_MR) ||
|
2009-05-29 19:22:37 +08:00
|
|
|
(le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
|
2006-01-18 08:06:29 +08:00
|
|
|
return 0;
|
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (sc == NULL) {
|
|
|
|
MPIHeader_t *hdr = (MPIHeader_t *)mf;
|
|
|
|
|
|
|
|
/* Remark: writeSDP1 will use the ScsiDoneCtx
|
|
|
|
* If a SCSI I/O cmd, device disabled by OS and
|
|
|
|
* completion done. Cannot touch sc struct. Just free mem.
|
|
|
|
*/
|
|
|
|
if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
|
|
|
|
printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
|
|
|
|
ioc->name);
|
|
|
|
|
|
|
|
mptscsih_freeChainBuffers(ioc, req_idx);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-07-12 07:32:33 +08:00
|
|
|
if ((unsigned char *)mf != sc->host_scribble) {
|
|
|
|
mptscsih_freeChainBuffers(ioc, req_idx);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-09-02 14:15:53 +08:00
|
|
|
if (ioc->bus_type == SAS) {
|
|
|
|
VirtDevice *vdevice = sc->device->hostdata;
|
|
|
|
|
|
|
|
if (!vdevice || !vdevice->vtarget ||
|
|
|
|
vdevice->vtarget->deleted) {
|
|
|
|
sc->result = DID_NO_CONNECT << 16;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-12 07:32:33 +08:00
|
|
|
sc->host_scribble = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
sc->result = DID_OK << 16; /* Set default reply as OK */
|
|
|
|
pScsiReq = (SCSIIORequest_t *) mf;
|
|
|
|
pScsiReply = (SCSIIOReply_t *) mr;
|
|
|
|
|
2005-08-18 22:24:53 +08:00
|
|
|
if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
|
2007-07-25 13:44:01 +08:00
|
|
|
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-08-18 22:24:53 +08:00
|
|
|
"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
|
|
|
|
ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
|
|
|
|
}else{
|
2007-07-25 13:44:01 +08:00
|
|
|
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-08-18 22:24:53 +08:00
|
|
|
"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
|
|
|
|
ioc->name, mf, mr, sc, req_idx));
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (pScsiReply == NULL) {
|
|
|
|
/* special context reply handling */
|
|
|
|
;
|
|
|
|
} else {
|
|
|
|
u32 xfer_cnt;
|
|
|
|
u16 status;
|
|
|
|
u8 scsi_state, scsi_status;
|
2007-01-30 00:44:54 +08:00
|
|
|
u32 log_info;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
2010-07-26 21:26:21 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
scsi_state = pScsiReply->SCSIState;
|
|
|
|
scsi_status = pScsiReply->SCSIStatus;
|
|
|
|
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
|
2007-05-25 23:37:15 +08:00
|
|
|
scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
|
2007-01-30 00:44:54 +08:00
|
|
|
log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
/*
|
|
|
|
* if we get a data underrun indication, yet no data was
|
|
|
|
* transferred and the SCSI status indicates that the
|
|
|
|
* command was never started, change the data underrun
|
|
|
|
* to success
|
|
|
|
*/
|
|
|
|
if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
|
|
|
|
(scsi_status == MPI_SCSI_STATUS_BUSY ||
|
|
|
|
scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
|
|
|
|
scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
|
|
|
|
status = MPI_IOCSTATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
|
2005-04-23 06:02:09 +08:00
|
|
|
mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Look for + dump FCP ResponseInfo[]!
|
|
|
|
*/
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
|
|
|
|
pScsiReply->ResponseInfo) {
|
2014-06-25 21:27:36 +08:00
|
|
|
printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%llu] "
|
2007-09-15 08:46:51 +08:00
|
|
|
"FCP_ResponseInfo=%08xh\n", ioc->name,
|
2007-01-30 00:44:54 +08:00
|
|
|
sc->device->host->host_no, sc->device->channel,
|
|
|
|
sc->device->id, sc->device->lun,
|
2005-04-17 06:20:36 +08:00
|
|
|
le32_to_cpu(pScsiReply->ResponseInfo));
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(status) {
|
|
|
|
case MPI_IOCSTATUS_BUSY: /* 0x0002 */
|
2009-08-05 15:21:25 +08:00
|
|
|
case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
|
2005-04-17 06:20:36 +08:00
|
|
|
/* CHECKME!
|
|
|
|
* Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
|
|
|
|
* But not: DID_BUS_BUSY lest one risk
|
|
|
|
* killing interrupt handler:-(
|
|
|
|
*/
|
|
|
|
sc->result = SAM_STAT_BUSY;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
|
|
|
|
case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
|
|
|
|
sc->result = DID_BAD_TARGET << 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
|
|
|
|
/* Spoof to SCSI Selection Timeout! */
|
2006-04-22 06:14:35 +08:00
|
|
|
if (ioc->bus_type != FC)
|
|
|
|
sc->result = DID_NO_CONNECT << 16;
|
|
|
|
/* else fibre, just stall until rescan event */
|
|
|
|
else
|
|
|
|
sc->result = DID_REQUEUE << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
|
|
|
|
hd->sel_timeout[pScsiReq->TargetID]++;
|
2006-07-12 07:22:22 +08:00
|
|
|
|
2007-09-15 08:48:19 +08:00
|
|
|
vdevice = sc->device->hostdata;
|
|
|
|
if (!vdevice)
|
2006-07-12 07:22:22 +08:00
|
|
|
break;
|
2007-09-15 08:48:19 +08:00
|
|
|
vtarget = vdevice->vtarget;
|
2006-07-12 07:22:22 +08:00
|
|
|
if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
|
|
|
|
mptscsih_issue_sep_command(ioc, vtarget,
|
|
|
|
MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
|
|
|
|
vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
|
2006-07-12 07:25:35 +08:00
|
|
|
if ( ioc->bus_type == SAS ) {
|
2010-07-26 21:26:21 +08:00
|
|
|
u16 ioc_status =
|
|
|
|
le16_to_cpu(pScsiReply->IOCStatus);
|
|
|
|
if ((ioc_status &
|
|
|
|
MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
|
|
|
|
&&
|
|
|
|
((log_info & SAS_LOGINFO_MASK) ==
|
|
|
|
SAS_LOGINFO_NEXUS_LOSS)) {
|
|
|
|
VirtDevice *vdevice =
|
|
|
|
sc->device->hostdata;
|
|
|
|
|
|
|
|
/* flag the device as being in
|
|
|
|
* device removal delay so we can
|
|
|
|
* notify the midlayer to hold off
|
|
|
|
* on timeout eh */
|
|
|
|
if (vdevice && vdevice->
|
|
|
|
vtarget &&
|
|
|
|
vdevice->vtarget->
|
|
|
|
raidVolume)
|
|
|
|
printk(KERN_INFO
|
|
|
|
"Skipping Raid Volume"
|
|
|
|
"for inDMD\n");
|
|
|
|
else if (vdevice &&
|
|
|
|
vdevice->vtarget)
|
|
|
|
vdevice->vtarget->
|
|
|
|
inDMD = 1;
|
|
|
|
|
|
|
|
sc->result =
|
|
|
|
(DID_TRANSPORT_DISRUPTED
|
|
|
|
<< 16);
|
|
|
|
break;
|
2006-07-12 07:25:35 +08:00
|
|
|
}
|
2007-01-05 11:44:01 +08:00
|
|
|
} else if (ioc->bus_type == FC) {
|
|
|
|
/*
|
|
|
|
* The FC IOC may kill a request for variety of
|
|
|
|
* reasons, some of which may be recovered by a
|
|
|
|
* retry, some which are unlikely to be
|
|
|
|
* recovered. Return DID_ERROR instead of
|
|
|
|
* DID_RESET to permit retry of the command,
|
|
|
|
* just not an infinite number of them
|
|
|
|
*/
|
|
|
|
sc->result = DID_ERROR << 16;
|
|
|
|
break;
|
2006-07-12 07:25:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allow non-SAS & non-NEXUS_LOSS to drop into below code
|
|
|
|
*/
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Linux handles an unsolicited DID_RESET better
|
|
|
|
* than an unsolicited DID_ABORT.
|
|
|
|
*/
|
|
|
|
sc->result = DID_RESET << 16;
|
2012-12-19 06:21:30 +08:00
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
|
|
|
|
if (ioc->bus_type == FC)
|
|
|
|
sc->result = DID_ERROR << 16;
|
|
|
|
else
|
|
|
|
sc->result = DID_RESET << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
|
2007-05-25 23:37:15 +08:00
|
|
|
scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
|
|
|
|
sc->result=DID_SOFT_ERROR << 16;
|
|
|
|
else /* Sufficient data transfer occurred */
|
2005-04-17 06:20:36 +08:00
|
|
|
sc->result = (DID_OK << 16) | scsi_status;
|
2007-09-15 08:46:51 +08:00
|
|
|
dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2007-01-30 00:44:54 +08:00
|
|
|
"RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
|
2007-09-15 08:46:51 +08:00
|
|
|
ioc->name, sc->result, sc->device->channel, sc->device->id));
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2005-04-23 06:02:09 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
|
|
|
|
/*
|
|
|
|
* Do upfront check for valid SenseData and give it
|
|
|
|
* precedence!
|
|
|
|
*/
|
|
|
|
sc->result = (DID_OK << 16) | scsi_status;
|
2009-10-07 13:57:40 +08:00
|
|
|
if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For an Errata on LSI53C1030
|
|
|
|
* When the length of request data
|
|
|
|
* and transfer data are different
|
|
|
|
* with result of command (READ or VERIFY),
|
|
|
|
* DID_SOFT_ERROR is set.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2009-10-07 13:57:40 +08:00
|
|
|
if (ioc->bus_type == SPI) {
|
2011-07-20 23:58:03 +08:00
|
|
|
if ((pScsiReq->CDB[0] == READ_6 && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
|
2009-10-07 13:57:40 +08:00
|
|
|
pScsiReq->CDB[0] == READ_10 ||
|
|
|
|
pScsiReq->CDB[0] == READ_12 ||
|
2011-09-19 12:57:20 +08:00
|
|
|
(pScsiReq->CDB[0] == READ_16 &&
|
|
|
|
((pScsiReq->CDB[1] & 0x02) == 0)) ||
|
2009-10-07 13:57:40 +08:00
|
|
|
pScsiReq->CDB[0] == VERIFY ||
|
|
|
|
pScsiReq->CDB[0] == VERIFY_16) {
|
|
|
|
if (scsi_bufflen(sc) !=
|
|
|
|
xfer_cnt) {
|
|
|
|
sc->result =
|
|
|
|
DID_SOFT_ERROR << 16;
|
|
|
|
printk(KERN_WARNING "Errata"
|
|
|
|
"on LSI53C1030 occurred."
|
|
|
|
"sc->req_bufflen=0x%02x,"
|
|
|
|
"xfer_cnt=0x%02x\n",
|
|
|
|
scsi_bufflen(sc),
|
|
|
|
xfer_cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (xfer_cnt < sc->underflow) {
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
if (scsi_status == SAM_STAT_BUSY)
|
|
|
|
sc->result = SAM_STAT_BUSY;
|
|
|
|
else
|
|
|
|
sc->result = DID_SOFT_ERROR << 16;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
|
|
|
|
/* What to do?
|
|
|
|
*/
|
|
|
|
sc->result = DID_SOFT_ERROR << 16;
|
|
|
|
}
|
|
|
|
else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
|
|
|
|
/* Not real sure here either... */
|
|
|
|
sc->result = DID_RESET << 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
|
2007-09-15 08:46:51 +08:00
|
|
|
dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
" sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
|
|
|
|
ioc->name, sc->underflow));
|
|
|
|
dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
" ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
|
2007-07-25 13:44:01 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Report Queue Full
|
|
|
|
*/
|
|
|
|
if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
|
|
|
|
mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
|
2005-04-23 06:02:09 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2006-01-17 09:53:21 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
|
2007-05-25 23:37:15 +08:00
|
|
|
scsi_set_resid(sc, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
|
|
|
|
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
|
2007-03-20 00:31:51 +08:00
|
|
|
sc->result = (DID_OK << 16) | scsi_status;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (scsi_state == 0) {
|
|
|
|
;
|
2009-10-07 13:57:40 +08:00
|
|
|
} else if (scsi_state &
|
|
|
|
MPI_SCSI_STATE_AUTOSENSE_VALID) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For potential trouble on LSI53C1030.
|
|
|
|
* (date:2007.xx.)
|
|
|
|
* It is checked whether the length of
|
|
|
|
* request data is equal to
|
|
|
|
* the length of transfer and residual.
|
|
|
|
* MEDIUM_ERROR is set by incorrect data.
|
|
|
|
*/
|
|
|
|
if ((ioc->bus_type == SPI) &&
|
|
|
|
(sc->sense_buffer[2] & 0x20)) {
|
|
|
|
u32 difftransfer;
|
|
|
|
difftransfer =
|
|
|
|
sc->sense_buffer[3] << 24 |
|
|
|
|
sc->sense_buffer[4] << 16 |
|
|
|
|
sc->sense_buffer[5] << 8 |
|
|
|
|
sc->sense_buffer[6];
|
|
|
|
if (((sc->sense_buffer[3] & 0x80) ==
|
|
|
|
0x80) && (scsi_bufflen(sc)
|
|
|
|
!= xfer_cnt)) {
|
|
|
|
sc->sense_buffer[2] =
|
|
|
|
MEDIUM_ERROR;
|
|
|
|
sc->sense_buffer[12] = 0xff;
|
|
|
|
sc->sense_buffer[13] = 0xff;
|
|
|
|
printk(KERN_WARNING"Errata"
|
|
|
|
"on LSI53C1030 occurred."
|
|
|
|
"sc->req_bufflen=0x%02x,"
|
|
|
|
"xfer_cnt=0x%02x\n" ,
|
|
|
|
scsi_bufflen(sc),
|
|
|
|
xfer_cnt);
|
|
|
|
}
|
|
|
|
if (((sc->sense_buffer[3] & 0x80)
|
|
|
|
!= 0x80) &&
|
|
|
|
(scsi_bufflen(sc) !=
|
|
|
|
xfer_cnt + difftransfer)) {
|
|
|
|
sc->sense_buffer[2] =
|
|
|
|
MEDIUM_ERROR;
|
|
|
|
sc->sense_buffer[12] = 0xff;
|
|
|
|
sc->sense_buffer[13] = 0xff;
|
|
|
|
printk(KERN_WARNING
|
|
|
|
"Errata on LSI53C1030 occurred"
|
|
|
|
"sc->req_bufflen=0x%02x,"
|
|
|
|
" xfer_cnt=0x%02x,"
|
|
|
|
"difftransfer=0x%02x\n",
|
|
|
|
scsi_bufflen(sc),
|
|
|
|
xfer_cnt,
|
|
|
|
difftransfer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* If running against circa 200003dd 909 MPT f/w,
|
|
|
|
* may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
|
|
|
|
* (QUEUE_FULL) returned from device! --> get 0x0000?128
|
|
|
|
* and with SenseBytes set to 0.
|
|
|
|
*/
|
|
|
|
if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
|
|
|
|
mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (scsi_state &
|
|
|
|
(MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
|
|
|
|
) {
|
|
|
|
/*
|
|
|
|
* What to do?
|
|
|
|
*/
|
|
|
|
sc->result = DID_SOFT_ERROR << 16;
|
|
|
|
}
|
|
|
|
else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
|
|
|
|
/* Not real sure here either... */
|
|
|
|
sc->result = DID_RESET << 16;
|
|
|
|
}
|
|
|
|
else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
|
|
|
|
/* Device Inq. data indicates that it supports
|
|
|
|
* QTags, but rejects QTag messages.
|
|
|
|
* This command completed OK.
|
|
|
|
*
|
|
|
|
* Not real sure here either so do nothing... */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
|
|
|
|
mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
|
|
|
|
|
|
|
|
/* Add handling of:
|
|
|
|
* Reservation Conflict, Busy,
|
|
|
|
* Command Terminated, CHECK
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
|
|
|
|
sc->result = DID_SOFT_ERROR << 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
|
|
|
|
case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
|
|
|
|
case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
|
|
|
|
case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
|
|
|
|
case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
|
|
|
|
case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
|
|
|
|
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
|
|
|
|
case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* What to do?
|
|
|
|
*/
|
|
|
|
sc->result = DID_SOFT_ERROR << 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
} /* switch(status) */
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
#ifdef CONFIG_FUSION_LOGGING
|
|
|
|
if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
|
|
|
|
mptscsih_info_scsiio(ioc, sc, pScsiReply);
|
2007-01-30 00:44:54 +08:00
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
} /* end of address reply case */
|
2009-09-02 14:15:53 +08:00
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Unmap the DMA buffers, if any. */
|
2007-05-25 23:37:15 +08:00
|
|
|
scsi_dma_unmap(sc);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
sc->scsi_done(sc); /* Issue the command callback */
|
|
|
|
|
|
|
|
/* Free Chain buffers */
|
|
|
|
mptscsih_freeChainBuffers(ioc, req_idx);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* mptscsih_flush_running_cmds - For each command found, search
|
|
|
|
* Scsi_Host instance taskQ and reply to OS.
|
|
|
|
* Called only if recovering from a FW reload.
|
|
|
|
* @hd: Pointer to a SCSI HOST structure
|
|
|
|
*
|
|
|
|
* Returns: None.
|
|
|
|
*
|
|
|
|
* Must be called while new I/Os are being queued.
|
|
|
|
*/
|
2011-08-04 19:12:15 +08:00
|
|
|
void
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
|
|
|
|
{
|
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
2007-09-30 00:16:53 +08:00
|
|
|
struct scsi_cmnd *sc;
|
|
|
|
SCSIIORequest_t *mf = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
int ii;
|
2007-09-30 00:16:53 +08:00
|
|
|
int channel, id;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
for (ii= 0; ii < ioc->req_depth; ii++) {
|
|
|
|
sc = mptscsih_getclear_scsi_lookup(ioc, ii);
|
|
|
|
if (!sc)
|
|
|
|
continue;
|
|
|
|
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
|
|
|
|
if (!mf)
|
|
|
|
continue;
|
|
|
|
channel = mf->Bus;
|
|
|
|
id = mf->TargetID;
|
|
|
|
mptscsih_freeChainBuffers(ioc, ii);
|
|
|
|
mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
|
|
|
|
if ((unsigned char *)mf != sc->host_scribble)
|
|
|
|
continue;
|
|
|
|
scsi_dma_unmap(sc);
|
|
|
|
sc->result = DID_RESET << 16;
|
|
|
|
sc->host_scribble = NULL;
|
2009-05-29 19:22:37 +08:00
|
|
|
dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
|
|
|
|
"completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
|
|
|
|
"idx=%x\n", ioc->name, channel, id, sc, mf, ii));
|
2007-09-30 00:16:53 +08:00
|
|
|
sc->scsi_done(sc);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
2011-08-04 19:12:15 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_flush_running_cmds);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* mptscsih_search_running_cmds - Delete any commands associated
|
|
|
|
* with the specified target and lun. Function called only
|
|
|
|
* when a lun is disable by mid-layer.
|
|
|
|
* Do NOT access the referenced scsi_cmnd structure or
|
|
|
|
* members. Will cause either a paging or NULL ptr error.
|
2006-01-14 04:31:54 +08:00
|
|
|
* (BUT, BUT, BUT, the code does reference it! - mdr)
|
2005-11-17 09:54:25 +08:00
|
|
|
* @hd: Pointer to a SCSI HOST structure
|
|
|
|
* @vdevice: per device private data
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Returns: None.
|
|
|
|
*
|
|
|
|
* Called from slave_destroy.
|
|
|
|
*/
|
|
|
|
static void
|
2005-11-17 09:54:25 +08:00
|
|
|
mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
SCSIIORequest_t *mf = NULL;
|
|
|
|
int ii;
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
struct scsi_cmnd *sc;
|
2007-01-30 00:42:20 +08:00
|
|
|
struct scsi_lun lun;
|
2007-09-15 08:49:03 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
2007-09-30 00:16:53 +08:00
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
|
|
|
for (ii = 0; ii < ioc->req_depth; ii++) {
|
|
|
|
if ((sc = ioc->ScsiLookup[ii]) != NULL) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
|
2006-07-12 07:32:33 +08:00
|
|
|
if (mf == NULL)
|
|
|
|
continue;
|
2007-06-16 07:27:21 +08:00
|
|
|
/* If the device is a hidden raid component, then its
|
|
|
|
* expected that the mf->function will be RAID_SCSI_IO
|
|
|
|
*/
|
|
|
|
if (vdevice->vtarget->tflags &
|
|
|
|
MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
|
|
|
|
MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
|
|
|
|
continue;
|
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
int_to_scsilun(vdevice->lun, &lun);
|
|
|
|
if ((mf->Bus != vdevice->vtarget->channel) ||
|
|
|
|
(mf->TargetID != vdevice->vtarget->id) ||
|
|
|
|
memcmp(lun.scsi_lun, mf->LUN, 8))
|
2005-04-17 06:20:36 +08:00
|
|
|
continue;
|
|
|
|
|
2006-07-12 07:32:33 +08:00
|
|
|
if ((unsigned char *)mf != sc->host_scribble)
|
|
|
|
continue;
|
2007-09-30 00:16:53 +08:00
|
|
|
ioc->ScsiLookup[ii] = NULL;
|
|
|
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
|
|
|
mptscsih_freeChainBuffers(ioc, ii);
|
|
|
|
mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
|
2007-05-25 23:37:15 +08:00
|
|
|
scsi_dma_unmap(sc);
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
sc->host_scribble = NULL;
|
|
|
|
sc->result = DID_NO_CONNECT << 16;
|
2009-05-29 19:22:37 +08:00
|
|
|
dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
|
|
|
|
MYIOC_s_FMT "completing cmds: fw_channel %d, "
|
|
|
|
"fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
|
|
|
|
vdevice->vtarget->channel, vdevice->vtarget->id,
|
|
|
|
sc, mf, ii));
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
sc->scsi_done(sc);
|
2007-09-30 00:16:53 +08:00
|
|
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
2007-09-30 00:16:53 +08:00
|
|
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_report_queue_full - Report QUEUE_FULL status returned
|
|
|
|
* from a SCSI target device.
|
|
|
|
* @sc: Pointer to scsi_cmnd structure
|
|
|
|
* @pScsiReply: Pointer to SCSIIOReply_t
|
|
|
|
* @pScsiReq: Pointer to original SCSI request
|
|
|
|
*
|
|
|
|
* This routine periodically reports QUEUE_FULL status returned from a
|
|
|
|
* SCSI target device. It reports this to the console via kernel
|
|
|
|
* printk() API call, not more than once every 10 seconds.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
|
|
|
|
{
|
|
|
|
long time = jiffies;
|
|
|
|
MPT_SCSI_HOST *hd;
|
2007-09-15 08:49:03 +08:00
|
|
|
MPT_ADAPTER *ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
if (sc->device == NULL)
|
|
|
|
return;
|
|
|
|
if (sc->device->host == NULL)
|
|
|
|
return;
|
2007-09-30 00:15:59 +08:00
|
|
|
if ((hd = shost_priv(sc->device->host)) == NULL)
|
2005-04-23 06:02:09 +08:00
|
|
|
return;
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc = hd->ioc;
|
2005-04-23 06:02:09 +08:00
|
|
|
if (time - hd->last_queue_full > 10 * HZ) {
|
2014-06-25 21:27:36 +08:00
|
|
|
dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%llu) reported QUEUE_FULL!\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, 0, sc->device->id, sc->device->lun));
|
2005-04-23 06:02:09 +08:00
|
|
|
hd->last_queue_full = time;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_remove - Removed scsi devices
|
|
|
|
* @pdev: Pointer to pci_dev structure
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
void
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_remove(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
|
|
|
|
struct Scsi_Host *host = ioc->sh;
|
|
|
|
MPT_SCSI_HOST *hd;
|
2005-04-23 06:02:09 +08:00
|
|
|
int sz1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
scsi_remove_host(host);
|
|
|
|
|
2007-09-30 00:15:59 +08:00
|
|
|
if((hd = shost_priv(host)) == NULL)
|
2005-04-23 06:02:09 +08:00
|
|
|
return;
|
|
|
|
|
2005-06-24 08:35:56 +08:00
|
|
|
mptscsih_shutdown(pdev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
sz1=0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
if (ioc->ScsiLookup != NULL) {
|
2007-09-15 08:49:03 +08:00
|
|
|
sz1 = ioc->req_depth * sizeof(void *);
|
2007-09-30 00:16:53 +08:00
|
|
|
kfree(ioc->ScsiLookup);
|
|
|
|
ioc->ScsiLookup = NULL;
|
2005-04-23 06:02:09 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-04-23 06:02:09 +08:00
|
|
|
"Free'd ScsiLookup (%d) memory\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, sz1));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-12 07:37:26 +08:00
|
|
|
kfree(hd->info_kbuf);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
/* NULL the Scsi_Host pointer
|
|
|
|
*/
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->sh = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
scsi_host_put(host);
|
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
mpt_detach(pdev);
|
2005-08-18 22:24:53 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_shutdown - reboot notifier
|
|
|
|
*
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
void
|
2005-06-24 08:35:56 +08:00
|
|
|
mptscsih_shutdown(struct pci_dev *pdev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
2005-04-23 06:02:09 +08:00
|
|
|
* mptscsih_suspend - Fusion MPT scsi driver suspend routine.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:25:28 +08:00
|
|
|
mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-03-07 18:49:50 +08:00
|
|
|
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
|
|
|
|
|
|
|
|
scsi_block_requests(ioc->sh);
|
|
|
|
flush_scheduled_work();
|
2005-06-24 08:35:56 +08:00
|
|
|
mptscsih_shutdown(pdev);
|
2005-04-23 06:02:09 +08:00
|
|
|
return mpt_suspend(pdev,state);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_resume - Fusion MPT scsi driver resume routine.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_resume(struct pci_dev *pdev)
|
|
|
|
{
|
2008-03-07 18:49:50 +08:00
|
|
|
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = mpt_resume(pdev);
|
|
|
|
scsi_unblock_requests(ioc->sh);
|
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_info - Return information about MPT adapter
|
|
|
|
* @SChost: Pointer to Scsi_Host structure
|
|
|
|
*
|
|
|
|
* (linux scsi_host_template.info routine)
|
|
|
|
*
|
|
|
|
* Returns pointer to buffer where information was written.
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
const char *
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_info(struct Scsi_Host *SChost)
|
|
|
|
{
|
|
|
|
MPT_SCSI_HOST *h;
|
|
|
|
int size = 0;
|
|
|
|
|
2007-09-30 00:15:59 +08:00
|
|
|
h = shost_priv(SChost);
|
2005-04-23 06:02:09 +08:00
|
|
|
|
2014-06-26 05:06:54 +08:00
|
|
|
if (h->info_kbuf == NULL)
|
|
|
|
if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
|
|
|
|
return h->info_kbuf;
|
|
|
|
h->info_kbuf[0] = '\0';
|
|
|
|
|
|
|
|
mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
|
|
|
|
h->info_kbuf[size-1] = '\0';
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
return h->info_kbuf;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2013-03-31 13:42:38 +08:00
|
|
|
int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2005-04-17 06:20:36 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
2013-03-31 13:42:38 +08:00
|
|
|
seq_printf(m, "%s: %s, ", ioc->name, ioc->prod_name);
|
|
|
|
seq_printf(m, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
|
|
|
|
seq_printf(m, "Ports=%d, ", ioc->facts.NumberOfPorts);
|
|
|
|
seq_printf(m, "MaxQ=%d\n", ioc->req_depth);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-03-31 13:42:38 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
#define ADD_INDEX_LOG(req_ent) do { } while(0)
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
|
|
|
|
* @SCpnt: Pointer to scsi_cmnd structure
|
|
|
|
*
|
|
|
|
* (linux scsi_host_template.queuecommand routine)
|
|
|
|
* This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
|
|
|
|
* from a linux scsi_cmnd request and send it to the IOC.
|
|
|
|
*
|
|
|
|
* Returns 0. (rtn value discarded by linux scsi mid-layer)
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2014-03-28 04:40:36 +08:00
|
|
|
mptscsih_qcmd(struct scsi_cmnd *SCpnt)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
MPT_SCSI_HOST *hd;
|
|
|
|
MPT_FRAME_HDR *mf;
|
|
|
|
SCSIIORequest_t *pScsiReq;
|
2007-09-15 08:48:19 +08:00
|
|
|
VirtDevice *vdevice = SCpnt->device->hostdata;
|
2005-04-17 06:20:36 +08:00
|
|
|
u32 datalen;
|
|
|
|
u32 scsictl;
|
|
|
|
u32 scsidir;
|
|
|
|
u32 cmd_len;
|
|
|
|
int my_idx;
|
|
|
|
int ii;
|
2007-07-25 13:44:01 +08:00
|
|
|
MPT_ADAPTER *ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:15:59 +08:00
|
|
|
hd = shost_priv(SCpnt->device->host);
|
2007-07-25 13:44:01 +08:00
|
|
|
ioc = hd->ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-03-28 04:40:36 +08:00
|
|
|
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p\n",
|
|
|
|
ioc->name, SCpnt));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-04-26 14:39:15 +08:00
|
|
|
if (ioc->taskmgmt_quiesce_io)
|
2005-04-17 06:20:36 +08:00
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put together a MPT SCSI request...
|
|
|
|
*/
|
2007-09-15 08:49:03 +08:00
|
|
|
if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
|
2007-07-25 13:44:01 +08:00
|
|
|
dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
|
|
|
|
ioc->name));
|
2005-04-17 06:20:36 +08:00
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
pScsiReq = (SCSIIORequest_t *) mf;
|
|
|
|
|
|
|
|
my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
|
|
|
|
|
|
|
ADD_INDEX_LOG(my_idx);
|
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
/* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
|
2005-04-17 06:20:36 +08:00
|
|
|
* Seems we may receive a buffer (datalen>0) even when there
|
|
|
|
* will be no data transfer! GRRRRR...
|
|
|
|
*/
|
|
|
|
if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
|
2007-05-25 23:37:15 +08:00
|
|
|
datalen = scsi_bufflen(SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
|
|
|
|
} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
|
2007-05-25 23:37:15 +08:00
|
|
|
datalen = scsi_bufflen(SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
|
|
|
|
} else {
|
|
|
|
datalen = 0;
|
|
|
|
scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Default to untagged. Once a target structure has been allocated,
|
|
|
|
* use the Inquiry data to determine if device supports tagged.
|
|
|
|
*/
|
2014-06-26 05:06:54 +08:00
|
|
|
if ((vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
|
2005-04-17 06:20:36 +08:00
|
|
|
&& (SCpnt->device->tagged_supported)) {
|
|
|
|
scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
|
2009-12-16 21:31:13 +08:00
|
|
|
if (SCpnt->request && SCpnt->request->ioprio) {
|
|
|
|
if (((SCpnt->request->ioprio & 0x7) == 1) ||
|
|
|
|
!(SCpnt->request->ioprio & 0x7))
|
|
|
|
scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ;
|
|
|
|
}
|
|
|
|
} else
|
2005-04-17 06:20:36 +08:00
|
|
|
scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
|
2009-12-16 21:31:13 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Use the above information to set up the message frame
|
|
|
|
*/
|
2007-09-15 08:48:19 +08:00
|
|
|
pScsiReq->TargetID = (u8) vdevice->vtarget->id;
|
|
|
|
pScsiReq->Bus = vdevice->vtarget->channel;
|
2005-04-17 06:20:36 +08:00
|
|
|
pScsiReq->ChainOffset = 0;
|
2007-09-15 08:48:19 +08:00
|
|
|
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
|
2006-03-01 23:02:49 +08:00
|
|
|
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
|
|
|
|
else
|
|
|
|
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
|
2005-04-17 06:20:36 +08:00
|
|
|
pScsiReq->CDBLength = SCpnt->cmd_len;
|
|
|
|
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
|
|
|
|
pScsiReq->Reserved = 0;
|
2009-05-29 19:07:04 +08:00
|
|
|
pScsiReq->MsgFlags = mpt_msg_flags(ioc);
|
2007-01-30 00:42:20 +08:00
|
|
|
int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
|
2005-04-17 06:20:36 +08:00
|
|
|
pScsiReq->Control = cpu_to_le32(scsictl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write SCSI CDB into the message
|
|
|
|
*/
|
|
|
|
cmd_len = SCpnt->cmd_len;
|
|
|
|
for (ii=0; ii < cmd_len; ii++)
|
|
|
|
pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
|
|
|
|
|
|
|
|
for (ii=cmd_len; ii < 16; ii++)
|
|
|
|
pScsiReq->CDB[ii] = 0;
|
|
|
|
|
|
|
|
/* DataLength */
|
|
|
|
pScsiReq->DataLength = cpu_to_le32(datalen);
|
|
|
|
|
|
|
|
/* SenseBuffer low address */
|
2007-09-15 08:49:03 +08:00
|
|
|
pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
|
2005-04-17 06:20:36 +08:00
|
|
|
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
|
|
|
|
|
|
|
|
/* Now add the SG list
|
|
|
|
* Always have a SGE even if null length.
|
|
|
|
*/
|
|
|
|
if (datalen == 0) {
|
|
|
|
/* Add a NULL SGE */
|
2009-05-29 19:07:04 +08:00
|
|
|
ioc->add_sge((char *)&pScsiReq->SGL,
|
|
|
|
MPT_SGE_FLAGS_SSIMPLE_READ | 0,
|
2005-04-17 06:20:36 +08:00
|
|
|
(dma_addr_t) -1);
|
|
|
|
} else {
|
|
|
|
/* Add a 32 or 64 bit SGE */
|
2007-09-15 08:49:03 +08:00
|
|
|
if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2006-07-12 07:32:33 +08:00
|
|
|
SCpnt->host_scribble = (unsigned char *)mf;
|
2007-09-30 00:16:53 +08:00
|
|
|
mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
|
2007-07-25 13:44:01 +08:00
|
|
|
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
|
|
|
|
ioc->name, SCpnt, mf, my_idx));
|
2007-09-15 08:46:51 +08:00
|
|
|
DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
2007-09-15 08:49:03 +08:00
|
|
|
mptscsih_freeChainBuffers(ioc, my_idx);
|
|
|
|
mpt_free_msg_frame(ioc, mf);
|
2005-04-17 06:20:36 +08:00
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_freeChainBuffers - Function to free chain buffers associated
|
|
|
|
* with a SCSI IO request
|
|
|
|
* @hd: Pointer to the MPT_SCSI_HOST instance
|
|
|
|
* @req_idx: Index of the SCSI IO request frame.
|
|
|
|
*
|
|
|
|
* Called if SG chain buffer allocation fails and mptscsih callbacks.
|
|
|
|
* No return.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
|
|
|
|
{
|
|
|
|
MPT_FRAME_HDR *chain;
|
|
|
|
unsigned long flags;
|
|
|
|
int chain_idx;
|
|
|
|
int next;
|
|
|
|
|
|
|
|
/* Get the first chain index and reset
|
|
|
|
* tracker state.
|
|
|
|
*/
|
|
|
|
chain_idx = ioc->ReqToChain[req_idx];
|
|
|
|
ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
|
|
|
|
|
|
|
|
while (chain_idx != MPT_HOST_NO_CHAIN) {
|
|
|
|
|
|
|
|
/* Save the next chain buffer index */
|
|
|
|
next = ioc->ChainToChain[chain_idx];
|
|
|
|
|
|
|
|
/* Free this chain buffer and reset
|
|
|
|
* tracker
|
|
|
|
*/
|
|
|
|
ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
|
|
|
|
|
|
|
|
chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
|
|
|
|
+ (chain_idx * ioc->req_sz));
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
|
|
|
list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
|
|
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
ioc->name, chain_idx));
|
|
|
|
|
|
|
|
/* handle next */
|
|
|
|
chain_idx = next;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* Reset Handling
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2007-01-30 00:47:47 +08:00
|
|
|
/**
|
2009-05-29 19:14:48 +08:00
|
|
|
* mptscsih_IssueTaskMgmt - Generic send Task Management function.
|
|
|
|
* @hd: Pointer to MPT_SCSI_HOST structure
|
2005-04-17 06:20:36 +08:00
|
|
|
* @type: Task Management type
|
2007-02-21 03:17:03 +08:00
|
|
|
* @channel: channel number for task management
|
2007-01-30 00:42:20 +08:00
|
|
|
* @id: Logical Target ID for reset (if appropriate)
|
2005-04-17 06:20:36 +08:00
|
|
|
* @lun: Logical Unit for reset (if appropriate)
|
|
|
|
* @ctx2abort: Context for the task to be aborted (if appropriate)
|
2007-02-21 03:17:03 +08:00
|
|
|
* @timeout: timeout for task management control
|
|
|
|
*
|
2009-05-29 19:14:48 +08:00
|
|
|
* Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
|
|
|
|
* or a non-interrupt thread. In the former, must not call schedule().
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2009-05-29 19:14:48 +08:00
|
|
|
* Not all fields are meaningfull for all task types.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2009-05-29 19:14:48 +08:00
|
|
|
* Returns 0 for SUCCESS, or FAILED.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2007-01-30 00:47:47 +08:00
|
|
|
**/
|
2006-01-30 02:10:24 +08:00
|
|
|
int
|
2014-06-25 21:27:36 +08:00
|
|
|
mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, u64 lun,
|
2009-05-29 19:14:48 +08:00
|
|
|
int ctx2abort, ulong timeout)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-05-29 19:14:48 +08:00
|
|
|
MPT_FRAME_HDR *mf;
|
|
|
|
SCSITaskMgmt_t *pScsiTm;
|
|
|
|
int ii;
|
|
|
|
int retval;
|
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
unsigned long timeleft;
|
|
|
|
u8 issue_hard_reset;
|
2005-04-17 06:20:36 +08:00
|
|
|
u32 ioc_raw_state;
|
2009-05-29 19:14:48 +08:00
|
|
|
unsigned long time_count;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
issue_hard_reset = 0;
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc_raw_state = mpt_GetIocState(ioc, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
|
|
|
|
printk(MYIOC_s_WARN_FMT
|
2009-05-29 19:14:48 +08:00
|
|
|
"TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
|
2007-01-30 00:47:47 +08:00
|
|
|
ioc->name, type, ioc_raw_state);
|
2009-05-29 19:14:48 +08:00
|
|
|
printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
|
|
|
|
ioc->name, __func__);
|
2007-01-30 00:47:47 +08:00
|
|
|
if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
|
2009-05-29 19:14:48 +08:00
|
|
|
printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
|
2007-09-15 08:46:51 +08:00
|
|
|
"FAILED!!\n", ioc->name);
|
2009-05-29 19:14:48 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-08-05 13:34:37 +08:00
|
|
|
/* DOORBELL ACTIVE check is not required if
|
|
|
|
* MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)
|
|
|
|
&& (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&
|
|
|
|
(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
|
2007-01-30 00:47:47 +08:00
|
|
|
printk(MYIOC_s_WARN_FMT
|
2009-05-29 19:14:48 +08:00
|
|
|
"TaskMgmt type=%x: ioc_state: "
|
2007-01-30 00:47:47 +08:00
|
|
|
"DOORBELL_ACTIVE (0x%x)!\n",
|
|
|
|
ioc->name, type, ioc_raw_state);
|
|
|
|
return FAILED;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
mutex_lock(&ioc->taskmgmt_cmds.mutex);
|
|
|
|
if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
|
|
|
|
mf = NULL;
|
|
|
|
retval = FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Return Fail to calling function if no message frames available.
|
|
|
|
*/
|
2007-09-15 08:49:03 +08:00
|
|
|
if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
|
2009-05-29 19:14:48 +08:00
|
|
|
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
|
|
|
"TaskMgmt no msg frames!!\n", ioc->name));
|
|
|
|
retval = FAILED;
|
|
|
|
mpt_clear_taskmgmt_in_progress_flag(ioc);
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2009-05-29 19:14:48 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, mf));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Format the Request
|
|
|
|
*/
|
|
|
|
pScsiTm = (SCSITaskMgmt_t *) mf;
|
2007-01-30 00:42:20 +08:00
|
|
|
pScsiTm->TargetID = id;
|
2005-04-17 06:20:36 +08:00
|
|
|
pScsiTm->Bus = channel;
|
|
|
|
pScsiTm->ChainOffset = 0;
|
|
|
|
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
|
|
|
|
|
|
|
|
pScsiTm->Reserved = 0;
|
|
|
|
pScsiTm->TaskType = type;
|
|
|
|
pScsiTm->Reserved1 = 0;
|
|
|
|
pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
|
|
|
|
? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
|
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
for (ii=0; ii < 7; ii++)
|
|
|
|
pScsiTm->Reserved2[ii] = 0;
|
|
|
|
|
|
|
|
pScsiTm->TaskMsgContext = ctx2abort;
|
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
|
|
|
|
"task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
|
|
|
|
type, timeout));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
|
|
|
|
time_count = jiffies;
|
2007-09-15 08:49:03 +08:00
|
|
|
if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
|
|
|
|
(ioc->facts.MsgVersion >= MPI_VERSION_01_05))
|
|
|
|
mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
|
2007-08-14 18:38:40 +08:00
|
|
|
else {
|
2007-09-15 08:49:03 +08:00
|
|
|
retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
|
2007-08-14 18:38:40 +08:00
|
|
|
sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
|
|
|
|
if (retval) {
|
2009-05-29 19:14:48 +08:00
|
|
|
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
|
|
|
"TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
|
|
|
|
ioc->name, mf, retval));
|
|
|
|
mpt_free_msg_frame(ioc, mf);
|
|
|
|
mpt_clear_taskmgmt_in_progress_flag(ioc);
|
|
|
|
goto out;
|
2007-08-14 18:38:40 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
|
|
|
|
timeout*HZ);
|
|
|
|
if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
|
|
|
|
retval = FAILED;
|
|
|
|
dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
|
|
|
|
"TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
|
|
|
|
mpt_clear_taskmgmt_in_progress_flag(ioc);
|
|
|
|
if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
|
|
|
|
goto out;
|
|
|
|
issue_hard_reset = 1;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
retval = mptscsih_taskmgmt_reply(ioc, type,
|
|
|
|
(SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
|
2007-01-30 00:47:47 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"TaskMgmt completed (%d seconds)\n",
|
|
|
|
ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
|
2007-01-30 00:47:47 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
out:
|
2007-01-30 00:47:47 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
|
|
|
|
if (issue_hard_reset) {
|
2010-06-22 18:01:51 +08:00
|
|
|
printk(MYIOC_s_WARN_FMT
|
|
|
|
"Issuing Reset from %s!! doorbell=0x%08x\n",
|
|
|
|
ioc->name, __func__, mpt_GetIocState(ioc, 0));
|
2011-08-05 13:34:37 +08:00
|
|
|
retval = (ioc->bus_type == SAS) ?
|
|
|
|
mpt_HardResetHandler(ioc, CAN_SLEEP) :
|
|
|
|
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
2009-05-29 19:14:48 +08:00
|
|
|
mpt_free_msg_frame(ioc, mf);
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = (retval == 0) ? 0 : FAILED;
|
|
|
|
mutex_unlock(&ioc->taskmgmt_cmds.mutex);
|
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2009-05-29 19:14:48 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-01-17 21:43:14 +08:00
|
|
|
static int
|
|
|
|
mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
|
|
|
|
{
|
|
|
|
switch (ioc->bus_type) {
|
|
|
|
case FC:
|
|
|
|
return 40;
|
|
|
|
case SAS:
|
2010-03-18 21:53:19 +08:00
|
|
|
return 30;
|
2006-01-17 21:43:14 +08:00
|
|
|
case SPI:
|
|
|
|
default:
|
2008-09-23 21:28:58 +08:00
|
|
|
return 10;
|
2006-01-17 21:43:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
|
|
|
|
* @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
|
|
|
|
*
|
|
|
|
* (linux scsi_host_template.eh_abort_handler routine)
|
|
|
|
*
|
|
|
|
* Returns SUCCESS or FAILED.
|
2007-01-30 00:47:47 +08:00
|
|
|
**/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_abort(struct scsi_cmnd * SCpnt)
|
|
|
|
{
|
|
|
|
MPT_SCSI_HOST *hd;
|
|
|
|
MPT_FRAME_HDR *mf;
|
|
|
|
u32 ctx2abort;
|
|
|
|
int scpnt_idx;
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
int retval;
|
2007-06-16 07:24:14 +08:00
|
|
|
VirtDevice *vdevice;
|
|
|
|
MPT_ADAPTER *ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* If we can't locate our host adapter structure, return FAILED status.
|
|
|
|
*/
|
2007-09-30 00:15:59 +08:00
|
|
|
if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
|
2005-04-17 06:20:36 +08:00
|
|
|
SCpnt->result = DID_RESET << 16;
|
|
|
|
SCpnt->scsi_done(SCpnt);
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(KERN_ERR MYNAM ": task abort: "
|
|
|
|
"can't locate host! (sc=%p)\n", SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
ioc = hd->ioc;
|
|
|
|
printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt);
|
|
|
|
scsi_print_command(SCpnt);
|
|
|
|
|
|
|
|
vdevice = SCpnt->device->hostdata;
|
|
|
|
if (!vdevice || !vdevice->vtarget) {
|
2007-09-15 08:46:51 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"task abort: device has been deleted (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt));
|
2007-06-16 07:24:14 +08:00
|
|
|
SCpnt->result = DID_NO_CONNECT << 16;
|
|
|
|
SCpnt->scsi_done(SCpnt);
|
2010-03-18 21:53:19 +08:00
|
|
|
retval = SUCCESS;
|
2007-06-16 07:24:14 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2007-06-16 07:27:21 +08:00
|
|
|
/* Task aborts are not supported for hidden raid components.
|
|
|
|
*/
|
|
|
|
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
|
2007-09-15 08:46:51 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"task abort: hidden raid component (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt));
|
2007-06-16 07:27:21 +08:00
|
|
|
SCpnt->result = DID_RESET << 16;
|
|
|
|
retval = FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-03-18 21:53:19 +08:00
|
|
|
/* Task aborts are not supported for volumes.
|
|
|
|
*/
|
|
|
|
if (vdevice->vtarget->raidVolume) {
|
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"task abort: raid volume (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt));
|
|
|
|
SCpnt->result = DID_RESET << 16;
|
|
|
|
retval = FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Find this command
|
|
|
|
*/
|
2007-09-30 00:16:53 +08:00
|
|
|
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
/* Cmd not found in ScsiLookup.
|
2005-04-17 06:20:36 +08:00
|
|
|
* Do OS callback.
|
|
|
|
*/
|
|
|
|
SCpnt->result = DID_RESET << 16;
|
2007-09-15 08:46:51 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
|
2007-06-16 07:24:14 +08:00
|
|
|
"Command not in the active list! (sc=%p)\n", ioc->name,
|
|
|
|
SCpnt));
|
2010-01-25 18:50:52 +08:00
|
|
|
retval = SUCCESS;
|
2007-06-16 07:24:14 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
if (ioc->timeouts < -1)
|
|
|
|
ioc->timeouts++;
|
2006-04-22 06:14:35 +08:00
|
|
|
|
2009-01-06 17:33:37 +08:00
|
|
|
if (mpt_fwfault_debug)
|
|
|
|
mpt_halt_firmware(ioc);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
|
|
|
|
* (the IO to be ABORT'd)
|
|
|
|
*
|
|
|
|
* NOTE: Since we do not byteswap MsgContext, we do not
|
|
|
|
* swap it here either. It is an opaque cookie to
|
|
|
|
* the controller, so it does not matter. -DaveM
|
|
|
|
*/
|
2007-09-15 08:49:03 +08:00
|
|
|
mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
|
2005-04-17 06:20:36 +08:00
|
|
|
ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
|
2009-05-29 19:14:48 +08:00
|
|
|
retval = mptscsih_IssueTaskMgmt(hd,
|
|
|
|
MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
|
|
|
|
vdevice->vtarget->channel,
|
|
|
|
vdevice->vtarget->id, vdevice->lun,
|
|
|
|
ctx2abort, mptscsih_get_tm_timeout(ioc));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-04-04 21:42:41 +08:00
|
|
|
if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
|
2009-05-29 19:22:37 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"task abort: command still in active list! (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt));
|
2006-07-12 07:32:33 +08:00
|
|
|
retval = FAILED;
|
2009-05-29 19:22:37 +08:00
|
|
|
} else {
|
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"task abort: command cleared from active list! (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt));
|
|
|
|
retval = SUCCESS;
|
|
|
|
}
|
2006-07-12 07:32:33 +08:00
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
out:
|
2011-04-04 21:42:41 +08:00
|
|
|
printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
|
2011-02-10 14:23:44 +08:00
|
|
|
ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
|
2011-04-04 21:42:41 +08:00
|
|
|
SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
|
|
|
|
* @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
|
|
|
|
*
|
|
|
|
* (linux scsi_host_template.eh_dev_reset_handler routine)
|
|
|
|
*
|
|
|
|
* Returns SUCCESS or FAILED.
|
2007-01-30 00:47:47 +08:00
|
|
|
**/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
|
|
|
|
{
|
|
|
|
MPT_SCSI_HOST *hd;
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
int retval;
|
2007-06-16 07:24:14 +08:00
|
|
|
VirtDevice *vdevice;
|
|
|
|
MPT_ADAPTER *ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* If we can't locate our host adapter structure, return FAILED status.
|
|
|
|
*/
|
2007-09-30 00:15:59 +08:00
|
|
|
if ((hd = shost_priv(SCpnt->device->host)) == NULL){
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(KERN_ERR MYNAM ": target reset: "
|
|
|
|
"Can't locate host! (sc=%p)\n", SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
ioc = hd->ioc;
|
|
|
|
printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt);
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
scsi_print_command(SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
vdevice = SCpnt->device->hostdata;
|
|
|
|
if (!vdevice || !vdevice->vtarget) {
|
2011-02-10 14:23:44 +08:00
|
|
|
retval = 0;
|
2007-06-16 07:24:14 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2007-06-16 07:27:21 +08:00
|
|
|
/* Target reset to hidden raid component is not supported
|
|
|
|
*/
|
|
|
|
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
|
|
|
|
retval = FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
retval = mptscsih_IssueTaskMgmt(hd,
|
|
|
|
MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
|
|
|
|
vdevice->vtarget->channel,
|
|
|
|
vdevice->vtarget->id, 0, 0,
|
|
|
|
mptscsih_get_tm_timeout(ioc));
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
out:
|
|
|
|
printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
|
|
|
|
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
|
|
|
|
if (retval == 0)
|
|
|
|
return SUCCESS;
|
2007-01-30 00:47:47 +08:00
|
|
|
else
|
|
|
|
return FAILED;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-01-30 00:47:47 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
|
|
|
|
* @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
|
|
|
|
*
|
|
|
|
* (linux scsi_host_template.eh_bus_reset_handler routine)
|
|
|
|
*
|
|
|
|
* Returns SUCCESS or FAILED.
|
2007-01-30 00:47:47 +08:00
|
|
|
**/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
|
|
|
|
{
|
|
|
|
MPT_SCSI_HOST *hd;
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
int retval;
|
2007-09-15 08:48:19 +08:00
|
|
|
VirtDevice *vdevice;
|
2007-06-16 07:24:14 +08:00
|
|
|
MPT_ADAPTER *ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* If we can't locate our host adapter structure, return FAILED status.
|
|
|
|
*/
|
2007-09-30 00:15:59 +08:00
|
|
|
if ((hd = shost_priv(SCpnt->device->host)) == NULL){
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(KERN_ERR MYNAM ": bus reset: "
|
|
|
|
"Can't locate host! (sc=%p)\n", SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
ioc = hd->ioc;
|
|
|
|
printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt);
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
scsi_print_command(SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
if (ioc->timeouts < -1)
|
|
|
|
ioc->timeouts++;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:48:19 +08:00
|
|
|
vdevice = SCpnt->device->hostdata;
|
2009-05-29 19:22:37 +08:00
|
|
|
if (!vdevice || !vdevice->vtarget)
|
|
|
|
return SUCCESS;
|
2009-05-29 19:14:48 +08:00
|
|
|
retval = mptscsih_IssueTaskMgmt(hd,
|
|
|
|
MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
|
|
|
vdevice->vtarget->channel, 0, 0, 0,
|
|
|
|
mptscsih_get_tm_timeout(ioc));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
|
|
|
|
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
|
[SCSI] fusion SAS support (mptsas driver) updates
Summary of Changes:
* splitting mpt_interrupt per Christophs suggestion
about a month ago
* rename ScsiCfgData to SpiCfgData structure,
then move all the raid related info into
new structure called RaidCfgData. This is
done because SAS supports RAID, as well as SPI,
so the raid stuff should be seperate.
* incorrect timeout calculation for cntdn
inside WaitForDoorbellAck and WaitForDoortbellInt
* add support for interpreting SAS Log Info
* Increase Event Log Size from 0xA to 0x32
* Fix bug in mptsas/mptfc/mptspi - when controller
has Initiator Mode Disabled, and only running in
TargetMode, the mptctl would panic when loading.
The fix is to return 0, instead of -ENODEV, in
SCSI LLD respective probe routines
* Fix bug in mptlan.c - driver will panic if
there is host reset, due to dev being set to
zero in mpt_lan_ioc_reset
* Fix's for SPI - Echo Buffer
* Several fix's in mptscsih_io_done - FCP Response
info, RESIDUAL_MISMATCH, Data Underrun, etc.
* Cleanup Error Handling - EH handlers,
mptscsih_flush_cmds, and zeroing out ScsiLookup
from mptscsih_qcmd
* Cleanup asyn event handling from
mptscsih -> mptscsih_event_process. Also
added support for SAS Persistent Table Full,
an asyn event
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-09-15 08:09:10 +08:00
|
|
|
|
|
|
|
if (retval == 0)
|
|
|
|
return SUCCESS;
|
2007-01-30 00:47:47 +08:00
|
|
|
else
|
|
|
|
return FAILED;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
2006-12-07 12:38:43 +08:00
|
|
|
* mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
|
2005-04-17 06:20:36 +08:00
|
|
|
* @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
|
|
|
|
*
|
|
|
|
* (linux scsi_host_template.eh_host_reset_handler routine)
|
|
|
|
*
|
|
|
|
* Returns SUCCESS or FAILED.
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_host_reset(struct scsi_cmnd *SCpnt)
|
|
|
|
{
|
|
|
|
MPT_SCSI_HOST * hd;
|
2009-05-29 19:22:37 +08:00
|
|
|
int status = SUCCESS;
|
2007-06-16 07:24:14 +08:00
|
|
|
MPT_ADAPTER *ioc;
|
2009-05-29 19:22:37 +08:00
|
|
|
int retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* If we can't locate the host to reset, then we failed. */
|
2007-09-30 00:15:59 +08:00
|
|
|
if ((hd = shost_priv(SCpnt->device->host)) == NULL){
|
2007-09-15 08:46:51 +08:00
|
|
|
printk(KERN_ERR MYNAM ": host reset: "
|
|
|
|
"Can't locate host! (sc=%p)\n", SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
return FAILED;
|
|
|
|
}
|
|
|
|
|
2008-12-16 04:13:27 +08:00
|
|
|
/* make sure we have no outstanding commands at this stage */
|
|
|
|
mptscsih_flush_running_cmds(hd);
|
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
ioc = hd->ioc;
|
|
|
|
printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
|
|
|
|
ioc->name, SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* If our attempts to reset the host failed, then return a failed
|
|
|
|
* status. The host will be taken off line by the SCSI mid-layer.
|
|
|
|
*/
|
2010-03-18 21:42:17 +08:00
|
|
|
retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
2009-05-29 19:22:37 +08:00
|
|
|
if (retval < 0)
|
|
|
|
status = FAILED;
|
|
|
|
else
|
|
|
|
status = SUCCESS;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-16 07:24:14 +08:00
|
|
|
printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
|
|
|
|
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
return status;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-05-29 19:14:48 +08:00
|
|
|
mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
|
|
|
|
SCSITaskMgmtReply_t *pScsiTmReply)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-05-29 19:14:48 +08:00
|
|
|
u16 iocstatus;
|
|
|
|
u32 termination_count;
|
|
|
|
int retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
|
|
|
|
retval = FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
|
|
termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
|
|
|
|
"\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
|
|
|
|
"\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
|
|
|
|
pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
|
|
|
|
le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
|
|
|
|
termination_count));
|
|
|
|
|
|
|
|
if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
|
|
|
|
pScsiTmReply->ResponseCode)
|
|
|
|
mptscsih_taskmgmt_response_code(ioc,
|
|
|
|
pScsiTmReply->ResponseCode);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
|
|
|
|
retval = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = FAILED;
|
|
|
|
if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
|
|
|
|
if (termination_count == 1)
|
|
|
|
retval = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
|
|
|
|
iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
|
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-01-17 09:53:26 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2009-05-29 19:16:07 +08:00
|
|
|
void
|
2006-01-17 09:53:26 +08:00
|
|
|
mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
|
|
|
|
{
|
|
|
|
char *desc;
|
|
|
|
|
|
|
|
switch (response_code) {
|
|
|
|
case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
|
|
|
|
desc = "The task completed.";
|
|
|
|
break;
|
|
|
|
case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
|
|
|
|
desc = "The IOC received an invalid frame status.";
|
|
|
|
break;
|
|
|
|
case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
|
|
|
|
desc = "The task type is not supported.";
|
|
|
|
break;
|
|
|
|
case MPI_SCSITASKMGMT_RSP_TM_FAILED:
|
|
|
|
desc = "The requested task failed.";
|
|
|
|
break;
|
|
|
|
case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
|
|
|
|
desc = "The task completed successfully.";
|
|
|
|
break;
|
|
|
|
case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
|
|
|
|
desc = "The LUN request is invalid.";
|
|
|
|
break;
|
|
|
|
case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
|
|
|
|
desc = "The task is in the IOC queue and has not been sent to target.";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
desc = "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
|
|
|
|
ioc->name, response_code, desc);
|
|
|
|
}
|
2009-05-29 19:16:07 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
|
2006-01-17 09:53:26 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @mf: Pointer to SCSI task mgmt request frame
|
|
|
|
* @mr: Pointer to SCSI task mgmt reply frame
|
|
|
|
*
|
|
|
|
* This routine is called from mptbase.c::mpt_interrupt() at the completion
|
|
|
|
* of any SCSI task management request.
|
|
|
|
* This routine is registered with the MPT (base) driver at driver
|
|
|
|
* load/init time via the mpt_register() API call.
|
|
|
|
*
|
|
|
|
* Returns 1 indicating alloc'd request frame ptr should be freed.
|
2007-01-30 00:47:47 +08:00
|
|
|
**/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2009-05-29 19:14:48 +08:00
|
|
|
mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
|
|
|
|
MPT_FRAME_HDR *mr)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-05-29 19:14:48 +08:00
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
|
2007-01-30 00:47:47 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
|
2007-07-25 13:44:01 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
if (!mr)
|
2007-01-30 00:47:47 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
|
|
|
|
memcpy(ioc->taskmgmt_cmds.reply, mr,
|
|
|
|
min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
|
2007-01-30 00:47:47 +08:00
|
|
|
out:
|
2009-05-29 19:14:48 +08:00
|
|
|
if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
|
|
|
|
mpt_clear_taskmgmt_in_progress_flag(ioc);
|
|
|
|
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
|
|
|
|
complete(&ioc->taskmgmt_cmds.done);
|
2010-06-17 17:10:56 +08:00
|
|
|
if (ioc->bus_type == SAS)
|
|
|
|
ioc->schedule_target_reset(ioc);
|
2009-05-29 19:14:48 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* This is anyones guess quite frankly.
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
|
|
|
|
sector_t capacity, int geom[])
|
|
|
|
{
|
|
|
|
int heads;
|
|
|
|
int sectors;
|
|
|
|
sector_t cylinders;
|
|
|
|
ulong dummy;
|
|
|
|
|
|
|
|
heads = 64;
|
|
|
|
sectors = 32;
|
|
|
|
|
|
|
|
dummy = heads * sectors;
|
|
|
|
cylinders = capacity;
|
|
|
|
sector_div(cylinders,dummy);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle extended translation size for logical drives
|
|
|
|
* > 1Gb
|
|
|
|
*/
|
|
|
|
if ((ulong)capacity >= 0x200000) {
|
|
|
|
heads = 255;
|
|
|
|
sectors = 63;
|
|
|
|
dummy = heads * sectors;
|
|
|
|
cylinders = capacity;
|
|
|
|
sector_div(cylinders,dummy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return result */
|
|
|
|
geom[0] = heads;
|
|
|
|
geom[1] = sectors;
|
|
|
|
geom[2] = cylinders;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-15 00:14:21 +08:00
|
|
|
/* Search IOC page 3 to determine if this is hidden physical disk
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
2007-01-30 00:42:20 +08:00
|
|
|
mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
2006-03-15 00:14:21 +08:00
|
|
|
{
|
2007-01-30 00:45:37 +08:00
|
|
|
struct inactive_raid_component_info *component_info;
|
2009-05-29 19:23:56 +08:00
|
|
|
int i, j;
|
|
|
|
RaidPhysDiskPage1_t *phys_disk;
|
2007-01-30 00:42:20 +08:00
|
|
|
int rc = 0;
|
2009-05-29 19:23:56 +08:00
|
|
|
int num_paths;
|
2006-03-15 00:14:21 +08:00
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
if (!ioc->raid_data.pIocPg3)
|
|
|
|
goto out;
|
2006-03-15 00:14:21 +08:00
|
|
|
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
2007-01-30 00:42:20 +08:00
|
|
|
if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
|
|
|
|
(channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
|
|
|
|
rc = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
2006-03-01 23:02:49 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:23:56 +08:00
|
|
|
if (ioc->bus_type != SAS)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if dual path
|
|
|
|
*/
|
|
|
|
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
|
|
|
num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
|
|
|
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
|
|
|
|
if (num_paths < 2)
|
|
|
|
continue;
|
|
|
|
phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
|
|
|
|
(num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
|
|
|
|
if (!phys_disk)
|
|
|
|
continue;
|
|
|
|
if ((mpt_raid_phys_disk_pg1(ioc,
|
|
|
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
|
|
|
|
phys_disk))) {
|
|
|
|
kfree(phys_disk);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (j = 0; j < num_paths; j++) {
|
|
|
|
if ((phys_disk->Path[j].Flags &
|
|
|
|
MPI_RAID_PHYSDISK1_FLAG_INVALID))
|
|
|
|
continue;
|
|
|
|
if ((phys_disk->Path[j].Flags &
|
|
|
|
MPI_RAID_PHYSDISK1_FLAG_BROKEN))
|
|
|
|
continue;
|
|
|
|
if ((id == phys_disk->Path[j].PhysDiskID) &&
|
|
|
|
(channel == phys_disk->Path[j].PhysDiskBus)) {
|
|
|
|
rc = 1;
|
|
|
|
kfree(phys_disk);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kfree(phys_disk);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-30 00:45:37 +08:00
|
|
|
/*
|
|
|
|
* Check inactive list for matching phys disks
|
|
|
|
*/
|
|
|
|
if (list_empty(&ioc->raid_data.inactive_list))
|
|
|
|
goto out;
|
|
|
|
|
2008-03-09 19:16:27 +08:00
|
|
|
mutex_lock(&ioc->raid_data.inactive_list_mutex);
|
2007-01-30 00:45:37 +08:00
|
|
|
list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
|
|
|
|
list) {
|
|
|
|
if ((component_info->d.PhysDiskID == id) &&
|
|
|
|
(component_info->d.PhysDiskBus == channel))
|
|
|
|
rc = 1;
|
|
|
|
}
|
2008-03-09 19:16:27 +08:00
|
|
|
mutex_unlock(&ioc->raid_data.inactive_list_mutex);
|
2007-01-30 00:45:37 +08:00
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
2005-11-17 09:54:25 +08:00
|
|
|
}
|
2007-01-30 00:42:20 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_is_phys_disk);
|
2005-11-17 09:54:25 +08:00
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
u8
|
|
|
|
mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-01-30 00:45:37 +08:00
|
|
|
struct inactive_raid_component_info *component_info;
|
2009-05-29 19:23:56 +08:00
|
|
|
int i, j;
|
|
|
|
RaidPhysDiskPage1_t *phys_disk;
|
2007-01-30 00:42:20 +08:00
|
|
|
int rc = -ENXIO;
|
2009-05-29 19:23:56 +08:00
|
|
|
int num_paths;
|
2006-03-01 23:02:49 +08:00
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
if (!ioc->raid_data.pIocPg3)
|
|
|
|
goto out;
|
|
|
|
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
|
|
|
if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
|
|
|
|
(channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
|
|
|
|
rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-29 19:23:56 +08:00
|
|
|
if (ioc->bus_type != SAS)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if dual path
|
|
|
|
*/
|
|
|
|
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
|
|
|
num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
|
|
|
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
|
|
|
|
if (num_paths < 2)
|
|
|
|
continue;
|
|
|
|
phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
|
|
|
|
(num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
|
|
|
|
if (!phys_disk)
|
|
|
|
continue;
|
|
|
|
if ((mpt_raid_phys_disk_pg1(ioc,
|
|
|
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
|
|
|
|
phys_disk))) {
|
|
|
|
kfree(phys_disk);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (j = 0; j < num_paths; j++) {
|
|
|
|
if ((phys_disk->Path[j].Flags &
|
|
|
|
MPI_RAID_PHYSDISK1_FLAG_INVALID))
|
|
|
|
continue;
|
|
|
|
if ((phys_disk->Path[j].Flags &
|
|
|
|
MPI_RAID_PHYSDISK1_FLAG_BROKEN))
|
|
|
|
continue;
|
|
|
|
if ((id == phys_disk->Path[j].PhysDiskID) &&
|
|
|
|
(channel == phys_disk->Path[j].PhysDiskBus)) {
|
|
|
|
rc = phys_disk->PhysDiskNum;
|
|
|
|
kfree(phys_disk);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kfree(phys_disk);
|
|
|
|
}
|
|
|
|
|
2007-01-30 00:45:37 +08:00
|
|
|
/*
|
|
|
|
* Check inactive list for matching phys disks
|
|
|
|
*/
|
|
|
|
if (list_empty(&ioc->raid_data.inactive_list))
|
|
|
|
goto out;
|
|
|
|
|
2008-03-09 19:16:27 +08:00
|
|
|
mutex_lock(&ioc->raid_data.inactive_list_mutex);
|
2007-01-30 00:45:37 +08:00
|
|
|
list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
|
|
|
|
list) {
|
|
|
|
if ((component_info->d.PhysDiskID == id) &&
|
|
|
|
(component_info->d.PhysDiskBus == channel))
|
|
|
|
rc = component_info->d.PhysDiskNum;
|
|
|
|
}
|
2008-03-09 19:16:27 +08:00
|
|
|
mutex_unlock(&ioc->raid_data.inactive_list_mutex);
|
2007-01-30 00:45:37 +08:00
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
2005-11-17 09:54:25 +08:00
|
|
|
}
|
2007-01-30 00:42:20 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_raid_id_to_num);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-11-17 09:54:25 +08:00
|
|
|
/*
|
|
|
|
* OS entry point to allow for host driver to free allocated memory
|
|
|
|
* Called if no device present or device being unloaded
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mptscsih_slave_destroy(struct scsi_device *sdev)
|
|
|
|
{
|
|
|
|
struct Scsi_Host *host = sdev->host;
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2005-11-17 09:54:25 +08:00
|
|
|
VirtTarget *vtarget;
|
|
|
|
VirtDevice *vdevice;
|
|
|
|
struct scsi_target *starget;
|
|
|
|
|
|
|
|
starget = scsi_target(sdev);
|
|
|
|
vtarget = starget->hostdata;
|
|
|
|
vdevice = sdev->hostdata;
|
2010-03-18 21:52:45 +08:00
|
|
|
if (!vdevice)
|
|
|
|
return;
|
2005-11-17 09:54:25 +08:00
|
|
|
|
|
|
|
mptscsih_search_running_cmds(hd, vdevice);
|
|
|
|
vtarget->num_luns--;
|
|
|
|
mptscsih_synchronize_cache(hd, vdevice);
|
|
|
|
kfree(vdevice);
|
|
|
|
sdev->hostdata = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-06-25 02:18:57 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_change_queue_depth - This function will set a devices queue depth
|
|
|
|
* @sdev: per scsi_device pointer
|
|
|
|
* @qdepth: requested queue depth
|
|
|
|
*
|
|
|
|
* Adding support for new 'change_queue_depth' api.
|
|
|
|
*/
|
|
|
|
int
|
2014-11-13 22:08:42 +08:00
|
|
|
mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(sdev->host);
|
2005-11-17 09:54:25 +08:00
|
|
|
VirtTarget *vtarget;
|
|
|
|
struct scsi_target *starget;
|
|
|
|
int max_depth;
|
2007-09-15 08:49:03 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-11-17 09:54:25 +08:00
|
|
|
starget = scsi_target(sdev);
|
|
|
|
vtarget = starget->hostdata;
|
2005-06-25 02:18:57 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
if (ioc->bus_type == SPI) {
|
2006-03-01 23:02:49 +08:00
|
|
|
if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
|
2005-04-17 06:20:36 +08:00
|
|
|
max_depth = 1;
|
2006-03-01 23:02:49 +08:00
|
|
|
else if (sdev->type == TYPE_DISK &&
|
|
|
|
vtarget->minSyncFactor <= MPT_ULTRA160)
|
|
|
|
max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
|
|
|
|
else
|
|
|
|
max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
|
2005-04-17 06:20:36 +08:00
|
|
|
} else
|
2009-08-05 15:22:58 +08:00
|
|
|
max_depth = ioc->sh->can_queue;
|
|
|
|
|
|
|
|
if (!sdev->tagged_supported)
|
|
|
|
max_depth = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (qdepth > max_depth)
|
|
|
|
qdepth = max_depth;
|
|
|
|
|
2014-11-13 22:08:42 +08:00
|
|
|
return scsi_change_queue_depth(sdev, qdepth);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OS entry point to adjust the queue_depths on a per-device basis.
|
|
|
|
* Called once per device the bus scan. Use it to force the queue_depth
|
|
|
|
* member to 1 if a device does not support Q tags.
|
|
|
|
* Return non-zero if fails.
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-11-17 09:54:25 +08:00
|
|
|
mptscsih_slave_configure(struct scsi_device *sdev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-11-17 09:54:25 +08:00
|
|
|
struct Scsi_Host *sh = sdev->host;
|
|
|
|
VirtTarget *vtarget;
|
|
|
|
VirtDevice *vdevice;
|
|
|
|
struct scsi_target *starget;
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(sh);
|
2007-09-15 08:49:03 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-11-17 09:54:25 +08:00
|
|
|
starget = scsi_target(sdev);
|
|
|
|
vtarget = starget->hostdata;
|
|
|
|
vdevice = sdev->hostdata;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2014-06-25 21:27:36 +08:00
|
|
|
"device @ %p, channel=%d, id=%d, lun=%llu\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
|
|
|
|
if (ioc->bus_type == SPI)
|
|
|
|
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-11-17 09:54:25 +08:00
|
|
|
"sdtr %d wdtr %d ppr %d inq length=%d\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, sdev->sdtr, sdev->wdtr,
|
2005-11-17 09:54:25 +08:00
|
|
|
sdev->ppr, sdev->inquiry_len));
|
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
vdevice->configured_lun = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-04-17 06:20:36 +08:00
|
|
|
"Queue depth=%d, tflags=%x\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, sdev->queue_depth, vtarget->tflags));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-15 08:49:03 +08:00
|
|
|
if (ioc->bus_type == SPI)
|
|
|
|
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2005-11-17 09:54:25 +08:00
|
|
|
"negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
|
2007-09-15 08:49:03 +08:00
|
|
|
ioc->name, vtarget->negoFlags, vtarget->maxOffset,
|
2005-11-17 09:54:25 +08:00
|
|
|
vtarget->minSyncFactor));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-11-13 22:08:42 +08:00
|
|
|
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
|
2007-09-15 08:49:03 +08:00
|
|
|
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2014-10-30 18:54:58 +08:00
|
|
|
"tagged %d, simple %d\n",
|
|
|
|
ioc->name,sdev->tagged_supported, sdev->simple_tags));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
[SCSI] mptsas: fix hangs caused by ATA pass-through
I may have an explanation for the LSI 1068 HBA hangs provoked by ATA
pass-through commands, in particular by smartctl.
First, my version of the symptoms. On an LSI SAS1068E B3 HBA running
01.29.00.00 firmware, with SATA disks, and with smartd running, I'm seeing
occasional task, bus, and host resets, some of which lead to hard faults of
the HBA requiring a reboot. Abusively looping the smartctl command,
# while true; do smartctl -a /dev/sdb > /dev/null; done
dramatically increases the frequency of these failures to nearly one per
minute. A high IO load through the HBA while looping smartctl seems to
improve the chance of a full scsi host reset or a non-recoverable hang.
I reduced what smartctl was doing down to a simple test case which
causes the hang with a single IO when pointed at the sd interface. See
the code at the bottom of this e-mail. It uses an SG_IO ioctl to issue
a single pass-through ATA identify device command. If the buffer
userspace gives for the read data has certain alignments, the task is
issued to the HBA but the HBA fails to respond. If run against the sg
interface, neither the test code nor smartctl causes a hang.
sd and sg handle the SG_IO ioctl slightly differently. Unless you
specifically set a flag to do direct IO, sg passes a buffer of its own,
which is page-aligned, to the block layer and later copies the result
into the userspace buffer regardless of its alignment. sd, on the other
hand, always does direct IO unless the userspace buffer fails an
alignment test at block/blk-map.c line 57, in which case a page-aligned
buffer is created and used for the transfer.
The alignment test currently checks for word-alignment, the default
setup by scsi_lib.c; therefore, userspace buffers of almost any
alignment are given directly to the HBA as DMA targets. The LSI 1068
hardware doesn't seem to like at least a couple of the alignments which
cross a page boundary (see the test code below). Curiously, many
page-boundary-crossing alignments do work just fine.
So, either the hardware has an bug handling certain alignments or the
hardware has a stricter alignment requirement than the driver is
advertising. If stricter alignment is required, then in no case should
misaligned buffers from userspace be allowed through without being
bounced or at least causing an error to be returned.
It seems the mptsas driver could use blk_queue_dma_alignment() to advertise
a stricter alignment requirement. If it does, sd does the right thing and
bounces misaligned buffers (see block/blk-map.c line 57). The following
patch to 2.6.34-rc5 makes my symptoms go away. I'm sure this is the wrong
place for this code, but it gets my idea across.
Acked-by: "Desai, Kashyap" <Kashyap.Desai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
2010-04-27 07:11:54 +08:00
|
|
|
blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* Private routines...
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/* Utility function to copy sense data from the scsi_cmnd buffer
|
|
|
|
* to the FC and SCSI target structures.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
2005-04-23 06:02:09 +08:00
|
|
|
mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-09-15 08:48:19 +08:00
|
|
|
VirtDevice *vdevice;
|
2005-04-17 06:20:36 +08:00
|
|
|
SCSIIORequest_t *pReq;
|
|
|
|
u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
|
2007-09-15 08:49:03 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Get target structure
|
|
|
|
*/
|
|
|
|
pReq = (SCSIIORequest_t *) mf;
|
2007-09-15 08:48:19 +08:00
|
|
|
vdevice = sc->device->hostdata;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (sense_count) {
|
|
|
|
u8 *sense_data;
|
|
|
|
int req_index;
|
|
|
|
|
|
|
|
/* Copy the sense received into the scsi command block. */
|
|
|
|
req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
2007-09-15 08:49:03 +08:00
|
|
|
sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
|
|
|
|
|
|
|
|
/* Log SMART data (asc = 0x5D, non-IM case only) if required.
|
|
|
|
*/
|
2007-09-15 08:49:03 +08:00
|
|
|
if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
|
2007-09-15 08:48:19 +08:00
|
|
|
if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
int idx;
|
|
|
|
|
2006-02-03 08:19:40 +08:00
|
|
|
idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
|
2005-04-17 06:20:36 +08:00
|
|
|
ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
|
|
|
|
ioc->events[idx].eventContext = ioc->eventContext;
|
|
|
|
|
2007-05-22 08:59:47 +08:00
|
|
|
ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
|
|
|
|
(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
|
|
|
|
(sc->device->channel << 8) | sc->device->id;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-22 08:59:47 +08:00
|
|
|
ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
ioc->eventContext++;
|
2007-09-15 08:49:03 +08:00
|
|
|
if (ioc->pcidev->vendor ==
|
2006-07-12 07:22:22 +08:00
|
|
|
PCI_VENDOR_ID_IBM) {
|
2007-09-15 08:49:03 +08:00
|
|
|
mptscsih_issue_sep_command(ioc,
|
2007-09-15 08:48:19 +08:00
|
|
|
vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
|
|
|
|
vdevice->vtarget->tflags |=
|
2006-07-12 07:22:22 +08:00
|
|
|
MPT_TARGET_FLAGS_LED_ON;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2007-09-15 08:49:03 +08:00
|
|
|
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
|
|
|
|
ioc->name));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-29 19:26:59 +08:00
|
|
|
/**
|
|
|
|
* mptscsih_get_scsi_lookup - retrieves scmd entry
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @i: index into the array
|
|
|
|
*
|
|
|
|
* Returns the scsi_cmd pointer
|
|
|
|
*/
|
|
|
|
struct scsi_cmnd *
|
|
|
|
mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
struct scsi_cmnd *scmd;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
|
|
|
scmd = ioc->ScsiLookup[i];
|
|
|
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
|
|
|
|
|
|
|
return scmd;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
|
2007-09-30 00:16:53 +08:00
|
|
|
|
|
|
|
/**
|
2009-06-10 07:01:01 +08:00
|
|
|
* mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
|
2009-05-29 19:22:37 +08:00
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @i: index into the array
|
|
|
|
*
|
2008-03-01 14:03:27 +08:00
|
|
|
* Returns the scsi_cmd pointer
|
2009-05-29 19:22:37 +08:00
|
|
|
*
|
2007-09-30 00:16:53 +08:00
|
|
|
**/
|
|
|
|
static struct scsi_cmnd *
|
|
|
|
mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
struct scsi_cmnd *scmd;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
|
|
|
scmd = ioc->ScsiLookup[i];
|
|
|
|
ioc->ScsiLookup[i] = NULL;
|
|
|
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
|
|
|
|
|
|
|
return scmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-05-24 08:02:30 +08:00
|
|
|
* mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
|
2007-09-30 00:16:53 +08:00
|
|
|
*
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @i: index into the array
|
|
|
|
* @scmd: scsi_cmnd pointer
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
static void
|
|
|
|
mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
|
|
|
ioc->ScsiLookup[i] = scmd;
|
|
|
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-16 08:29:33 +08:00
|
|
|
* SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
|
2007-09-30 00:16:53 +08:00
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2007-10-16 08:29:33 +08:00
|
|
|
* @sc: scsi_cmnd pointer
|
|
|
|
*/
|
2007-09-30 00:16:53 +08:00
|
|
|
static int
|
|
|
|
SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
int i, index=-1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
|
|
|
|
for (i = 0; i < ioc->req_depth; i++) {
|
|
|
|
if (ioc->ScsiLookup[i] == sc) {
|
|
|
|
index = i;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-30 00:16:53 +08:00
|
|
|
out:
|
|
|
|
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
|
|
|
|
return index;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
|
|
|
{
|
|
|
|
MPT_SCSI_HOST *hd;
|
|
|
|
|
2007-09-30 00:15:59 +08:00
|
|
|
if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
hd = shost_priv(ioc->sh);
|
|
|
|
switch (reset_phase) {
|
|
|
|
case MPT_IOC_SETUP_RESET:
|
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
|
|
|
|
break;
|
|
|
|
case MPT_IOC_PRE_RESET:
|
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
|
|
|
|
mptscsih_flush_running_cmds(hd);
|
|
|
|
break;
|
|
|
|
case MPT_IOC_POST_RESET:
|
|
|
|
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
|
|
|
|
if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
|
|
|
|
ioc->internal_cmds.status |=
|
|
|
|
MPT_MGMT_STATUS_DID_IOCRESET;
|
|
|
|
complete(&ioc->internal_cmds.done);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2009-05-29 19:14:06 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return 1; /* currently means nothing really */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
|
|
|
{
|
|
|
|
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"MPT event (=%02Xh) routed to SCSI host driver!\n",
|
|
|
|
ioc->name, event));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:22:37 +08:00
|
|
|
if ((event == MPI_EVENT_IOC_BUS_RESET ||
|
|
|
|
event == MPI_EVENT_EXT_BUS_RESET) &&
|
|
|
|
(ioc->bus_type == SPI) && (ioc->soft_resets < -1))
|
|
|
|
ioc->soft_resets++;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return 1; /* currently means nothing really */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* Bus Scan and Domain Validation functionality ...
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/*
|
|
|
|
* mptscsih_scandv_complete - Scan and DV callback routine registered
|
|
|
|
* to Fustion MPT (base) driver.
|
|
|
|
*
|
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
|
|
|
* @mf: Pointer to original MPT request frame
|
|
|
|
* @mr: Pointer to MPT reply frame (NULL if TurboReply)
|
|
|
|
*
|
|
|
|
* This routine is called from mpt.c::mpt_interrupt() at the completion
|
|
|
|
* of any SCSI IO request.
|
|
|
|
* This routine is registered with the Fusion MPT (base) driver at driver
|
|
|
|
* load/init time via the mpt_register() API call.
|
|
|
|
*
|
|
|
|
* Returns 1 indicating alloc'd request frame ptr should be freed.
|
|
|
|
*
|
|
|
|
* Remark: Sets a completion code and (possibly) saves sense data
|
|
|
|
* in the IOC member localReply structure.
|
|
|
|
* Used ONLY for DV and other internal commands.
|
|
|
|
*/
|
2005-04-23 06:02:09 +08:00
|
|
|
int
|
2009-05-29 19:14:06 +08:00
|
|
|
mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
|
|
|
|
MPT_FRAME_HDR *reply)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
SCSIIORequest_t *pReq;
|
2009-05-29 19:14:06 +08:00
|
|
|
SCSIIOReply_t *pReply;
|
|
|
|
u8 cmd;
|
2005-04-17 06:20:36 +08:00
|
|
|
u16 req_idx;
|
2009-05-29 19:14:06 +08:00
|
|
|
u8 *sense_data;
|
|
|
|
int sz;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
|
|
|
|
ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
|
|
|
|
if (!reply)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
pReply = (SCSIIOReply_t *) reply;
|
|
|
|
pReq = (SCSIIORequest_t *) req;
|
|
|
|
ioc->internal_cmds.completion_code =
|
|
|
|
mptscsih_get_completion_code(ioc, req, reply);
|
|
|
|
ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
|
|
|
|
memcpy(ioc->internal_cmds.reply, reply,
|
|
|
|
min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
|
|
|
|
cmd = reply->u.hdr.Function;
|
|
|
|
if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
|
|
|
|
(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
|
|
|
|
(pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
|
|
|
|
req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
|
|
|
|
sense_data = ((u8 *)ioc->sense_buf_pool +
|
|
|
|
(req_idx * MPT_SENSE_BUFFER_ALLOC));
|
|
|
|
sz = min_t(int, pReq->SenseBufferLength,
|
|
|
|
MPT_SENSE_BUFFER_ALLOC);
|
|
|
|
memcpy(ioc->internal_cmds.sense, sense_data, sz);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2009-05-29 19:14:06 +08:00
|
|
|
out:
|
|
|
|
if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
|
|
|
|
return 0;
|
|
|
|
ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
|
|
|
|
complete(&ioc->internal_cmds.done);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
/**
|
2010-05-24 08:02:30 +08:00
|
|
|
* mptscsih_get_completion_code - get completion code from MPT request
|
2009-05-29 19:14:06 +08:00
|
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2009-06-14 10:37:18 +08:00
|
|
|
* @req: Pointer to original MPT request frame
|
|
|
|
* @reply: Pointer to MPT reply frame (NULL if TurboReply)
|
2009-05-29 19:14:06 +08:00
|
|
|
*
|
|
|
|
**/
|
|
|
|
static int
|
|
|
|
mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
|
|
|
|
MPT_FRAME_HDR *reply)
|
|
|
|
{
|
|
|
|
SCSIIOReply_t *pReply;
|
|
|
|
MpiRaidActionReply_t *pr;
|
|
|
|
u8 scsi_status;
|
|
|
|
u16 status;
|
|
|
|
int completion_code;
|
|
|
|
|
|
|
|
pReply = (SCSIIOReply_t *)reply;
|
|
|
|
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
|
|
scsi_status = pReply->SCSIStatus;
|
|
|
|
|
|
|
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
|
|
|
|
"IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
|
|
|
|
scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
|
|
|
|
completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
|
|
|
|
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
|
|
|
|
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
|
|
|
|
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
|
|
|
|
completion_code = MPT_SCANDV_DID_RESET;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_BUSY:
|
|
|
|
case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
|
|
|
|
completion_code = MPT_SCANDV_BUSY;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
|
|
|
|
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
|
|
|
|
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
|
|
|
|
if (pReply->Function == MPI_FUNCTION_CONFIG) {
|
|
|
|
completion_code = MPT_SCANDV_GOOD;
|
|
|
|
} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
|
|
|
|
pr = (MpiRaidActionReply_t *)reply;
|
|
|
|
if (le16_to_cpu(pr->ActionStatus) ==
|
|
|
|
MPI_RAID_ACTION_ASTATUS_SUCCESS)
|
|
|
|
completion_code = MPT_SCANDV_GOOD;
|
|
|
|
else
|
|
|
|
completion_code = MPT_SCANDV_SOME_ERROR;
|
|
|
|
} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
|
|
|
|
completion_code = MPT_SCANDV_SENSE;
|
|
|
|
else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
|
|
|
|
if (req->u.scsireq.CDB[0] == INQUIRY)
|
|
|
|
completion_code = MPT_SCANDV_ISSUE_SENSE;
|
|
|
|
else
|
|
|
|
completion_code = MPT_SCANDV_DID_RESET;
|
|
|
|
} else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
|
|
|
|
completion_code = MPT_SCANDV_DID_RESET;
|
|
|
|
else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
|
|
|
|
completion_code = MPT_SCANDV_DID_RESET;
|
|
|
|
else if (scsi_status == MPI_SCSI_STATUS_BUSY)
|
|
|
|
completion_code = MPT_SCANDV_BUSY;
|
|
|
|
else
|
|
|
|
completion_code = MPT_SCANDV_GOOD;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
|
|
|
|
if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
|
|
|
|
completion_code = MPT_SCANDV_DID_RESET;
|
|
|
|
else
|
|
|
|
completion_code = MPT_SCANDV_SOME_ERROR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
completion_code = MPT_SCANDV_SOME_ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
} /* switch(status) */
|
|
|
|
|
|
|
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
" completionCode set to %08xh\n", ioc->name, completion_code));
|
|
|
|
return completion_code;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_do_cmd - Do internal command.
|
|
|
|
* @hd: MPT_SCSI_HOST pointer
|
|
|
|
* @io: INTERNAL_CMD pointer.
|
|
|
|
*
|
|
|
|
* Issue the specified internally generated command and do command
|
|
|
|
* specific cleanup. For bus scan / DV only.
|
|
|
|
* NOTES: If command is Inquiry and status is good,
|
|
|
|
* initialize a target structure, save the data
|
|
|
|
*
|
|
|
|
* Remark: Single threaded access only.
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* < 0 if an illegal command or no resources
|
|
|
|
*
|
|
|
|
* 0 if good
|
|
|
|
*
|
|
|
|
* > 0 if command complete but some type of completion error.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
|
|
|
|
{
|
|
|
|
MPT_FRAME_HDR *mf;
|
|
|
|
SCSIIORequest_t *pScsiReq;
|
|
|
|
int my_idx, ii, dir;
|
2009-05-29 19:14:06 +08:00
|
|
|
int timeout;
|
2005-04-17 06:20:36 +08:00
|
|
|
char cmdLen;
|
|
|
|
char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
2009-05-29 19:14:06 +08:00
|
|
|
u8 cmd = io->cmd;
|
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
int ret = 0;
|
|
|
|
unsigned long timeleft;
|
|
|
|
unsigned long flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:48 +08:00
|
|
|
/* don't send internal command during diag reset */
|
|
|
|
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
|
|
|
if (ioc->ioc_reset_in_progress) {
|
|
|
|
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
|
|
|
dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"%s: busy with host reset\n", ioc->name, __func__));
|
|
|
|
return MPT_SCANDV_BUSY;
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
mutex_lock(&ioc->internal_cmds.mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Set command specific information
|
|
|
|
*/
|
|
|
|
switch (cmd) {
|
|
|
|
case INQUIRY:
|
|
|
|
cmdLen = 6;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
|
|
|
CDB[0] = cmd;
|
|
|
|
CDB[4] = io->size;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TEST_UNIT_READY:
|
|
|
|
cmdLen = 6;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case START_STOP:
|
|
|
|
cmdLen = 6;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
|
|
|
CDB[0] = cmd;
|
|
|
|
CDB[4] = 1; /*Spin up the disk */
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 15;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case REQUEST_SENSE:
|
|
|
|
cmdLen = 6;
|
|
|
|
CDB[0] = cmd;
|
|
|
|
CDB[4] = io->size;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case READ_BUFFER:
|
|
|
|
cmdLen = 10;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
|
|
|
CDB[0] = cmd;
|
|
|
|
if (io->flags & MPT_ICFLAG_ECHO) {
|
|
|
|
CDB[1] = 0x0A;
|
|
|
|
} else {
|
|
|
|
CDB[1] = 0x02;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (io->flags & MPT_ICFLAG_BUF_CAP) {
|
|
|
|
CDB[1] |= 0x01;
|
|
|
|
}
|
|
|
|
CDB[6] = (io->size >> 16) & 0xFF;
|
|
|
|
CDB[7] = (io->size >> 8) & 0xFF;
|
|
|
|
CDB[8] = io->size & 0xFF;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WRITE_BUFFER:
|
|
|
|
cmdLen = 10;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_WRITE;
|
|
|
|
CDB[0] = cmd;
|
|
|
|
if (io->flags & MPT_ICFLAG_ECHO) {
|
|
|
|
CDB[1] = 0x0A;
|
|
|
|
} else {
|
|
|
|
CDB[1] = 0x02;
|
|
|
|
}
|
|
|
|
CDB[6] = (io->size >> 16) & 0xFF;
|
|
|
|
CDB[7] = (io->size >> 8) & 0xFF;
|
|
|
|
CDB[8] = io->size & 0xFF;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RESERVE:
|
|
|
|
cmdLen = 6;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
|
|
|
CDB[0] = cmd;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RELEASE:
|
|
|
|
cmdLen = 6;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
|
|
|
CDB[0] = cmd;
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SYNCHRONIZE_CACHE:
|
|
|
|
cmdLen = 10;
|
|
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
|
|
|
CDB[0] = cmd;
|
|
|
|
// CDB[1] = 0x02; /* set immediate bit */
|
2009-05-29 19:14:06 +08:00
|
|
|
timeout = 10;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Error Case */
|
2009-05-29 19:14:06 +08:00
|
|
|
ret = -EFAULT;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get and Populate a free Frame
|
2009-05-29 19:14:06 +08:00
|
|
|
* MsgContext set in mpt_get_msg_frame call
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2007-09-15 08:49:03 +08:00
|
|
|
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
|
2009-05-29 19:14:06 +08:00
|
|
|
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
|
|
|
|
ioc->name, __func__));
|
|
|
|
ret = MPT_SCANDV_BUSY;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pScsiReq = (SCSIIORequest_t *) mf;
|
|
|
|
|
|
|
|
/* Get the request index */
|
|
|
|
my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
|
|
|
ADD_INDEX_LOG(my_idx); /* for debug */
|
|
|
|
|
|
|
|
if (io->flags & MPT_ICFLAG_PHYS_DISK) {
|
|
|
|
pScsiReq->TargetID = io->physDiskNum;
|
|
|
|
pScsiReq->Bus = 0;
|
|
|
|
pScsiReq->ChainOffset = 0;
|
|
|
|
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
|
|
|
|
} else {
|
|
|
|
pScsiReq->TargetID = io->id;
|
2007-01-30 00:42:20 +08:00
|
|
|
pScsiReq->Bus = io->channel;
|
2005-04-17 06:20:36 +08:00
|
|
|
pScsiReq->ChainOffset = 0;
|
|
|
|
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
|
|
|
|
}
|
|
|
|
|
|
|
|
pScsiReq->CDBLength = cmdLen;
|
|
|
|
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
|
|
|
|
|
|
|
|
pScsiReq->Reserved = 0;
|
|
|
|
|
2009-05-29 19:07:04 +08:00
|
|
|
pScsiReq->MsgFlags = mpt_msg_flags(ioc);
|
2005-04-17 06:20:36 +08:00
|
|
|
/* MsgContext set in mpt_get_msg_fram call */
|
|
|
|
|
2007-01-30 00:42:20 +08:00
|
|
|
int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (io->flags & MPT_ICFLAG_TAGGED_CMD)
|
|
|
|
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
|
|
|
|
else
|
|
|
|
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
|
|
|
|
|
|
|
|
if (cmd == REQUEST_SENSE) {
|
|
|
|
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
|
2009-05-29 19:14:06 +08:00
|
|
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
for (ii = 0; ii < 16; ii++)
|
2005-04-17 06:20:36 +08:00
|
|
|
pScsiReq->CDB[ii] = CDB[ii];
|
|
|
|
|
|
|
|
pScsiReq->DataLength = cpu_to_le32(io->size);
|
2007-09-15 08:49:03 +08:00
|
|
|
pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
|
2005-04-17 06:20:36 +08:00
|
|
|
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
2014-06-25 21:27:36 +08:00
|
|
|
"%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%llu\n",
|
2009-05-29 19:14:06 +08:00
|
|
|
ioc->name, __func__, cmd, io->channel, io->id, io->lun));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
if (dir == MPI_SCSIIO_CONTROL_READ)
|
2009-05-29 19:07:04 +08:00
|
|
|
ioc->add_sge((char *) &pScsiReq->SGL,
|
2009-05-29 19:14:06 +08:00
|
|
|
MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
|
|
|
|
else
|
2009-05-29 19:07:04 +08:00
|
|
|
ioc->add_sge((char *) &pScsiReq->SGL,
|
2009-05-29 19:14:06 +08:00
|
|
|
MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
|
2007-09-15 08:49:03 +08:00
|
|
|
mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
|
2009-05-29 19:14:06 +08:00
|
|
|
timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
|
|
|
|
timeout*HZ);
|
|
|
|
if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
|
|
|
|
ret = MPT_SCANDV_DID_RESET;
|
|
|
|
dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
|
|
|
"%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
|
|
|
|
cmd));
|
|
|
|
if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
|
|
|
|
mpt_free_msg_frame(ioc, mf);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (!timeleft) {
|
2010-06-22 18:01:51 +08:00
|
|
|
printk(MYIOC_s_WARN_FMT
|
|
|
|
"Issuing Reset from %s!! doorbell=0x%08xh"
|
|
|
|
" cmd=0x%02x\n",
|
|
|
|
ioc->name, __func__, mpt_GetIocState(ioc, 0),
|
|
|
|
cmd);
|
2010-03-18 21:42:17 +08:00
|
|
|
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
2009-05-29 19:14:06 +08:00
|
|
|
mpt_free_msg_frame(ioc, mf);
|
|
|
|
}
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2009-05-29 19:14:06 +08:00
|
|
|
ret = ioc->internal_cmds.completion_code;
|
|
|
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
|
|
|
|
ioc->name, __func__, ret));
|
|
|
|
|
|
|
|
out:
|
|
|
|
CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
|
|
|
|
mutex_unlock(&ioc->internal_cmds.mutex);
|
|
|
|
return ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-11-17 09:54:25 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
|
|
|
/**
|
|
|
|
* mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
|
|
|
|
* @hd: Pointer to a SCSI HOST structure
|
2006-12-07 12:38:43 +08:00
|
|
|
* @vdevice: virtual target device
|
2005-11-17 09:54:25 +08:00
|
|
|
*
|
|
|
|
* Uses the ISR, but with special processing.
|
|
|
|
* MUST be single-threaded.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
|
|
|
|
{
|
|
|
|
INTERNAL_CMD iocmd;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-16 07:27:21 +08:00
|
|
|
/* Ignore hidden raid components, this is handled when the command
|
|
|
|
* is sent to the volume
|
|
|
|
*/
|
|
|
|
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
|
|
|
|
!vdevice->configured_lun)
|
|
|
|
return;
|
|
|
|
|
2005-11-17 09:54:25 +08:00
|
|
|
/* Following parameters will not change
|
|
|
|
* in this routine.
|
|
|
|
*/
|
|
|
|
iocmd.cmd = SYNCHRONIZE_CACHE;
|
|
|
|
iocmd.flags = 0;
|
|
|
|
iocmd.physDiskNum = -1;
|
|
|
|
iocmd.data = NULL;
|
|
|
|
iocmd.data_dma = -1;
|
|
|
|
iocmd.size = 0;
|
|
|
|
iocmd.rsvd = iocmd.rsvd2 = 0;
|
2007-01-30 00:42:20 +08:00
|
|
|
iocmd.channel = vdevice->vtarget->channel;
|
|
|
|
iocmd.id = vdevice->vtarget->id;
|
|
|
|
iocmd.lun = vdevice->lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-16 07:27:21 +08:00
|
|
|
mptscsih_do_cmd(hd, &iocmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-07-17 17:09:14 +08:00
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
|
|
|
|
(ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
|
|
|
|
(ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
|
|
|
|
(ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
|
|
|
|
ioc->facts.FWVersion.Word & 0x000000FF);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
|
2007-07-17 17:09:14 +08:00
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
|
|
|
|
(ioc->biosVersion & 0xFF000000) >> 24,
|
|
|
|
(ioc->biosVersion & 0x00FF0000) >> 16,
|
|
|
|
(ioc->biosVersion & 0x0000FF00) >> 8,
|
|
|
|
ioc->biosVersion & 0x000000FF);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
|
2007-07-17 17:09:14 +08:00
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
|
2007-07-17 17:09:14 +08:00
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_version_product_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(version_product, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_version_product_show, NULL);
|
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_version_nvdata_persistent_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%02xh\n",
|
|
|
|
ioc->nvdata_version_persistent);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_version_nvdata_persistent_show, NULL);
|
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_version_nvdata_default_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_version_nvdata_default_show, NULL);
|
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
|
2007-07-17 17:09:14 +08:00
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_board_assembly_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(board_assembly, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_board_assembly_show, NULL);
|
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(board_tracer, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_board_tracer_show, NULL);
|
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(io_delay, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_io_delay_show, NULL);
|
|
|
|
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-17 17:09:14 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-17 17:09:14 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(device_delay, S_IRUGO,
|
2007-07-17 17:09:14 +08:00
|
|
|
mptscsih_device_delay_show, NULL);
|
|
|
|
|
2007-07-25 13:44:01 +08:00
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-07-25 13:44:01 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-25 13:44:01 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
|
|
|
|
return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
|
|
|
|
}
|
|
|
|
static ssize_t
|
2008-02-22 07:13:36 +08:00
|
|
|
mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2007-07-25 13:44:01 +08:00
|
|
|
{
|
2008-02-22 07:13:36 +08:00
|
|
|
struct Scsi_Host *host = class_to_shost(dev);
|
2007-09-30 00:15:59 +08:00
|
|
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
2007-07-25 13:44:01 +08:00
|
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
|
|
|
int val = 0;
|
|
|
|
|
|
|
|
if (sscanf(buf, "%x", &val) != 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
ioc->debug_level = val;
|
|
|
|
printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
|
|
|
|
ioc->name, ioc->debug_level);
|
|
|
|
return strlen(buf);
|
|
|
|
}
|
2008-02-22 07:13:36 +08:00
|
|
|
static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
|
|
|
|
mptscsih_debug_level_show, mptscsih_debug_level_store);
|
|
|
|
|
|
|
|
struct device_attribute *mptscsih_host_attrs[] = {
|
|
|
|
&dev_attr_version_fw,
|
|
|
|
&dev_attr_version_bios,
|
|
|
|
&dev_attr_version_mpi,
|
|
|
|
&dev_attr_version_product,
|
|
|
|
&dev_attr_version_nvdata_persistent,
|
|
|
|
&dev_attr_version_nvdata_default,
|
|
|
|
&dev_attr_board_name,
|
|
|
|
&dev_attr_board_assembly,
|
|
|
|
&dev_attr_board_tracer,
|
|
|
|
&dev_attr_io_delay,
|
|
|
|
&dev_attr_device_delay,
|
|
|
|
&dev_attr_debug_level,
|
2007-07-17 17:09:14 +08:00
|
|
|
NULL,
|
|
|
|
};
|
2009-05-29 19:14:06 +08:00
|
|
|
|
2007-07-17 17:09:14 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_host_attrs);
|
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_remove);
|
|
|
|
EXPORT_SYMBOL(mptscsih_shutdown);
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
EXPORT_SYMBOL(mptscsih_suspend);
|
|
|
|
EXPORT_SYMBOL(mptscsih_resume);
|
|
|
|
#endif
|
2013-03-31 13:42:38 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_show_info);
|
2005-04-23 06:02:09 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_info);
|
|
|
|
EXPORT_SYMBOL(mptscsih_qcmd);
|
|
|
|
EXPORT_SYMBOL(mptscsih_slave_destroy);
|
|
|
|
EXPORT_SYMBOL(mptscsih_slave_configure);
|
|
|
|
EXPORT_SYMBOL(mptscsih_abort);
|
|
|
|
EXPORT_SYMBOL(mptscsih_dev_reset);
|
|
|
|
EXPORT_SYMBOL(mptscsih_bus_reset);
|
|
|
|
EXPORT_SYMBOL(mptscsih_host_reset);
|
|
|
|
EXPORT_SYMBOL(mptscsih_bios_param);
|
|
|
|
EXPORT_SYMBOL(mptscsih_io_done);
|
|
|
|
EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
|
|
|
|
EXPORT_SYMBOL(mptscsih_scandv_complete);
|
|
|
|
EXPORT_SYMBOL(mptscsih_event_process);
|
|
|
|
EXPORT_SYMBOL(mptscsih_ioc_reset);
|
2005-06-25 02:18:57 +08:00
|
|
|
EXPORT_SYMBOL(mptscsih_change_queue_depth);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-23 06:02:09 +08:00
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|