blob: 0c3ced70707b9b62be49c41f56e3bc482f80e2bb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090049#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/workqueue.h>
58
59#include <scsi/scsi.h>
60#include <scsi/scsi_cmnd.h>
61#include <scsi/scsi_device.h>
62#include <scsi/scsi_host.h>
63#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060064#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
67#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060068#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT SCSI Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptscsih"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*
82 * Other private/forward protos...
83 */
Kashyap, Desaidb7051b2009-05-29 16:56:59 +053084struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
Eric Mooree8206382007-09-29 10:16:53 -060085static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
86static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
87static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040088int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040090int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
93 SCSIIORequest_t *pReq, int req_idx);
94static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040095static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +053097int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
98 int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400100int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
101int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530103void
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530104mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530105static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
106 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400107int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700109static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530111static int
112mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
113 SCSITaskMgmtReply_t *pScsiTmReply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400114void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700115void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400117int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
118int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#endif
120
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900121#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * mptscsih_getFreeChainBuffer - Function to get a free chain
127 * from the MPT_SCSI_HOST FreeChainQ.
128 * @ioc: Pointer to MPT_ADAPTER structure
129 * @req_idx: Index of the SCSI IO request frame. (output)
130 *
131 * return SUCCESS or FAILED
132 */
133static inline int
134mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
135{
136 MPT_FRAME_HDR *chainBuf;
137 unsigned long flags;
138 int rc;
139 int chain_idx;
140
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530141 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600142 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 spin_lock_irqsave(&ioc->FreeQlock, flags);
144 if (!list_empty(&ioc->FreeChainQ)) {
145 int offset;
146
147 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
148 u.frame.linkage.list);
149 list_del(&chainBuf->u.frame.linkage.list);
150 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
151 chain_idx = offset / ioc->req_sz;
152 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600153 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
154 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
155 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 } else {
157 rc = FAILED;
158 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600159 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
160 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
162 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
163
164 *retIndex = chain_idx;
165 return rc;
166} /* mptscsih_getFreeChainBuffer() */
167
168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
169/*
170 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
171 * SCSIIORequest_t Message Frame.
172 * @ioc: Pointer to MPT_ADAPTER structure
173 * @SCpnt: Pointer to scsi_cmnd structure
174 * @pReq: Pointer to SCSIIORequest_t structure
175 *
176 * Returns ...
177 */
178static int
179mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
180 SCSIIORequest_t *pReq, int req_idx)
181{
182 char *psge;
183 char *chainSge;
184 struct scatterlist *sg;
185 int frm_sz;
186 int sges_left, sg_done;
187 int chain_idx = MPT_HOST_NO_CHAIN;
188 int sgeOffset;
189 int numSgeSlots, numSgeThisFrame;
190 u32 sgflags, sgdir, thisxfer = 0;
191 int chain_dma_off = 0;
192 int newIndex;
193 int ii;
194 dma_addr_t v2;
195 u32 RequestNB;
196
197 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
198 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
199 sgdir = MPT_TRANSFER_HOST_TO_IOC;
200 } else {
201 sgdir = MPT_TRANSFER_IOC_TO_HOST;
202 }
203
204 psge = (char *) &pReq->SGL;
205 frm_sz = ioc->req_sz;
206
207 /* Map the data portion, if any.
208 * sges_left = 0 if no data transfer.
209 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900210 sges_left = scsi_dma_map(SCpnt);
211 if (sges_left < 0)
212 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214 /* Handle the SG case.
215 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900216 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 sg_done = 0;
218 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
219 chainSge = NULL;
220
221 /* Prior to entering this loop - the following must be set
222 * current MF: sgeOffset (bytes)
223 * chainSge (Null if original MF is not a chain buffer)
224 * sg_done (num SGE done for this MF)
225 */
226
227nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530228 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
230
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530231 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 /* Get first (num - 1) SG elements
234 * Skip any SG entries with a length of 0
235 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
236 */
237 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
238 thisxfer = sg_dma_len(sg);
239 if (thisxfer == 0) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530240 /* Get next SG element from the OS */
241 sg = sg_next(sg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 sg_done++;
243 continue;
244 }
245
246 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530247 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Kashyap, Desai2f187862009-05-29 16:52:37 +0530249 /* Get next SG element from the OS */
250 sg = sg_next(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530251 psge += ioc->SGE_size;
252 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 sg_done++;
254 }
255
256 if (numSgeThisFrame == sges_left) {
257 /* Add last element, end of buffer and end of list flags.
258 */
259 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
260 MPT_SGE_FLAGS_END_OF_BUFFER |
261 MPT_SGE_FLAGS_END_OF_LIST;
262
263 /* Add last SGE and set termination flags.
264 * Note: Last SGE may have a length of 0 - which should be ok.
265 */
266 thisxfer = sg_dma_len(sg);
267
268 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530269 ioc->add_sge(psge, sgflags | thisxfer, v2);
270 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sg_done++;
272
273 if (chainSge) {
274 /* The current buffer is a chain buffer,
275 * but there is not another one.
276 * Update the chain element
277 * Offset and Length fields.
278 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530279 ioc->add_chain((char *)chainSge, 0, sgeOffset,
280 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 } else {
282 /* The current buffer is the original MF
283 * and there is no Chain buffer.
284 */
285 pReq->ChainOffset = 0;
286 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530287 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
289 ioc->RequestNB[req_idx] = RequestNB;
290 }
291 } else {
292 /* At least one chain buffer is needed.
293 * Complete the first MF
294 * - last SGE element, set the LastElement bit
295 * - set ChainOffset (words) for orig MF
296 * (OR finish previous MF chain buffer)
297 * - update MFStructPtr ChainIndex
298 * - Populate chain element
299 * Also
300 * Loop until done.
301 */
302
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530303 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 ioc->name, sg_done));
305
306 /* Set LAST_ELEMENT flag for last non-chain element
307 * in the buffer. Since psge points at the NEXT
308 * SGE element, go back one SGE element, update the flags
309 * and reset the pointer. (Note: sgflags & thisxfer are already
310 * set properly).
311 */
312 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530313 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 sgflags = le32_to_cpu(*ptmp);
315 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
316 *ptmp = cpu_to_le32(sgflags);
317 }
318
319 if (chainSge) {
320 /* The current buffer is a chain buffer.
321 * chainSge points to the previous Chain Element.
322 * Update its chain element Offset and Length (must
323 * include chain element size) fields.
324 * Old chain element is now complete.
325 */
326 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530327 sgeOffset += ioc->SGE_size;
328 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
329 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 } else {
331 /* The original MF buffer requires a chain buffer -
332 * set the offset.
333 * Last element in this MF is a chain element.
334 */
335 pReq->ChainOffset = (u8) (sgeOffset >> 2);
336 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530337 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 ioc->RequestNB[req_idx] = RequestNB;
339 }
340
341 sges_left -= sg_done;
342
343
344 /* NOTE: psge points to the beginning of the chain element
345 * in current buffer. Get a chain buffer.
346 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200347 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530348 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200349 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
350 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 /* Update the tracking arrays.
355 * If chainSge == NULL, update ReqToChain, else ChainToChain
356 */
357 if (chainSge) {
358 ioc->ChainToChain[chain_idx] = newIndex;
359 } else {
360 ioc->ReqToChain[req_idx] = newIndex;
361 }
362 chain_idx = newIndex;
363 chain_dma_off = ioc->req_sz * chain_idx;
364
365 /* Populate the chainSGE for the current buffer.
366 * - Set chain buffer pointer to psge and fill
367 * out the Address and Flags fields.
368 */
369 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600370 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
371 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 /* Start the SGE for the next buffer
374 */
375 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
376 sgeOffset = 0;
377 sg_done = 0;
378
Eric Moore29dd3602007-09-14 18:46:51 -0600379 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
380 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
382 /* Start the SGE for the next buffer
383 */
384
385 goto nextSGEset;
386 }
387
388 return SUCCESS;
389} /* mptscsih_AddSGE() */
390
Eric Moore786899b2006-07-11 17:22:22 -0600391static void
392mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
393 U32 SlotStatus)
394{
395 MPT_FRAME_HDR *mf;
396 SEPRequest_t *SEPMsg;
397
Eric Moorecc78d302007-06-15 17:27:21 -0600398 if (ioc->bus_type != SAS)
399 return;
400
401 /* Not supported for hidden raid components
402 */
403 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600404 return;
405
406 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530407 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700408 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600409 return;
410 }
411
412 SEPMsg = (SEPRequest_t *)mf;
413 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700414 SEPMsg->Bus = vtarget->channel;
415 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600416 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
417 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530418 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700419 "Sending SEP cmd=%x channel=%d id=%d\n",
420 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600421 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
422}
423
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530424#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700425/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530426 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700427 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700428 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530429 * @pScsiReply: Pointer to MPT reply frame
430 *
431 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700432 *
433 * Refer to lsi/mpi.h.
434 **/
435static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530436mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700437{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530438 char *desc = NULL;
439 char *desc1 = NULL;
440 u16 ioc_status;
441 u8 skey, asc, ascq;
442
443 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700444
445 switch (ioc_status) {
446
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530447 case MPI_IOCSTATUS_SUCCESS:
448 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700449 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530450 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
451 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700452 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530453 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
454 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700455 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530456 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
457 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700458 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530459 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
460 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700461 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530462 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
463 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700464 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530465 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
466 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700467 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530468 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
469 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700470 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530471 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
472 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700473 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530474 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
475 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700476 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530477 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
478 desc = "task management failed";
479 break;
480 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
481 desc = "IOC terminated";
482 break;
483 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
484 desc = "ext terminated";
485 break;
486 default:
487 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700488 break;
489 }
490
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530491 switch (pScsiReply->SCSIStatus)
492 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700493
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530494 case MPI_SCSI_STATUS_SUCCESS:
495 desc1 = "success";
496 break;
497 case MPI_SCSI_STATUS_CHECK_CONDITION:
498 desc1 = "check condition";
499 break;
500 case MPI_SCSI_STATUS_CONDITION_MET:
501 desc1 = "condition met";
502 break;
503 case MPI_SCSI_STATUS_BUSY:
504 desc1 = "busy";
505 break;
506 case MPI_SCSI_STATUS_INTERMEDIATE:
507 desc1 = "intermediate";
508 break;
509 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
510 desc1 = "intermediate condmet";
511 break;
512 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
513 desc1 = "reservation conflict";
514 break;
515 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
516 desc1 = "command terminated";
517 break;
518 case MPI_SCSI_STATUS_TASK_SET_FULL:
519 desc1 = "task set full";
520 break;
521 case MPI_SCSI_STATUS_ACA_ACTIVE:
522 desc1 = "aca active";
523 break;
524 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
525 desc1 = "fcpext device logged out";
526 break;
527 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
528 desc1 = "fcpext no link";
529 break;
530 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
531 desc1 = "fcpext unassigned";
532 break;
533 default:
534 desc1 = "";
535 break;
536 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700537
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530538 scsi_print_command(sc);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530539 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
540 ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
Eric Moore29dd3602007-09-14 18:46:51 -0600541 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
542 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
543 scsi_get_resid(sc));
544 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
545 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530546 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530547
Eric Moore29dd3602007-09-14 18:46:51 -0600548 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530549 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600550 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530551 pScsiReply->SCSIState);
552
553 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
554 skey = sc->sense_buffer[2] & 0x0F;
555 asc = sc->sense_buffer[12];
556 ascq = sc->sense_buffer[13];
557
Eric Moore29dd3602007-09-14 18:46:51 -0600558 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
559 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530560 }
561
562 /*
563 * Look for + dump FCP ResponseInfo[]!
564 */
565 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
566 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600567 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
568 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700569}
570#endif
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
573/*
574 * mptscsih_io_done - Main SCSI IO callback routine registered to
575 * Fusion MPT (base) driver
576 * @ioc: Pointer to MPT_ADAPTER structure
577 * @mf: Pointer to original MPT request frame
578 * @r: Pointer to MPT reply frame (NULL if TurboReply)
579 *
580 * This routine is called from mpt.c::mpt_interrupt() at the completion
581 * of any SCSI IO request.
582 * This routine is registered with the Fusion MPT (base) driver at driver
583 * load/init time via the mpt_register() API call.
584 *
585 * Returns 1 indicating alloc'd request frame ptr should be freed.
586 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400587int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
589{
590 struct scsi_cmnd *sc;
591 MPT_SCSI_HOST *hd;
592 SCSIIORequest_t *pScsiReq;
593 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700594 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600595 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600596 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Eric Mooree7eae9f2007-09-29 10:15:59 -0600598 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700600 req_idx_MR = (mr != NULL) ?
601 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
Kashyap, Desai2f187862009-05-29 16:52:37 +0530602
603 /* Special case, where already freed message frame is received from
604 * Firmware. It happens with Resetting IOC.
605 * Return immediately. Do not care
606 */
Moore, Eric2254c862006-01-17 17:06:29 -0700607 if ((req_idx != req_idx_MR) ||
Kashyap, Desai2f187862009-05-29 16:52:37 +0530608 (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
Moore, Eric2254c862006-01-17 17:06:29 -0700609 return 0;
Moore, Eric2254c862006-01-17 17:06:29 -0700610
Eric Mooree8206382007-09-29 10:16:53 -0600611 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (sc == NULL) {
613 MPIHeader_t *hdr = (MPIHeader_t *)mf;
614
615 /* Remark: writeSDP1 will use the ScsiDoneCtx
616 * If a SCSI I/O cmd, device disabled by OS and
617 * completion done. Cannot touch sc struct. Just free mem.
618 */
619 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
620 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
621 ioc->name);
622
623 mptscsih_freeChainBuffers(ioc, req_idx);
624 return 1;
625 }
626
Eric Moore3dc0b032006-07-11 17:32:33 -0600627 if ((unsigned char *)mf != sc->host_scribble) {
628 mptscsih_freeChainBuffers(ioc, req_idx);
629 return 1;
630 }
631
Kashyap, Desaifea98402009-09-02 11:45:53 +0530632 if (ioc->bus_type == SAS) {
633 VirtDevice *vdevice = sc->device->hostdata;
634
635 if (!vdevice || !vdevice->vtarget ||
636 vdevice->vtarget->deleted) {
637 sc->result = DID_NO_CONNECT << 16;
638 goto out;
639 }
640 }
641
Eric Moore3dc0b032006-07-11 17:32:33 -0600642 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sc->result = DID_OK << 16; /* Set default reply as OK */
644 pScsiReq = (SCSIIORequest_t *) mf;
645 pScsiReply = (SCSIIOReply_t *) mr;
646
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200647 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530648 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200649 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
650 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
651 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530652 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200653 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
654 ioc->name, mf, mr, sc, req_idx));
655 }
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (pScsiReply == NULL) {
658 /* special context reply handling */
659 ;
660 } else {
661 u32 xfer_cnt;
662 u16 status;
663 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700664 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +0530667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 scsi_state = pScsiReply->SCSIState;
669 scsi_status = pScsiReply->SCSIStatus;
670 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900671 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700672 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600674 /*
675 * if we get a data underrun indication, yet no data was
676 * transferred and the SCSI status indicates that the
677 * command was never started, change the data underrun
678 * to success
679 */
680 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
681 (scsi_status == MPI_SCSI_STATUS_BUSY ||
682 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
683 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
684 status = MPI_IOCSTATUS_SUCCESS;
685 }
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400688 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 /*
691 * Look for + dump FCP ResponseInfo[]!
692 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600693 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
694 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600695 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
696 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700697 sc->device->host->host_no, sc->device->channel,
698 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 le32_to_cpu(pScsiReply->ResponseInfo));
700 }
701
702 switch(status) {
703 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
Kashyap, Desaid23321b2009-08-05 12:51:25 +0530704 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 /* CHECKME!
706 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
707 * But not: DID_BUS_BUSY lest one risk
708 * killing interrupt handler:-(
709 */
710 sc->result = SAM_STAT_BUSY;
711 break;
712
713 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
714 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
715 sc->result = DID_BAD_TARGET << 16;
716 break;
717
718 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
719 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600720 if (ioc->bus_type != FC)
721 sc->result = DID_NO_CONNECT << 16;
722 /* else fibre, just stall until rescan event */
723 else
724 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
727 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600728
Eric Moorea69de502007-09-14 18:48:19 -0600729 vdevice = sc->device->hostdata;
730 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600731 break;
Eric Moorea69de502007-09-14 18:48:19 -0600732 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600733 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
734 mptscsih_issue_sep_command(ioc, vtarget,
735 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
736 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 break;
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600741 if ( ioc->bus_type == SAS ) {
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +0530742 u16 ioc_status =
743 le16_to_cpu(pScsiReply->IOCStatus);
744 if ((ioc_status &
745 MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
746 &&
747 ((log_info & SAS_LOGINFO_MASK) ==
748 SAS_LOGINFO_NEXUS_LOSS)) {
749 VirtDevice *vdevice =
750 sc->device->hostdata;
751
752 /* flag the device as being in
753 * device removal delay so we can
754 * notify the midlayer to hold off
755 * on timeout eh */
756 if (vdevice && vdevice->
757 vtarget &&
758 vdevice->vtarget->
759 raidVolume)
760 printk(KERN_INFO
761 "Skipping Raid Volume"
762 "for inDMD\n");
763 else if (vdevice &&
764 vdevice->vtarget)
765 vdevice->vtarget->
766 inDMD = 1;
767
768 sc->result =
769 (DID_TRANSPORT_DISRUPTED
770 << 16);
771 break;
Eric Moorebf451522006-07-11 17:25:35 -0600772 }
Eric Moore86dd4242007-01-04 20:44:01 -0700773 } else if (ioc->bus_type == FC) {
774 /*
775 * The FC IOC may kill a request for variety of
776 * reasons, some of which may be recovered by a
777 * retry, some which are unlikely to be
778 * recovered. Return DID_ERROR instead of
779 * DID_RESET to permit retry of the command,
780 * just not an infinite number of them
781 */
782 sc->result = DID_ERROR << 16;
783 break;
Eric Moorebf451522006-07-11 17:25:35 -0600784 }
785
786 /*
787 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
788 */
789
790 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 /* Linux handles an unsolicited DID_RESET better
792 * than an unsolicited DID_ABORT.
793 */
794 sc->result = DID_RESET << 16;
795
Kashyap, Desai2f187862009-05-29 16:52:37 +0530796 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
797 if (ioc->bus_type == FC)
798 sc->result = DID_ERROR << 16;
799 else
800 sc->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 break;
802
803 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900804 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600805 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
806 sc->result=DID_SOFT_ERROR << 16;
807 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600809 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700810 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600811 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
815 /*
816 * Do upfront check for valid SenseData and give it
817 * precedence!
818 */
819 sc->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530820 if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
821
822 /*
823 * For an Errata on LSI53C1030
824 * When the length of request data
825 * and transfer data are different
826 * with result of command (READ or VERIFY),
827 * DID_SOFT_ERROR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 */
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530829 if (ioc->bus_type == SPI) {
Kashyap, Desaie466e1c2011-07-20 21:28:03 +0530830 if ((pScsiReq->CDB[0] == READ_6 && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530831 pScsiReq->CDB[0] == READ_10 ||
832 pScsiReq->CDB[0] == READ_12 ||
nagalakshmi.nandigama@lsi.com513382c2011-09-19 10:27:20 +0530833 (pScsiReq->CDB[0] == READ_16 &&
834 ((pScsiReq->CDB[1] & 0x02) == 0)) ||
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530835 pScsiReq->CDB[0] == VERIFY ||
836 pScsiReq->CDB[0] == VERIFY_16) {
837 if (scsi_bufflen(sc) !=
838 xfer_cnt) {
839 sc->result =
840 DID_SOFT_ERROR << 16;
841 printk(KERN_WARNING "Errata"
842 "on LSI53C1030 occurred."
843 "sc->req_bufflen=0x%02x,"
844 "xfer_cnt=0x%02x\n",
845 scsi_bufflen(sc),
846 xfer_cnt);
847 }
848 }
849 }
850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600852 if (scsi_status == SAM_STAT_BUSY)
853 sc->result = SAM_STAT_BUSY;
854 else
855 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
857 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
858 /* What to do?
859 */
860 sc->result = DID_SOFT_ERROR << 16;
861 }
862 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
863 /* Not real sure here either... */
864 sc->result = DID_RESET << 16;
865 }
866 }
867
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530868
Eric Moore29dd3602007-09-14 18:46:51 -0600869 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
870 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
871 ioc->name, sc->underflow));
872 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
873 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 /* Report Queue Full
876 */
877 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
878 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 break;
881
Moore, Eric7e551472006-01-16 18:53:21 -0700882 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900883 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
885 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600886 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (scsi_state == 0) {
888 ;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530889 } else if (scsi_state &
890 MPI_SCSI_STATE_AUTOSENSE_VALID) {
891
892 /*
893 * For potential trouble on LSI53C1030.
894 * (date:2007.xx.)
895 * It is checked whether the length of
896 * request data is equal to
897 * the length of transfer and residual.
898 * MEDIUM_ERROR is set by incorrect data.
899 */
900 if ((ioc->bus_type == SPI) &&
901 (sc->sense_buffer[2] & 0x20)) {
902 u32 difftransfer;
903 difftransfer =
904 sc->sense_buffer[3] << 24 |
905 sc->sense_buffer[4] << 16 |
906 sc->sense_buffer[5] << 8 |
907 sc->sense_buffer[6];
908 if (((sc->sense_buffer[3] & 0x80) ==
909 0x80) && (scsi_bufflen(sc)
910 != xfer_cnt)) {
911 sc->sense_buffer[2] =
912 MEDIUM_ERROR;
913 sc->sense_buffer[12] = 0xff;
914 sc->sense_buffer[13] = 0xff;
915 printk(KERN_WARNING"Errata"
916 "on LSI53C1030 occurred."
917 "sc->req_bufflen=0x%02x,"
918 "xfer_cnt=0x%02x\n" ,
919 scsi_bufflen(sc),
920 xfer_cnt);
921 }
922 if (((sc->sense_buffer[3] & 0x80)
923 != 0x80) &&
924 (scsi_bufflen(sc) !=
925 xfer_cnt + difftransfer)) {
926 sc->sense_buffer[2] =
927 MEDIUM_ERROR;
928 sc->sense_buffer[12] = 0xff;
929 sc->sense_buffer[13] = 0xff;
930 printk(KERN_WARNING
931 "Errata on LSI53C1030 occurred"
932 "sc->req_bufflen=0x%02x,"
933 " xfer_cnt=0x%02x,"
934 "difftransfer=0x%02x\n",
935 scsi_bufflen(sc),
936 xfer_cnt,
937 difftransfer);
938 }
939 }
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /*
942 * If running against circa 200003dd 909 MPT f/w,
943 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
944 * (QUEUE_FULL) returned from device! --> get 0x0000?128
945 * and with SenseBytes set to 0.
946 */
947 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
948 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
949
950 }
951 else if (scsi_state &
952 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
953 ) {
954 /*
955 * What to do?
956 */
957 sc->result = DID_SOFT_ERROR << 16;
958 }
959 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
960 /* Not real sure here either... */
961 sc->result = DID_RESET << 16;
962 }
963 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
964 /* Device Inq. data indicates that it supports
965 * QTags, but rejects QTag messages.
966 * This command completed OK.
967 *
968 * Not real sure here either so do nothing... */
969 }
970
971 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
972 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
973
974 /* Add handling of:
975 * Reservation Conflict, Busy,
976 * Command Terminated, CHECK
977 */
978 break;
979
980 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
981 sc->result = DID_SOFT_ERROR << 16;
982 break;
983
984 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
985 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
986 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
987 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
989 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
991 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
992 default:
993 /*
994 * What to do?
995 */
996 sc->result = DID_SOFT_ERROR << 16;
997 break;
998
999 } /* switch(status) */
1000
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301001#ifdef CONFIG_FUSION_LOGGING
1002 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
1003 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -07001004#endif
1005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 } /* end of address reply case */
Kashyap, Desaifea98402009-09-02 11:45:53 +05301007out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001009 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 sc->scsi_done(sc); /* Issue the command callback */
1012
1013 /* Free Chain buffers */
1014 mptscsih_freeChainBuffers(ioc, req_idx);
1015 return 1;
1016}
1017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018/*
1019 * mptscsih_flush_running_cmds - For each command found, search
1020 * Scsi_Host instance taskQ and reply to OS.
1021 * Called only if recovering from a FW reload.
1022 * @hd: Pointer to a SCSI HOST structure
1023 *
1024 * Returns: None.
1025 *
1026 * Must be called while new I/Os are being queued.
1027 */
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +05301028void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
1030{
1031 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001032 struct scsi_cmnd *sc;
1033 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 int ii;
Eric Mooree8206382007-09-29 10:16:53 -06001035 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
Eric Mooree8206382007-09-29 10:16:53 -06001037 for (ii= 0; ii < ioc->req_depth; ii++) {
1038 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
1039 if (!sc)
1040 continue;
1041 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
1042 if (!mf)
1043 continue;
1044 channel = mf->Bus;
1045 id = mf->TargetID;
1046 mptscsih_freeChainBuffers(ioc, ii);
1047 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1048 if ((unsigned char *)mf != sc->host_scribble)
1049 continue;
1050 scsi_dma_unmap(sc);
1051 sc->result = DID_RESET << 16;
1052 sc->host_scribble = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301053 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
1054 "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
1055 "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
Eric Mooree8206382007-09-29 10:16:53 -06001056 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058}
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +05301059EXPORT_SYMBOL(mptscsih_flush_running_cmds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061/*
1062 * mptscsih_search_running_cmds - Delete any commands associated
1063 * with the specified target and lun. Function called only
1064 * when a lun is disable by mid-layer.
1065 * Do NOT access the referenced scsi_cmnd structure or
1066 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001067 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001068 * @hd: Pointer to a SCSI HOST structure
1069 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 *
1071 * Returns: None.
1072 *
1073 * Called from slave_destroy.
1074 */
1075static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001076mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077{
1078 SCSIIORequest_t *mf = NULL;
1079 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001080 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001081 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -06001082 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001083 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Eric Mooree8206382007-09-29 10:16:53 -06001085 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1086 for (ii = 0; ii < ioc->req_depth; ii++) {
1087 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Eric Mooree80b0022007-09-14 18:49:03 -06001089 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001090 if (mf == NULL)
1091 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001092 /* If the device is a hidden raid component, then its
1093 * expected that the mf->function will be RAID_SCSI_IO
1094 */
1095 if (vdevice->vtarget->tflags &
1096 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1097 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1098 continue;
1099
Eric Moore793955f2007-01-29 09:42:20 -07001100 int_to_scsilun(vdevice->lun, &lun);
1101 if ((mf->Bus != vdevice->vtarget->channel) ||
1102 (mf->TargetID != vdevice->vtarget->id) ||
1103 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 continue;
1105
Eric Moore3dc0b032006-07-11 17:32:33 -06001106 if ((unsigned char *)mf != sc->host_scribble)
1107 continue;
Eric Mooree8206382007-09-29 10:16:53 -06001108 ioc->ScsiLookup[ii] = NULL;
1109 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1110 mptscsih_freeChainBuffers(ioc, ii);
1111 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001112 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001113 sc->host_scribble = NULL;
1114 sc->result = DID_NO_CONNECT << 16;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301115 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
1116 MYIOC_s_FMT "completing cmds: fw_channel %d, "
1117 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
1118 vdevice->vtarget->channel, vdevice->vtarget->id,
1119 sc, mf, ii));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001120 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001121 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 }
1123 }
Eric Mooree8206382007-09-29 10:16:53 -06001124 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 return;
1126}
1127
1128/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1131/*
1132 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1133 * from a SCSI target device.
1134 * @sc: Pointer to scsi_cmnd structure
1135 * @pScsiReply: Pointer to SCSIIOReply_t
1136 * @pScsiReq: Pointer to original SCSI request
1137 *
1138 * This routine periodically reports QUEUE_FULL status returned from a
1139 * SCSI target device. It reports this to the console via kernel
1140 * printk() API call, not more than once every 10 seconds.
1141 */
1142static void
1143mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1144{
1145 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001147 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001149 if (sc->device == NULL)
1150 return;
1151 if (sc->device->host == NULL)
1152 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001153 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001154 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001155 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001157 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1158 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161}
1162
1163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1164/*
1165 * mptscsih_remove - Removed scsi devices
1166 * @pdev: Pointer to pci_dev structure
1167 *
1168 *
1169 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001170void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171mptscsih_remove(struct pci_dev *pdev)
1172{
1173 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1174 struct Scsi_Host *host = ioc->sh;
1175 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001176 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 scsi_remove_host(host);
1179
Eric Mooree7eae9f2007-09-29 10:15:59 -06001180 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001181 return;
1182
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001183 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001185 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Eric Mooree8206382007-09-29 10:16:53 -06001187 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001188 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001189 kfree(ioc->ScsiLookup);
1190 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192
Eric Mooree80b0022007-09-14 18:49:03 -06001193 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001194 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001195 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001197 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001198
1199 /* NULL the Scsi_Host pointer
1200 */
Eric Mooree80b0022007-09-14 18:49:03 -06001201 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001202
1203 scsi_host_put(host);
1204
1205 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
1209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1210/*
1211 * mptscsih_shutdown - reboot notifier
1212 *
1213 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001214void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001215mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217}
1218
1219#ifdef CONFIG_PM
1220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1221/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001222 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 *
1224 *
1225 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001226int
Pavel Machek8d189f72005-04-16 15:25:28 -07001227mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301229 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1230
1231 scsi_block_requests(ioc->sh);
1232 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001233 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235}
1236
1237/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1238/*
1239 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1240 *
1241 *
1242 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001243int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244mptscsih_resume(struct pci_dev *pdev)
1245{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301246 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1247 int rc;
1248
1249 rc = mpt_resume(pdev);
1250 scsi_unblock_requests(ioc->sh);
1251 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252}
1253
1254#endif
1255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1257/**
1258 * mptscsih_info - Return information about MPT adapter
1259 * @SChost: Pointer to Scsi_Host structure
1260 *
1261 * (linux scsi_host_template.info routine)
1262 *
1263 * Returns pointer to buffer where information was written.
1264 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001265const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266mptscsih_info(struct Scsi_Host *SChost)
1267{
1268 MPT_SCSI_HOST *h;
1269 int size = 0;
1270
Eric Mooree7eae9f2007-09-29 10:15:59 -06001271 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001274 if (h->info_kbuf == NULL)
1275 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1276 return h->info_kbuf;
1277 h->info_kbuf[0] = '\0';
1278
1279 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1280 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 }
1282
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284}
1285
1286struct info_str {
1287 char *buffer;
1288 int length;
1289 int offset;
1290 int pos;
1291};
1292
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001293static void
1294mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 if (info->pos + len > info->length)
1297 len = info->length - info->pos;
1298
1299 if (info->pos + len < info->offset) {
1300 info->pos += len;
1301 return;
1302 }
1303
1304 if (info->pos < info->offset) {
1305 data += (info->offset - info->pos);
1306 len -= (info->offset - info->pos);
1307 }
1308
1309 if (len > 0) {
1310 memcpy(info->buffer + info->pos, data, len);
1311 info->pos += len;
1312 }
1313}
1314
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001315static int
1316mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
1318 va_list args;
1319 char buf[81];
1320 int len;
1321
1322 va_start(args, fmt);
1323 len = vsprintf(buf, fmt, args);
1324 va_end(args);
1325
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001326 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 return len;
1328}
1329
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001330static int
1331mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332{
1333 struct info_str info;
1334
1335 info.buffer = pbuf;
1336 info.length = len;
1337 info.offset = offset;
1338 info.pos = 0;
1339
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001340 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1341 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1342 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1343 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1346}
1347
1348/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1349/**
1350 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001351 * @host: scsi host struct
1352 * @buffer: if write, user data; if read, buffer for user
1353 * @start: returns the buffer address
1354 * @offset: if write, 0; if read, the current offset into the buffer from
1355 * the previous read.
1356 * @length: if write, return length;
1357 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 *
1359 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001361int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1363 int length, int func)
1364{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001365 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 MPT_ADAPTER *ioc = hd->ioc;
1367 int size = 0;
1368
1369 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001370 /*
1371 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 */
1373 } else {
1374 if (start)
1375 *start = buffer;
1376
1377 size = mptscsih_host_info(ioc, buffer, offset, length);
1378 }
1379
1380 return size;
1381}
1382
1383/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1384#define ADD_INDEX_LOG(req_ent) do { } while(0)
1385
1386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1387/**
1388 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1389 * @SCpnt: Pointer to scsi_cmnd structure
1390 * @done: Pointer SCSI mid-layer IO completion function
1391 *
1392 * (linux scsi_host_template.queuecommand routine)
1393 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1394 * from a linux scsi_cmnd request and send it to the IOC.
1395 *
1396 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1397 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001398int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1400{
1401 MPT_SCSI_HOST *hd;
1402 MPT_FRAME_HDR *mf;
1403 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001404 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 u32 datalen;
1406 u32 scsictl;
1407 u32 scsidir;
1408 u32 cmd_len;
1409 int my_idx;
1410 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301411 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Eric Mooree7eae9f2007-09-29 10:15:59 -06001413 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301414 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 SCpnt->scsi_done = done;
1416
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301417 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1418 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Kashyap, Desai56cee8d2011-04-26 12:09:15 +05301420 if (ioc->taskmgmt_quiesce_io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
1423 /*
1424 * Put together a MPT SCSI request...
1425 */
Eric Mooree80b0022007-09-14 18:49:03 -06001426 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301427 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1428 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 return SCSI_MLQUEUE_HOST_BUSY;
1430 }
1431
1432 pScsiReq = (SCSIIORequest_t *) mf;
1433
1434 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1435
1436 ADD_INDEX_LOG(my_idx);
1437
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001438 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 * Seems we may receive a buffer (datalen>0) even when there
1440 * will be no data transfer! GRRRRR...
1441 */
1442 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001443 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1445 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001446 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1448 } else {
1449 datalen = 0;
1450 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1451 }
1452
1453 /* Default to untagged. Once a target structure has been allocated,
1454 * use the Inquiry data to determine if device supports tagged.
1455 */
Eric Moorea69de502007-09-14 18:48:19 -06001456 if (vdevice
1457 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 && (SCpnt->device->tagged_supported)) {
1459 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai65f89c22009-12-16 19:01:13 +05301460 if (SCpnt->request && SCpnt->request->ioprio) {
1461 if (((SCpnt->request->ioprio & 0x7) == 1) ||
1462 !(SCpnt->request->ioprio & 0x7))
1463 scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ;
1464 }
1465 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
Kashyap, Desai65f89c22009-12-16 19:01:13 +05301467
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
1469 /* Use the above information to set up the message frame
1470 */
Eric Moorea69de502007-09-14 18:48:19 -06001471 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1472 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001474 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001475 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1476 else
1477 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 pScsiReq->CDBLength = SCpnt->cmd_len;
1479 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1480 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301481 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001482 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 pScsiReq->Control = cpu_to_le32(scsictl);
1484
1485 /*
1486 * Write SCSI CDB into the message
1487 */
1488 cmd_len = SCpnt->cmd_len;
1489 for (ii=0; ii < cmd_len; ii++)
1490 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1491
1492 for (ii=cmd_len; ii < 16; ii++)
1493 pScsiReq->CDB[ii] = 0;
1494
1495 /* DataLength */
1496 pScsiReq->DataLength = cpu_to_le32(datalen);
1497
1498 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001499 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1501
1502 /* Now add the SG list
1503 * Always have a SGE even if null length.
1504 */
1505 if (datalen == 0) {
1506 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301507 ioc->add_sge((char *)&pScsiReq->SGL,
1508 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 (dma_addr_t) -1);
1510 } else {
1511 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001512 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 goto fail;
1514 }
1515
Eric Moore3dc0b032006-07-11 17:32:33 -06001516 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001517 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
Eric Mooree80b0022007-09-14 18:49:03 -06001519 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301520 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1521 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001522 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return 0;
1524
1525 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001526 mptscsih_freeChainBuffers(ioc, my_idx);
1527 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 return SCSI_MLQUEUE_HOST_BUSY;
1529}
1530
1531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1532/*
1533 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1534 * with a SCSI IO request
1535 * @hd: Pointer to the MPT_SCSI_HOST instance
1536 * @req_idx: Index of the SCSI IO request frame.
1537 *
1538 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1539 * No return.
1540 */
1541static void
1542mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1543{
1544 MPT_FRAME_HDR *chain;
1545 unsigned long flags;
1546 int chain_idx;
1547 int next;
1548
1549 /* Get the first chain index and reset
1550 * tracker state.
1551 */
1552 chain_idx = ioc->ReqToChain[req_idx];
1553 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1554
1555 while (chain_idx != MPT_HOST_NO_CHAIN) {
1556
1557 /* Save the next chain buffer index */
1558 next = ioc->ChainToChain[chain_idx];
1559
1560 /* Free this chain buffer and reset
1561 * tracker
1562 */
1563 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1564
1565 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1566 + (chain_idx * ioc->req_sz));
1567
1568 spin_lock_irqsave(&ioc->FreeQlock, flags);
1569 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1570 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1571
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301572 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 ioc->name, chain_idx));
1574
1575 /* handle next */
1576 chain_idx = next;
1577 }
1578 return;
1579}
1580
1581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1582/*
1583 * Reset Handling
1584 */
1585
1586/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001587/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1589 * @hd: Pointer to MPT_SCSI_HOST structure
1590 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001591 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001592 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 * @lun: Logical Unit for reset (if appropriate)
1594 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001595 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 *
1597 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1598 * or a non-interrupt thread. In the former, must not call schedule().
1599 *
1600 * Not all fields are meaningfull for all task types.
1601 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001602 * Returns 0 for SUCCESS, or FAILED.
1603 *
1604 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301605int
1606mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1607 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
1609 MPT_FRAME_HDR *mf;
1610 SCSITaskMgmt_t *pScsiTm;
1611 int ii;
1612 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001613 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301614 unsigned long timeleft;
1615 u8 issue_hard_reset;
1616 u32 ioc_raw_state;
1617 unsigned long time_count;
1618
1619 issue_hard_reset = 0;
1620 ioc_raw_state = mpt_GetIocState(ioc, 0);
1621
1622 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1623 printk(MYIOC_s_WARN_FMT
1624 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1625 ioc->name, type, ioc_raw_state);
1626 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1627 ioc->name, __func__);
1628 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1629 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1630 "FAILED!!\n", ioc->name);
1631 return 0;
1632 }
1633
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05301634 /* DOORBELL ACTIVE check is not required if
1635 * MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.
1636 */
1637
1638 if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)
1639 && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&
1640 (ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301641 printk(MYIOC_s_WARN_FMT
1642 "TaskMgmt type=%x: ioc_state: "
1643 "DOORBELL_ACTIVE (0x%x)!\n",
1644 ioc->name, type, ioc_raw_state);
1645 return FAILED;
1646 }
1647
1648 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1649 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1650 mf = NULL;
1651 retval = FAILED;
1652 goto out;
1653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 /* Return Fail to calling function if no message frames available.
1656 */
Eric Mooree80b0022007-09-14 18:49:03 -06001657 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301658 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1659 "TaskMgmt no msg frames!!\n", ioc->name));
1660 retval = FAILED;
1661 mpt_clear_taskmgmt_in_progress_flag(ioc);
1662 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301664 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001665 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 /* Format the Request
1668 */
1669 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001670 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 pScsiTm->Bus = channel;
1672 pScsiTm->ChainOffset = 0;
1673 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1674
1675 pScsiTm->Reserved = 0;
1676 pScsiTm->TaskType = type;
1677 pScsiTm->Reserved1 = 0;
1678 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1679 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1680
Eric Moore793955f2007-01-29 09:42:20 -07001681 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 for (ii=0; ii < 7; ii++)
1684 pScsiTm->Reserved2[ii] = 0;
1685
1686 pScsiTm->TaskMsgContext = ctx2abort;
1687
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301688 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1689 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1690 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301692 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301694 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1695 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001696 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1697 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1698 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301699 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001700 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301701 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1702 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301703 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1704 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1705 ioc->name, mf, retval));
1706 mpt_free_msg_frame(ioc, mf);
1707 mpt_clear_taskmgmt_in_progress_flag(ioc);
1708 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
1711
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301712 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1713 timeout*HZ);
1714 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1715 retval = FAILED;
1716 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1717 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1718 mpt_clear_taskmgmt_in_progress_flag(ioc);
1719 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1720 goto out;
1721 issue_hard_reset = 1;
1722 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
1724
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301725 retval = mptscsih_taskmgmt_reply(ioc, type,
1726 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001727
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301728 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1729 "TaskMgmt completed (%d seconds)\n",
1730 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1731
1732 out:
1733
1734 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1735 if (issue_hard_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09001736 printk(MYIOC_s_WARN_FMT
1737 "Issuing Reset from %s!! doorbell=0x%08x\n",
1738 ioc->name, __func__, mpt_GetIocState(ioc, 0));
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05301739 retval = (ioc->bus_type == SAS) ?
1740 mpt_HardResetHandler(ioc, CAN_SLEEP) :
1741 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301742 mpt_free_msg_frame(ioc, mf);
1743 }
1744
1745 retval = (retval == 0) ? 0 : FAILED;
1746 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 return retval;
1748}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301749EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001751static int
1752mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1753{
1754 switch (ioc->bus_type) {
1755 case FC:
1756 return 40;
1757 case SAS:
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301758 return 30;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001759 case SPI:
1760 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001761 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001762 }
1763}
1764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1766/**
1767 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1768 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1769 *
1770 * (linux scsi_host_template.eh_abort_handler routine)
1771 *
1772 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001773 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001774int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775mptscsih_abort(struct scsi_cmnd * SCpnt)
1776{
1777 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 MPT_FRAME_HDR *mf;
1779 u32 ctx2abort;
1780 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001781 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001782 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001783 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 /* If we can't locate our host adapter structure, return FAILED status.
1786 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001787 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 SCpnt->result = DID_RESET << 16;
1789 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001790 printk(KERN_ERR MYNAM ": task abort: "
1791 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 return FAILED;
1793 }
1794
Eric Moore958d4a32007-06-15 17:24:14 -06001795 ioc = hd->ioc;
1796 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1797 ioc->name, SCpnt);
1798 scsi_print_command(SCpnt);
1799
1800 vdevice = SCpnt->device->hostdata;
1801 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001802 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1803 "task abort: device has been deleted (sc=%p)\n",
1804 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001805 SCpnt->result = DID_NO_CONNECT << 16;
1806 SCpnt->scsi_done(SCpnt);
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301807 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001808 goto out;
1809 }
1810
Eric Moorecc78d302007-06-15 17:27:21 -06001811 /* Task aborts are not supported for hidden raid components.
1812 */
1813 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001814 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1815 "task abort: hidden raid component (sc=%p)\n",
1816 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001817 SCpnt->result = DID_RESET << 16;
1818 retval = FAILED;
1819 goto out;
1820 }
1821
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301822 /* Task aborts are not supported for volumes.
1823 */
1824 if (vdevice->vtarget->raidVolume) {
1825 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1826 "task abort: raid volume (sc=%p)\n",
1827 ioc->name, SCpnt));
1828 SCpnt->result = DID_RESET << 16;
1829 retval = FAILED;
1830 goto out;
1831 }
1832
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 /* Find this command
1834 */
Eric Mooree8206382007-09-29 10:16:53 -06001835 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001836 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 * Do OS callback.
1838 */
1839 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001840 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001841 "Command not in the active list! (sc=%p)\n", ioc->name,
1842 SCpnt));
Kashyap, Desai9858ae32010-01-25 16:20:52 +05301843 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001844 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 }
1846
Kashyap, Desai2f187862009-05-29 16:52:37 +05301847 if (ioc->timeouts < -1)
1848 ioc->timeouts++;
Moore, Eric65207fe2006-04-21 16:14:35 -06001849
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301850 if (mpt_fwfault_debug)
1851 mpt_halt_firmware(ioc);
1852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1854 * (the IO to be ABORT'd)
1855 *
1856 * NOTE: Since we do not byteswap MsgContext, we do not
1857 * swap it here either. It is an opaque cookie to
1858 * the controller, so it does not matter. -DaveM
1859 */
Eric Mooree80b0022007-09-14 18:49:03 -06001860 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301862 retval = mptscsih_IssueTaskMgmt(hd,
1863 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1864 vdevice->vtarget->channel,
1865 vdevice->vtarget->id, vdevice->lun,
1866 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001868 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05301869 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1870 "task abort: command still in active list! (sc=%p)\n",
1871 ioc->name, SCpnt));
Eric Moore3dc0b032006-07-11 17:32:33 -06001872 retval = FAILED;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301873 } else {
1874 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1875 "task abort: command cleared from active list! (sc=%p)\n",
1876 ioc->name, SCpnt));
1877 retval = SUCCESS;
1878 }
Eric Moore3dc0b032006-07-11 17:32:33 -06001879
Eric Moore958d4a32007-06-15 17:24:14 -06001880 out:
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001881 printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
Kashyap, Desaibcfe42e2011-02-10 11:53:44 +05301882 ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001883 SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Kashyap, Desai2f187862009-05-29 16:52:37 +05301885 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886}
1887
1888/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1889/**
1890 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1891 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1892 *
1893 * (linux scsi_host_template.eh_dev_reset_handler routine)
1894 *
1895 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001896 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001897int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1899{
1900 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001901 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001902 VirtDevice *vdevice;
1903 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
1905 /* If we can't locate our host adapter structure, return FAILED status.
1906 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001907 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001908 printk(KERN_ERR MYNAM ": target reset: "
1909 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 return FAILED;
1911 }
1912
Eric Moore958d4a32007-06-15 17:24:14 -06001913 ioc = hd->ioc;
1914 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1915 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001916 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
Eric Moore958d4a32007-06-15 17:24:14 -06001918 vdevice = SCpnt->device->hostdata;
1919 if (!vdevice || !vdevice->vtarget) {
Kashyap, Desaibcfe42e2011-02-10 11:53:44 +05301920 retval = 0;
Eric Moore958d4a32007-06-15 17:24:14 -06001921 goto out;
1922 }
1923
Eric Moorecc78d302007-06-15 17:27:21 -06001924 /* Target reset to hidden raid component is not supported
1925 */
1926 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1927 retval = FAILED;
1928 goto out;
1929 }
1930
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301931 retval = mptscsih_IssueTaskMgmt(hd,
1932 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1933 vdevice->vtarget->channel,
1934 vdevice->vtarget->id, 0, 0,
1935 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001936
1937 out:
1938 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1939 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001940
1941 if (retval == 0)
1942 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001943 else
1944 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945}
1946
Eric Moorecd2c6192007-01-29 09:47:47 -07001947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1949/**
1950 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1951 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1952 *
1953 * (linux scsi_host_template.eh_bus_reset_handler routine)
1954 *
1955 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001956 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001957int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1959{
1960 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001961 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001962 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001963 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
1965 /* If we can't locate our host adapter structure, return FAILED status.
1966 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001967 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001968 printk(KERN_ERR MYNAM ": bus reset: "
1969 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 return FAILED;
1971 }
1972
Eric Moore958d4a32007-06-15 17:24:14 -06001973 ioc = hd->ioc;
1974 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1975 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001976 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Kashyap, Desai2f187862009-05-29 16:52:37 +05301978 if (ioc->timeouts < -1)
1979 ioc->timeouts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Eric Moorea69de502007-09-14 18:48:19 -06001981 vdevice = SCpnt->device->hostdata;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301982 if (!vdevice || !vdevice->vtarget)
1983 return SUCCESS;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301984 retval = mptscsih_IssueTaskMgmt(hd,
1985 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1986 vdevice->vtarget->channel, 0, 0, 0,
1987 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Eric Moore958d4a32007-06-15 17:24:14 -06001989 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1990 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001991
1992 if (retval == 0)
1993 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001994 else
1995 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996}
1997
1998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1999/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002000 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
2002 *
2003 * (linux scsi_host_template.eh_host_reset_handler routine)
2004 *
2005 * Returns SUCCESS or FAILED.
2006 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002007int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2009{
2010 MPT_SCSI_HOST * hd;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302011 int status = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06002012 MPT_ADAPTER *ioc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302013 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
2015 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06002016 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06002017 printk(KERN_ERR MYNAM ": host reset: "
2018 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return FAILED;
2020 }
2021
James Bottomleya6da74c2008-12-15 14:13:27 -06002022 /* make sure we have no outstanding commands at this stage */
2023 mptscsih_flush_running_cmds(hd);
2024
Eric Moore958d4a32007-06-15 17:24:14 -06002025 ioc = hd->ioc;
2026 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2027 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
2029 /* If our attempts to reset the host failed, then return a failed
2030 * status. The host will be taken off line by the SCSI mid-layer.
2031 */
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302032 retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302033 if (retval < 0)
2034 status = FAILED;
2035 else
2036 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037
Eric Moore958d4a32007-06-15 17:24:14 -06002038 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2039 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
Kashyap, Desai2f187862009-05-29 16:52:37 +05302041 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042}
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302045mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
2046 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302048 u16 iocstatus;
2049 u32 termination_count;
2050 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302052 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
2053 retval = FAILED;
2054 goto out;
2055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302057 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302059 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2060 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302062 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2063 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
2064 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
2065 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
2066 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
2067 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
2068 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302070 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2071 pScsiTmReply->ResponseCode)
2072 mptscsih_taskmgmt_response_code(ioc,
2073 pScsiTmReply->ResponseCode);
2074
2075 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
2076 retval = 0;
2077 goto out;
2078 }
2079
2080 retval = FAILED;
2081 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
2082 if (termination_count == 1)
2083 retval = 0;
2084 goto out;
2085 }
2086
2087 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
2088 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
2089 retval = 0;
2090
2091 out:
2092 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093}
2094
2095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302096void
Moore, Eric9f63bb72006-01-16 18:53:26 -07002097mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2098{
2099 char *desc;
2100
2101 switch (response_code) {
2102 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2103 desc = "The task completed.";
2104 break;
2105 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2106 desc = "The IOC received an invalid frame status.";
2107 break;
2108 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2109 desc = "The task type is not supported.";
2110 break;
2111 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2112 desc = "The requested task failed.";
2113 break;
2114 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2115 desc = "The task completed successfully.";
2116 break;
2117 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2118 desc = "The LUN request is invalid.";
2119 break;
2120 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2121 desc = "The task is in the IOC queue and has not been sent to target.";
2122 break;
2123 default:
2124 desc = "unknown";
2125 break;
2126 }
2127 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2128 ioc->name, response_code, desc);
2129}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302130EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07002131
2132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133/**
2134 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2135 * @ioc: Pointer to MPT_ADAPTER structure
2136 * @mf: Pointer to SCSI task mgmt request frame
2137 * @mr: Pointer to SCSI task mgmt reply frame
2138 *
2139 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2140 * of any SCSI task management request.
2141 * This routine is registered with the MPT (base) driver at driver
2142 * load/init time via the mpt_register() API call.
2143 *
2144 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002145 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002146int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302147mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2148 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302150 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2151 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302153 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302155 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002156 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002157
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302158 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2159 memcpy(ioc->taskmgmt_cmds.reply, mr,
2160 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002161 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302162 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2163 mpt_clear_taskmgmt_in_progress_flag(ioc);
2164 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2165 complete(&ioc->taskmgmt_cmds.done);
Kashyap, Desaib68bf092010-06-17 14:40:56 +05302166 if (ioc->bus_type == SAS)
2167 ioc->schedule_target_reset(ioc);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302168 return 1;
2169 }
2170 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171}
2172
2173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2174/*
2175 * This is anyones guess quite frankly.
2176 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002177int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2179 sector_t capacity, int geom[])
2180{
2181 int heads;
2182 int sectors;
2183 sector_t cylinders;
2184 ulong dummy;
2185
2186 heads = 64;
2187 sectors = 32;
2188
2189 dummy = heads * sectors;
2190 cylinders = capacity;
2191 sector_div(cylinders,dummy);
2192
2193 /*
2194 * Handle extended translation size for logical drives
2195 * > 1Gb
2196 */
2197 if ((ulong)capacity >= 0x200000) {
2198 heads = 255;
2199 sectors = 63;
2200 dummy = heads * sectors;
2201 cylinders = capacity;
2202 sector_div(cylinders,dummy);
2203 }
2204
2205 /* return result */
2206 geom[0] = heads;
2207 geom[1] = sectors;
2208 geom[2] = cylinders;
2209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 return 0;
2211}
2212
Moore, Ericf44e5462006-03-14 09:14:21 -07002213/* Search IOC page 3 to determine if this is hidden physical disk
2214 *
2215 */
2216int
Eric Moore793955f2007-01-29 09:42:20 -07002217mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002218{
Eric Mooreb506ade2007-01-29 09:45:37 -07002219 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302220 int i, j;
2221 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002222 int rc = 0;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302223 int num_paths;
Moore, Ericf44e5462006-03-14 09:14:21 -07002224
Eric Moore793955f2007-01-29 09:42:20 -07002225 if (!ioc->raid_data.pIocPg3)
2226 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002227 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002228 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2229 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2230 rc = 1;
2231 goto out;
2232 }
2233 }
2234
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302235 if (ioc->bus_type != SAS)
2236 goto out;
2237
2238 /*
2239 * Check if dual path
2240 */
2241 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2242 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2243 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2244 if (num_paths < 2)
2245 continue;
2246 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2247 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2248 if (!phys_disk)
2249 continue;
2250 if ((mpt_raid_phys_disk_pg1(ioc,
2251 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2252 phys_disk))) {
2253 kfree(phys_disk);
2254 continue;
2255 }
2256 for (j = 0; j < num_paths; j++) {
2257 if ((phys_disk->Path[j].Flags &
2258 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2259 continue;
2260 if ((phys_disk->Path[j].Flags &
2261 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2262 continue;
2263 if ((id == phys_disk->Path[j].PhysDiskID) &&
2264 (channel == phys_disk->Path[j].PhysDiskBus)) {
2265 rc = 1;
2266 kfree(phys_disk);
2267 goto out;
2268 }
2269 }
2270 kfree(phys_disk);
2271 }
2272
2273
Eric Mooreb506ade2007-01-29 09:45:37 -07002274 /*
2275 * Check inactive list for matching phys disks
2276 */
2277 if (list_empty(&ioc->raid_data.inactive_list))
2278 goto out;
2279
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002280 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002281 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2282 list) {
2283 if ((component_info->d.PhysDiskID == id) &&
2284 (component_info->d.PhysDiskBus == channel))
2285 rc = 1;
2286 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002287 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002288
Eric Moore793955f2007-01-29 09:42:20 -07002289 out:
2290 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002291}
2292EXPORT_SYMBOL(mptscsih_is_phys_disk);
2293
Eric Moore793955f2007-01-29 09:42:20 -07002294u8
2295mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002296{
Eric Mooreb506ade2007-01-29 09:45:37 -07002297 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302298 int i, j;
2299 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002300 int rc = -ENXIO;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302301 int num_paths;
James Bottomleyc92f2222006-03-01 09:02:49 -06002302
Eric Moore793955f2007-01-29 09:42:20 -07002303 if (!ioc->raid_data.pIocPg3)
2304 goto out;
2305 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2306 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2307 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2308 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2309 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002310 }
2311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302313 if (ioc->bus_type != SAS)
2314 goto out;
2315
2316 /*
2317 * Check if dual path
2318 */
2319 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2320 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2321 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2322 if (num_paths < 2)
2323 continue;
2324 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2325 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2326 if (!phys_disk)
2327 continue;
2328 if ((mpt_raid_phys_disk_pg1(ioc,
2329 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2330 phys_disk))) {
2331 kfree(phys_disk);
2332 continue;
2333 }
2334 for (j = 0; j < num_paths; j++) {
2335 if ((phys_disk->Path[j].Flags &
2336 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2337 continue;
2338 if ((phys_disk->Path[j].Flags &
2339 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2340 continue;
2341 if ((id == phys_disk->Path[j].PhysDiskID) &&
2342 (channel == phys_disk->Path[j].PhysDiskBus)) {
2343 rc = phys_disk->PhysDiskNum;
2344 kfree(phys_disk);
2345 goto out;
2346 }
2347 }
2348 kfree(phys_disk);
2349 }
2350
Eric Mooreb506ade2007-01-29 09:45:37 -07002351 /*
2352 * Check inactive list for matching phys disks
2353 */
2354 if (list_empty(&ioc->raid_data.inactive_list))
2355 goto out;
2356
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002357 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002358 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2359 list) {
2360 if ((component_info->d.PhysDiskID == id) &&
2361 (component_info->d.PhysDiskBus == channel))
2362 rc = component_info->d.PhysDiskNum;
2363 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002364 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002365
Eric Moore793955f2007-01-29 09:42:20 -07002366 out:
2367 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368}
Eric Moore793955f2007-01-29 09:42:20 -07002369EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002370
2371/*
2372 * OS entry point to allow for host driver to free allocated memory
2373 * Called if no device present or device being unloaded
2374 */
2375void
2376mptscsih_slave_destroy(struct scsi_device *sdev)
2377{
2378 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002379 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002380 VirtTarget *vtarget;
2381 VirtDevice *vdevice;
2382 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002384 starget = scsi_target(sdev);
2385 vtarget = starget->hostdata;
2386 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05302387 if (!vdevice)
2388 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002390 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002391 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 mptscsih_synchronize_cache(hd, vdevice);
2393 kfree(vdevice);
2394 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395}
2396
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002397/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2398/*
2399 * mptscsih_change_queue_depth - This function will set a devices queue depth
2400 * @sdev: per scsi_device pointer
2401 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07002402 * @reason: calling context
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002403 *
2404 * Adding support for new 'change_queue_depth' api.
2405*/
2406int
Mike Christiee881a172009-10-15 17:46:39 -07002407mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002409 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002410 VirtTarget *vtarget;
2411 struct scsi_target *starget;
2412 int max_depth;
2413 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002414 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002416 starget = scsi_target(sdev);
2417 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002418
Mike Christiee881a172009-10-15 17:46:39 -07002419 if (reason != SCSI_QDEPTH_DEFAULT)
2420 return -EOPNOTSUPP;
2421
Eric Mooree80b0022007-09-14 18:49:03 -06002422 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002423 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002425 else if (sdev->type == TYPE_DISK &&
2426 vtarget->minSyncFactor <= MPT_ULTRA160)
2427 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2428 else
2429 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 } else
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05302431 max_depth = ioc->sh->can_queue;
2432
2433 if (!sdev->tagged_supported)
2434 max_depth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
2436 if (qdepth > max_depth)
2437 qdepth = max_depth;
2438 if (qdepth == 1)
2439 tagged = 0;
2440 else
2441 tagged = MSG_SIMPLE_TAG;
2442
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002443 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2444 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445}
2446
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447/*
2448 * OS entry point to adjust the queue_depths on a per-device basis.
2449 * Called once per device the bus scan. Use it to force the queue_depth
2450 * member to 1 if a device does not support Q tags.
2451 * Return non-zero if fails.
2452 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002453int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002454mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002456 struct Scsi_Host *sh = sdev->host;
2457 VirtTarget *vtarget;
2458 VirtDevice *vdevice;
2459 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002460 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002461 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002463 starget = scsi_target(sdev);
2464 vtarget = starget->hostdata;
2465 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
Eric Mooree80b0022007-09-14 18:49:03 -06002467 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002468 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002469 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2470 if (ioc->bus_type == SPI)
2471 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002472 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002473 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002474 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
Eric Moore793955f2007-01-29 09:42:20 -07002476 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
Eric Mooree80b0022007-09-14 18:49:03 -06002478 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002480 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
Eric Mooree80b0022007-09-14 18:49:03 -06002482 if (ioc->bus_type == SPI)
2483 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002484 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002485 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002486 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
Mike Christiee881a172009-10-15 17:46:39 -07002488 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
2489 SCSI_QDEPTH_DEFAULT);
Eric Mooree80b0022007-09-14 18:49:03 -06002490 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002492 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002493 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
Ryan Kuester2a1b7e52010-04-26 18:11:54 -05002495 blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
2496
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 return 0;
2498}
2499
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2501/*
2502 * Private routines...
2503 */
2504
2505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2506/* Utility function to copy sense data from the scsi_cmnd buffer
2507 * to the FC and SCSI target structures.
2508 *
2509 */
2510static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002511mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512{
Eric Moorea69de502007-09-14 18:48:19 -06002513 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 SCSIIORequest_t *pReq;
2515 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002516 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
2518 /* Get target structure
2519 */
2520 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002521 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 if (sense_count) {
2524 u8 *sense_data;
2525 int req_index;
2526
2527 /* Copy the sense received into the scsi command block. */
2528 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002529 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2531
2532 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2533 */
Eric Mooree80b0022007-09-14 18:49:03 -06002534 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002535 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002538 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2540 ioc->events[idx].eventContext = ioc->eventContext;
2541
Dave Jones3d9780b2007-05-21 20:59:47 -04002542 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2543 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2544 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
Dave Jones3d9780b2007-05-21 20:59:47 -04002546 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
2548 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002549 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002550 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002551 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002552 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2553 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002554 MPT_TARGET_FLAGS_LED_ON;
2555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 }
2557 }
2558 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002559 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2560 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 }
2562}
2563
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05302564/**
2565 * mptscsih_get_scsi_lookup - retrieves scmd entry
2566 * @ioc: Pointer to MPT_ADAPTER structure
2567 * @i: index into the array
2568 *
2569 * Returns the scsi_cmd pointer
2570 */
2571struct scsi_cmnd *
2572mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2573{
2574 unsigned long flags;
2575 struct scsi_cmnd *scmd;
2576
2577 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2578 scmd = ioc->ScsiLookup[i];
2579 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2580
2581 return scmd;
2582}
2583EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
Eric Mooree8206382007-09-29 10:16:53 -06002584
2585/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00002586 * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
Kashyap, Desai2f187862009-05-29 16:52:37 +05302587 * @ioc: Pointer to MPT_ADAPTER structure
2588 * @i: index into the array
2589 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002590 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302591 *
Eric Mooree8206382007-09-29 10:16:53 -06002592 **/
2593static struct scsi_cmnd *
2594mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2595{
2596 unsigned long flags;
2597 struct scsi_cmnd *scmd;
2598
2599 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2600 scmd = ioc->ScsiLookup[i];
2601 ioc->ScsiLookup[i] = NULL;
2602 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2603
2604 return scmd;
2605}
2606
2607/**
Ben Hutchings9b8f77a2010-05-23 17:02:30 -07002608 * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002609 *
2610 * @ioc: Pointer to MPT_ADAPTER structure
2611 * @i: index into the array
2612 * @scmd: scsi_cmnd pointer
2613 *
2614 **/
2615static void
2616mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2617{
2618 unsigned long flags;
2619
2620 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2621 ioc->ScsiLookup[i] = scmd;
2622 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2623}
2624
2625/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002626 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002627 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002628 * @sc: scsi_cmnd pointer
2629 */
Eric Mooree8206382007-09-29 10:16:53 -06002630static int
2631SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2632{
2633 unsigned long flags;
2634 int i, index=-1;
2635
2636 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2637 for (i = 0; i < ioc->req_depth; i++) {
2638 if (ioc->ScsiLookup[i] == sc) {
2639 index = i;
2640 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 }
2642 }
2643
Eric Mooree8206382007-09-29 10:16:53 -06002644 out:
2645 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2646 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647}
2648
2649/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002650int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2652{
2653 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
Eric Mooree7eae9f2007-09-29 10:15:59 -06002655 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302658 hd = shost_priv(ioc->sh);
2659 switch (reset_phase) {
2660 case MPT_IOC_SETUP_RESET:
2661 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2662 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302663 break;
2664 case MPT_IOC_PRE_RESET:
2665 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2666 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302667 mptscsih_flush_running_cmds(hd);
2668 break;
2669 case MPT_IOC_POST_RESET:
2670 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2671 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2672 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2673 ioc->internal_cmds.status |=
2674 MPT_MGMT_STATUS_DID_IOCRESET;
2675 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302677 break;
2678 default:
2679 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 return 1; /* currently means nothing really */
2682}
2683
2684/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002685int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2687{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2689
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302690 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2691 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2692 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
Kashyap, Desai2f187862009-05-29 16:52:37 +05302694 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2695 event == MPI_EVENT_EXT_BUS_RESET) &&
2696 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2697 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699 return 1; /* currently means nothing really */
2700}
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2703/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 * Bus Scan and Domain Validation functionality ...
2705 */
2706
2707/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2708/*
2709 * mptscsih_scandv_complete - Scan and DV callback routine registered
2710 * to Fustion MPT (base) driver.
2711 *
2712 * @ioc: Pointer to MPT_ADAPTER structure
2713 * @mf: Pointer to original MPT request frame
2714 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2715 *
2716 * This routine is called from mpt.c::mpt_interrupt() at the completion
2717 * of any SCSI IO request.
2718 * This routine is registered with the Fusion MPT (base) driver at driver
2719 * load/init time via the mpt_register() API call.
2720 *
2721 * Returns 1 indicating alloc'd request frame ptr should be freed.
2722 *
2723 * Remark: Sets a completion code and (possibly) saves sense data
2724 * in the IOC member localReply structure.
2725 * Used ONLY for DV and other internal commands.
2726 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002727int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302728mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2729 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302732 SCSIIOReply_t *pReply;
2733 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302735 u8 *sense_data;
2736 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302738 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2739 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2740 if (!reply)
2741 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002742
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302743 pReply = (SCSIIOReply_t *) reply;
2744 pReq = (SCSIIORequest_t *) req;
2745 ioc->internal_cmds.completion_code =
2746 mptscsih_get_completion_code(ioc, req, reply);
2747 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2748 memcpy(ioc->internal_cmds.reply, reply,
2749 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2750 cmd = reply->u.hdr.Function;
2751 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2752 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2753 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2754 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2755 sense_data = ((u8 *)ioc->sense_buf_pool +
2756 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2757 sz = min_t(int, pReq->SenseBufferLength,
2758 MPT_SENSE_BUFFER_ALLOC);
2759 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302761 out:
2762 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2763 return 0;
2764 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2765 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 return 1;
2767}
2768
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302770/**
Ben Hutchings9b8f77a2010-05-23 17:02:30 -07002771 * mptscsih_get_completion_code - get completion code from MPT request
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302772 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap9cf46a32009-06-13 19:37:18 -07002773 * @req: Pointer to original MPT request frame
2774 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302775 *
2776 **/
2777static int
2778mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2779 MPT_FRAME_HDR *reply)
2780{
2781 SCSIIOReply_t *pReply;
2782 MpiRaidActionReply_t *pr;
2783 u8 scsi_status;
2784 u16 status;
2785 int completion_code;
2786
2787 pReply = (SCSIIOReply_t *)reply;
2788 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2789 scsi_status = pReply->SCSIStatus;
2790
2791 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2792 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2793 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2794 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2795
2796 switch (status) {
2797
2798 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2799 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2800 break;
2801
2802 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2803 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2804 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2805 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2806 completion_code = MPT_SCANDV_DID_RESET;
2807 break;
2808
2809 case MPI_IOCSTATUS_BUSY:
2810 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2811 completion_code = MPT_SCANDV_BUSY;
2812 break;
2813
2814 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2815 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2816 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2817 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2818 completion_code = MPT_SCANDV_GOOD;
2819 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2820 pr = (MpiRaidActionReply_t *)reply;
2821 if (le16_to_cpu(pr->ActionStatus) ==
2822 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2823 completion_code = MPT_SCANDV_GOOD;
2824 else
2825 completion_code = MPT_SCANDV_SOME_ERROR;
2826 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2827 completion_code = MPT_SCANDV_SENSE;
2828 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2829 if (req->u.scsireq.CDB[0] == INQUIRY)
2830 completion_code = MPT_SCANDV_ISSUE_SENSE;
2831 else
2832 completion_code = MPT_SCANDV_DID_RESET;
2833 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2834 completion_code = MPT_SCANDV_DID_RESET;
2835 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2836 completion_code = MPT_SCANDV_DID_RESET;
2837 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2838 completion_code = MPT_SCANDV_BUSY;
2839 else
2840 completion_code = MPT_SCANDV_GOOD;
2841 break;
2842
2843 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2844 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2845 completion_code = MPT_SCANDV_DID_RESET;
2846 else
2847 completion_code = MPT_SCANDV_SOME_ERROR;
2848 break;
2849 default:
2850 completion_code = MPT_SCANDV_SOME_ERROR;
2851 break;
2852
2853 } /* switch(status) */
2854
2855 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2856 " completionCode set to %08xh\n", ioc->name, completion_code));
2857 return completion_code;
2858}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2861/**
2862 * mptscsih_do_cmd - Do internal command.
2863 * @hd: MPT_SCSI_HOST pointer
2864 * @io: INTERNAL_CMD pointer.
2865 *
2866 * Issue the specified internally generated command and do command
2867 * specific cleanup. For bus scan / DV only.
2868 * NOTES: If command is Inquiry and status is good,
2869 * initialize a target structure, save the data
2870 *
2871 * Remark: Single threaded access only.
2872 *
2873 * Return:
2874 * < 0 if an illegal command or no resources
2875 *
2876 * 0 if good
2877 *
2878 * > 0 if command complete but some type of completion error.
2879 */
2880static int
2881mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2882{
2883 MPT_FRAME_HDR *mf;
2884 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302886 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 char cmdLen;
2888 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302889 u8 cmd = io->cmd;
2890 MPT_ADAPTER *ioc = hd->ioc;
2891 int ret = 0;
2892 unsigned long timeleft;
2893 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302895 /* don't send internal command during diag reset */
2896 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2897 if (ioc->ioc_reset_in_progress) {
2898 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2899 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2900 "%s: busy with host reset\n", ioc->name, __func__));
2901 return MPT_SCANDV_BUSY;
2902 }
2903 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2904
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302905 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
2907 /* Set command specific information
2908 */
2909 switch (cmd) {
2910 case INQUIRY:
2911 cmdLen = 6;
2912 dir = MPI_SCSIIO_CONTROL_READ;
2913 CDB[0] = cmd;
2914 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302915 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 break;
2917
2918 case TEST_UNIT_READY:
2919 cmdLen = 6;
2920 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302921 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 break;
2923
2924 case START_STOP:
2925 cmdLen = 6;
2926 dir = MPI_SCSIIO_CONTROL_READ;
2927 CDB[0] = cmd;
2928 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302929 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 break;
2931
2932 case REQUEST_SENSE:
2933 cmdLen = 6;
2934 CDB[0] = cmd;
2935 CDB[4] = io->size;
2936 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302937 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 break;
2939
2940 case READ_BUFFER:
2941 cmdLen = 10;
2942 dir = MPI_SCSIIO_CONTROL_READ;
2943 CDB[0] = cmd;
2944 if (io->flags & MPT_ICFLAG_ECHO) {
2945 CDB[1] = 0x0A;
2946 } else {
2947 CDB[1] = 0x02;
2948 }
2949
2950 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2951 CDB[1] |= 0x01;
2952 }
2953 CDB[6] = (io->size >> 16) & 0xFF;
2954 CDB[7] = (io->size >> 8) & 0xFF;
2955 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302956 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 break;
2958
2959 case WRITE_BUFFER:
2960 cmdLen = 10;
2961 dir = MPI_SCSIIO_CONTROL_WRITE;
2962 CDB[0] = cmd;
2963 if (io->flags & MPT_ICFLAG_ECHO) {
2964 CDB[1] = 0x0A;
2965 } else {
2966 CDB[1] = 0x02;
2967 }
2968 CDB[6] = (io->size >> 16) & 0xFF;
2969 CDB[7] = (io->size >> 8) & 0xFF;
2970 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302971 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 break;
2973
2974 case RESERVE:
2975 cmdLen = 6;
2976 dir = MPI_SCSIIO_CONTROL_READ;
2977 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302978 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 break;
2980
2981 case RELEASE:
2982 cmdLen = 6;
2983 dir = MPI_SCSIIO_CONTROL_READ;
2984 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302985 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 break;
2987
2988 case SYNCHRONIZE_CACHE:
2989 cmdLen = 10;
2990 dir = MPI_SCSIIO_CONTROL_READ;
2991 CDB[0] = cmd;
2992// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302993 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 break;
2995
2996 default:
2997 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302998 ret = -EFAULT;
2999 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 }
3001
3002 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303003 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 */
Eric Mooree80b0022007-09-14 18:49:03 -06003005 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303006 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
3007 ioc->name, __func__));
3008 ret = MPT_SCANDV_BUSY;
3009 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 }
3011
3012 pScsiReq = (SCSIIORequest_t *) mf;
3013
3014 /* Get the request index */
3015 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3016 ADD_INDEX_LOG(my_idx); /* for debug */
3017
3018 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3019 pScsiReq->TargetID = io->physDiskNum;
3020 pScsiReq->Bus = 0;
3021 pScsiReq->ChainOffset = 0;
3022 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3023 } else {
3024 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003025 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 pScsiReq->ChainOffset = 0;
3027 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3028 }
3029
3030 pScsiReq->CDBLength = cmdLen;
3031 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3032
3033 pScsiReq->Reserved = 0;
3034
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303035 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 /* MsgContext set in mpt_get_msg_fram call */
3037
Eric Moore793955f2007-01-29 09:42:20 -07003038 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
3040 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3041 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3042 else
3043 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3044
3045 if (cmd == REQUEST_SENSE) {
3046 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303047 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3048 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 }
3050
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303051 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 pScsiReq->CDB[ii] = CDB[ii];
3053
3054 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003055 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3057
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303058 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3059 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3060 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303062 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303063 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303064 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3065 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303066 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303067 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303069 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003070 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303071 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3072 timeout*HZ);
3073 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3074 ret = MPT_SCANDV_DID_RESET;
3075 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3076 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3077 cmd));
3078 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3079 mpt_free_msg_frame(ioc, mf);
3080 goto out;
3081 }
3082 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09003083 printk(MYIOC_s_WARN_FMT
3084 "Issuing Reset from %s!! doorbell=0x%08xh"
3085 " cmd=0x%02x\n",
3086 ioc->name, __func__, mpt_GetIocState(ioc, 0),
3087 cmd);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05303088 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303089 mpt_free_msg_frame(ioc, mf);
3090 }
3091 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 }
3093
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303094 ret = ioc->internal_cmds.completion_code;
3095 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3096 ioc->name, __func__, ret));
3097
3098 out:
3099 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3100 mutex_unlock(&ioc->internal_cmds.mutex);
3101 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102}
3103
3104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3105/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003106 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3107 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003108 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003109 *
3110 * Uses the ISR, but with special processing.
3111 * MUST be single-threaded.
3112 *
3113 */
3114static void
3115mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3116{
3117 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118
Eric Moorecc78d302007-06-15 17:27:21 -06003119 /* Ignore hidden raid components, this is handled when the command
3120 * is sent to the volume
3121 */
3122 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3123 return;
3124
3125 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3126 !vdevice->configured_lun)
3127 return;
3128
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 /* Following parameters will not change
3130 * in this routine.
3131 */
3132 iocmd.cmd = SYNCHRONIZE_CACHE;
3133 iocmd.flags = 0;
3134 iocmd.physDiskNum = -1;
3135 iocmd.data = NULL;
3136 iocmd.data_dma = -1;
3137 iocmd.size = 0;
3138 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003139 iocmd.channel = vdevice->vtarget->channel;
3140 iocmd.id = vdevice->vtarget->id;
3141 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
Eric Moorecc78d302007-06-15 17:27:21 -06003143 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144}
3145
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303146static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003147mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3148 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303149{
Tony Jonesee959b02008-02-22 00:13:36 +01003150 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003151 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303152 MPT_ADAPTER *ioc = hd->ioc;
3153
3154 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3155 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3156 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3157 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3158 ioc->facts.FWVersion.Word & 0x000000FF);
3159}
Tony Jonesee959b02008-02-22 00:13:36 +01003160static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303161
3162static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003163mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3164 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303165{
Tony Jonesee959b02008-02-22 00:13:36 +01003166 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003167 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303168 MPT_ADAPTER *ioc = hd->ioc;
3169
3170 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3171 (ioc->biosVersion & 0xFF000000) >> 24,
3172 (ioc->biosVersion & 0x00FF0000) >> 16,
3173 (ioc->biosVersion & 0x0000FF00) >> 8,
3174 ioc->biosVersion & 0x000000FF);
3175}
Tony Jonesee959b02008-02-22 00:13:36 +01003176static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303177
3178static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003179mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3180 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303181{
Tony Jonesee959b02008-02-22 00:13:36 +01003182 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003183 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303184 MPT_ADAPTER *ioc = hd->ioc;
3185
3186 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3187}
Tony Jonesee959b02008-02-22 00:13:36 +01003188static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303189
3190static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003191mptscsih_version_product_show(struct device *dev,
3192 struct device_attribute *attr,
3193char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303194{
Tony Jonesee959b02008-02-22 00:13:36 +01003195 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003196 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303197 MPT_ADAPTER *ioc = hd->ioc;
3198
3199 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3200}
Tony Jonesee959b02008-02-22 00:13:36 +01003201static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303202 mptscsih_version_product_show, NULL);
3203
3204static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003205mptscsih_version_nvdata_persistent_show(struct device *dev,
3206 struct device_attribute *attr,
3207 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303208{
Tony Jonesee959b02008-02-22 00:13:36 +01003209 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003210 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303211 MPT_ADAPTER *ioc = hd->ioc;
3212
3213 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3214 ioc->nvdata_version_persistent);
3215}
Tony Jonesee959b02008-02-22 00:13:36 +01003216static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303217 mptscsih_version_nvdata_persistent_show, NULL);
3218
3219static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003220mptscsih_version_nvdata_default_show(struct device *dev,
3221 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303222{
Tony Jonesee959b02008-02-22 00:13:36 +01003223 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003224 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303225 MPT_ADAPTER *ioc = hd->ioc;
3226
3227 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3228}
Tony Jonesee959b02008-02-22 00:13:36 +01003229static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303230 mptscsih_version_nvdata_default_show, NULL);
3231
3232static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003233mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3234 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303235{
Tony Jonesee959b02008-02-22 00:13:36 +01003236 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003237 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303238 MPT_ADAPTER *ioc = hd->ioc;
3239
3240 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3241}
Tony Jonesee959b02008-02-22 00:13:36 +01003242static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303243
3244static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003245mptscsih_board_assembly_show(struct device *dev,
3246 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303247{
Tony Jonesee959b02008-02-22 00:13:36 +01003248 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003249 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303250 MPT_ADAPTER *ioc = hd->ioc;
3251
3252 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3253}
Tony Jonesee959b02008-02-22 00:13:36 +01003254static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303255 mptscsih_board_assembly_show, NULL);
3256
3257static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003258mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3259 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303260{
Tony Jonesee959b02008-02-22 00:13:36 +01003261 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003262 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303263 MPT_ADAPTER *ioc = hd->ioc;
3264
3265 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3266}
Tony Jonesee959b02008-02-22 00:13:36 +01003267static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303268 mptscsih_board_tracer_show, NULL);
3269
3270static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003271mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3272 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303273{
Tony Jonesee959b02008-02-22 00:13:36 +01003274 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003275 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303276 MPT_ADAPTER *ioc = hd->ioc;
3277
3278 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3279}
Tony Jonesee959b02008-02-22 00:13:36 +01003280static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303281 mptscsih_io_delay_show, NULL);
3282
3283static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003284mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3285 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303286{
Tony Jonesee959b02008-02-22 00:13:36 +01003287 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003288 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303289 MPT_ADAPTER *ioc = hd->ioc;
3290
3291 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3292}
Tony Jonesee959b02008-02-22 00:13:36 +01003293static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303294 mptscsih_device_delay_show, NULL);
3295
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303296static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003297mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3298 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303299{
Tony Jonesee959b02008-02-22 00:13:36 +01003300 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003301 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303302 MPT_ADAPTER *ioc = hd->ioc;
3303
3304 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3305}
3306static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003307mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3308 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303309{
Tony Jonesee959b02008-02-22 00:13:36 +01003310 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003311 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303312 MPT_ADAPTER *ioc = hd->ioc;
3313 int val = 0;
3314
3315 if (sscanf(buf, "%x", &val) != 1)
3316 return -EINVAL;
3317
3318 ioc->debug_level = val;
3319 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3320 ioc->name, ioc->debug_level);
3321 return strlen(buf);
3322}
Tony Jonesee959b02008-02-22 00:13:36 +01003323static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3324 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303325
Tony Jonesee959b02008-02-22 00:13:36 +01003326struct device_attribute *mptscsih_host_attrs[] = {
3327 &dev_attr_version_fw,
3328 &dev_attr_version_bios,
3329 &dev_attr_version_mpi,
3330 &dev_attr_version_product,
3331 &dev_attr_version_nvdata_persistent,
3332 &dev_attr_version_nvdata_default,
3333 &dev_attr_board_name,
3334 &dev_attr_board_assembly,
3335 &dev_attr_board_tracer,
3336 &dev_attr_io_delay,
3337 &dev_attr_device_delay,
3338 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303339 NULL,
3340};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303341
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303342EXPORT_SYMBOL(mptscsih_host_attrs);
3343
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003344EXPORT_SYMBOL(mptscsih_remove);
3345EXPORT_SYMBOL(mptscsih_shutdown);
3346#ifdef CONFIG_PM
3347EXPORT_SYMBOL(mptscsih_suspend);
3348EXPORT_SYMBOL(mptscsih_resume);
3349#endif
3350EXPORT_SYMBOL(mptscsih_proc_info);
3351EXPORT_SYMBOL(mptscsih_info);
3352EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003353EXPORT_SYMBOL(mptscsih_slave_destroy);
3354EXPORT_SYMBOL(mptscsih_slave_configure);
3355EXPORT_SYMBOL(mptscsih_abort);
3356EXPORT_SYMBOL(mptscsih_dev_reset);
3357EXPORT_SYMBOL(mptscsih_bus_reset);
3358EXPORT_SYMBOL(mptscsih_host_reset);
3359EXPORT_SYMBOL(mptscsih_bios_param);
3360EXPORT_SYMBOL(mptscsih_io_done);
3361EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3362EXPORT_SYMBOL(mptscsih_scandv_complete);
3363EXPORT_SYMBOL(mptscsih_event_process);
3364EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003365EXPORT_SYMBOL(mptscsih_change_queue_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003367/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/