[SCSI] mpt fusion: cleanup eh handlers
[linux-2.6-block.git] / drivers / message / fusion / mptscsih.c
CommitLineData
1da177e4
LT
1/*
2 * linux/drivers/message/fusion/mptscsih.c
0d0c7974 3 * For use with LSI Logic PCI chip/adapter(s)
1da177e4
LT
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
9f4203b3 6 * Copyright (c) 1999-2007 LSI Logic Corporation
16d20101 7 * (mailto:DL-MPTFusionLinux@lsi.com)
1da177e4 8 *
1da177e4
LT
9 */
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
1da177e4
LT
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
1da177e4
LT
56#include <linux/workqueue.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
e0fc15be 63#include <scsi/scsi_dbg.h>
1da177e4
LT
64
65#include "mptbase.h"
66#include "mptscsih.h"
bf451522 67#include "lsi/mpi_log_sas.h"
1da177e4
LT
68
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
9f4203b3 77MODULE_VERSION(my_VERSION);
1da177e4 78
1da177e4 79/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1da177e4
LT
80/*
81 * Other private/forward protos...
82 */
0d0c7974 83int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1da177e4 84static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
0d0c7974 85int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1da177e4
LT
86
87static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
88 SCSIIORequest_t *pReq, int req_idx);
89static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
0d0c7974 90static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
1da177e4
LT
91static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
92static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
3dc0b03f 93static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
1da177e4 94
793955f5 95static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
1da177e4 96
0d0c7974
MED
97int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
98int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
1da177e4 99
0d0c7974 100int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1da177e4 101static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
c7c82987 102static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
1da177e4 103
0d0c7974 104void mptscsih_remove(struct pci_dev *);
d18c3db5 105void mptscsih_shutdown(struct pci_dev *);
1da177e4 106#ifdef CONFIG_PM
0d0c7974
MED
107int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
108int mptscsih_resume(struct pci_dev *pdev);
1da177e4
LT
109#endif
110
1da177e4
LT
111#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
112
1da177e4
LT
113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
114/**
115 * mptscsih_add_sge - Place a simple SGE at address pAddr.
116 * @pAddr: virtual address for SGE
117 * @flagslength: SGE flags and data transfer length
118 * @dma_addr: Physical address
119 *
120 * This routine places a MPT request frame back on the MPT adapter's
121 * FreeQ.
122 */
123static inline void
124mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
125{
126 if (sizeof(dma_addr_t) == sizeof(u64)) {
127 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
128 u32 tmp = dma_addr & 0xFFFFFFFF;
129
130 pSge->FlagsLength = cpu_to_le32(flagslength);
131 pSge->Address.Low = cpu_to_le32(tmp);
132 tmp = (u32) ((u64)dma_addr >> 32);
133 pSge->Address.High = cpu_to_le32(tmp);
134
135 } else {
136 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
137 pSge->FlagsLength = cpu_to_le32(flagslength);
138 pSge->Address = cpu_to_le32(dma_addr);
139 }
140} /* mptscsih_add_sge() */
141
142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
143/**
144 * mptscsih_add_chain - Place a chain SGE at address pAddr.
145 * @pAddr: virtual address for SGE
146 * @next: nextChainOffset value (u32's)
147 * @length: length of next SGL segment
148 * @dma_addr: Physical address
149 *
150 * This routine places a MPT request frame back on the MPT adapter's
151 * FreeQ.
152 */
153static inline void
154mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
155{
156 if (sizeof(dma_addr_t) == sizeof(u64)) {
157 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
158 u32 tmp = dma_addr & 0xFFFFFFFF;
159
160 pChain->Length = cpu_to_le16(length);
161 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
162
163 pChain->NextChainOffset = next;
164
165 pChain->Address.Low = cpu_to_le32(tmp);
166 tmp = (u32) ((u64)dma_addr >> 32);
167 pChain->Address.High = cpu_to_le32(tmp);
168 } else {
169 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
170 pChain->Length = cpu_to_le16(length);
171 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
172 pChain->NextChainOffset = next;
173 pChain->Address = cpu_to_le32(dma_addr);
174 }
175} /* mptscsih_add_chain() */
176
177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
178/*
179 * mptscsih_getFreeChainBuffer - Function to get a free chain
180 * from the MPT_SCSI_HOST FreeChainQ.
181 * @ioc: Pointer to MPT_ADAPTER structure
182 * @req_idx: Index of the SCSI IO request frame. (output)
183 *
184 * return SUCCESS or FAILED
185 */
186static inline int
187mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
188{
189 MPT_FRAME_HDR *chainBuf;
190 unsigned long flags;
191 int rc;
192 int chain_idx;
193
194 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
195 ioc->name));
196 spin_lock_irqsave(&ioc->FreeQlock, flags);
197 if (!list_empty(&ioc->FreeChainQ)) {
198 int offset;
199
200 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
201 u.frame.linkage.list);
202 list_del(&chainBuf->u.frame.linkage.list);
203 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
204 chain_idx = offset / ioc->req_sz;
205 rc = SUCCESS;
c6678e0c
CH
206 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
207 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
1da177e4
LT
208 } else {
209 rc = FAILED;
210 chain_idx = MPT_HOST_NO_CHAIN;
c6678e0c 211 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
1da177e4
LT
212 ioc->name));
213 }
214 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
215
216 *retIndex = chain_idx;
217 return rc;
218} /* mptscsih_getFreeChainBuffer() */
219
220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
221/*
222 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
223 * SCSIIORequest_t Message Frame.
224 * @ioc: Pointer to MPT_ADAPTER structure
225 * @SCpnt: Pointer to scsi_cmnd structure
226 * @pReq: Pointer to SCSIIORequest_t structure
227 *
228 * Returns ...
229 */
230static int
231mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
232 SCSIIORequest_t *pReq, int req_idx)
233{
234 char *psge;
235 char *chainSge;
236 struct scatterlist *sg;
237 int frm_sz;
238 int sges_left, sg_done;
239 int chain_idx = MPT_HOST_NO_CHAIN;
240 int sgeOffset;
241 int numSgeSlots, numSgeThisFrame;
242 u32 sgflags, sgdir, thisxfer = 0;
243 int chain_dma_off = 0;
244 int newIndex;
245 int ii;
246 dma_addr_t v2;
247 u32 RequestNB;
248
249 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
250 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
251 sgdir = MPT_TRANSFER_HOST_TO_IOC;
252 } else {
253 sgdir = MPT_TRANSFER_IOC_TO_HOST;
254 }
255
256 psge = (char *) &pReq->SGL;
257 frm_sz = ioc->req_sz;
258
259 /* Map the data portion, if any.
260 * sges_left = 0 if no data transfer.
261 */
1928d73f
FT
262 sges_left = scsi_dma_map(SCpnt);
263 if (sges_left < 0)
264 return FAILED;
1da177e4
LT
265
266 /* Handle the SG case.
267 */
1928d73f 268 sg = scsi_sglist(SCpnt);
1da177e4
LT
269 sg_done = 0;
270 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
271 chainSge = NULL;
272
273 /* Prior to entering this loop - the following must be set
274 * current MF: sgeOffset (bytes)
275 * chainSge (Null if original MF is not a chain buffer)
276 * sg_done (num SGE done for this MF)
277 */
278
279nextSGEset:
280 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
281 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
282
283 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
284
285 /* Get first (num - 1) SG elements
286 * Skip any SG entries with a length of 0
287 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
288 */
289 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
290 thisxfer = sg_dma_len(sg);
291 if (thisxfer == 0) {
292 sg ++; /* Get next SG element from the OS */
293 sg_done++;
294 continue;
295 }
296
297 v2 = sg_dma_address(sg);
298 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
299
300 sg++; /* Get next SG element from the OS */
301 psge += (sizeof(u32) + sizeof(dma_addr_t));
302 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
303 sg_done++;
304 }
305
306 if (numSgeThisFrame == sges_left) {
307 /* Add last element, end of buffer and end of list flags.
308 */
309 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
310 MPT_SGE_FLAGS_END_OF_BUFFER |
311 MPT_SGE_FLAGS_END_OF_LIST;
312
313 /* Add last SGE and set termination flags.
314 * Note: Last SGE may have a length of 0 - which should be ok.
315 */
316 thisxfer = sg_dma_len(sg);
317
318 v2 = sg_dma_address(sg);
319 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
320 /*
321 sg++;
322 psge += (sizeof(u32) + sizeof(dma_addr_t));
323 */
324 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
325 sg_done++;
326
327 if (chainSge) {
328 /* The current buffer is a chain buffer,
329 * but there is not another one.
330 * Update the chain element
331 * Offset and Length fields.
332 */
333 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
334 } else {
335 /* The current buffer is the original MF
336 * and there is no Chain buffer.
337 */
338 pReq->ChainOffset = 0;
339 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
c6678e0c 340 dsgprintk((MYIOC_s_INFO_FMT
1da177e4
LT
341 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
342 ioc->RequestNB[req_idx] = RequestNB;
343 }
344 } else {
345 /* At least one chain buffer is needed.
346 * Complete the first MF
347 * - last SGE element, set the LastElement bit
348 * - set ChainOffset (words) for orig MF
349 * (OR finish previous MF chain buffer)
350 * - update MFStructPtr ChainIndex
351 * - Populate chain element
352 * Also
353 * Loop until done.
354 */
355
356 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
357 ioc->name, sg_done));
358
359 /* Set LAST_ELEMENT flag for last non-chain element
360 * in the buffer. Since psge points at the NEXT
361 * SGE element, go back one SGE element, update the flags
362 * and reset the pointer. (Note: sgflags & thisxfer are already
363 * set properly).
364 */
365 if (sg_done) {
366 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
367 sgflags = le32_to_cpu(*ptmp);
368 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
369 *ptmp = cpu_to_le32(sgflags);
370 }
371
372 if (chainSge) {
373 /* The current buffer is a chain buffer.
374 * chainSge points to the previous Chain Element.
375 * Update its chain element Offset and Length (must
376 * include chain element size) fields.
377 * Old chain element is now complete.
378 */
379 u8 nextChain = (u8) (sgeOffset >> 2);
380 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
381 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
382 } else {
383 /* The original MF buffer requires a chain buffer -
384 * set the offset.
385 * Last element in this MF is a chain element.
386 */
387 pReq->ChainOffset = (u8) (sgeOffset >> 2);
388 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
389 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
390 ioc->RequestNB[req_idx] = RequestNB;
391 }
392
393 sges_left -= sg_done;
394
395
396 /* NOTE: psge points to the beginning of the chain element
397 * in current buffer. Get a chain buffer.
398 */
c6678e0c
CH
399 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
400 dfailprintk((MYIOC_s_INFO_FMT
401 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
402 ioc->name, pReq->CDB[0], SCpnt));
1da177e4 403 return FAILED;
c6678e0c 404 }
1da177e4
LT
405
406 /* Update the tracking arrays.
407 * If chainSge == NULL, update ReqToChain, else ChainToChain
408 */
409 if (chainSge) {
410 ioc->ChainToChain[chain_idx] = newIndex;
411 } else {
412 ioc->ReqToChain[req_idx] = newIndex;
413 }
414 chain_idx = newIndex;
415 chain_dma_off = ioc->req_sz * chain_idx;
416
417 /* Populate the chainSGE for the current buffer.
418 * - Set chain buffer pointer to psge and fill
419 * out the Address and Flags fields.
420 */
421 chainSge = (char *) psge;
422 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
423 psge, req_idx));
424
425 /* Start the SGE for the next buffer
426 */
427 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
428 sgeOffset = 0;
429 sg_done = 0;
430
431 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
432 psge, chain_idx));
433
434 /* Start the SGE for the next buffer
435 */
436
437 goto nextSGEset;
438 }
439
440 return SUCCESS;
441} /* mptscsih_AddSGE() */
442
786899b0
EM
443static void
444mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
445 U32 SlotStatus)
446{
447 MPT_FRAME_HDR *mf;
448 SEPRequest_t *SEPMsg;
449
450 if (ioc->bus_type == FC)
451 return;
452
453 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
454 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
455 ioc->name,__FUNCTION__));
456 return;
457 }
458
459 SEPMsg = (SEPRequest_t *)mf;
460 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
793955f5
EM
461 SEPMsg->Bus = vtarget->channel;
462 SEPMsg->TargetID = vtarget->id;
786899b0
EM
463 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
464 SEPMsg->SlotStatus = SlotStatus;
465 devtverboseprintk((MYIOC_s_WARN_FMT
793955f5
EM
466 "Sending SEP cmd=%x channel=%d id=%d\n",
467 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
786899b0
EM
468 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
469}
470
c6c727a1
EM
471#ifdef MPT_DEBUG_REPLY
472/**
473 * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
474 * @ioc: Pointer to MPT_ADAPTER structure
475 * @ioc_status: U32 IOCStatus word from IOC
476 * @scsi_status: U8 sam status from target
477 * @scsi_state: U8 scsi state
478 * @sc: original scsi cmnd pointer
479 * @mf: Pointer to MPT request frame
480 *
481 * Refer to lsi/mpi.h.
482 **/
483static void
484mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
485 u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
486{
487 char extend_desc[EVENT_DESCR_STR_SZ];
488 char *desc = NULL;
489
490 switch (ioc_status) {
491
492 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
493 desc = "SCSI Invalid Bus";
494 break;
495
496 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
497 desc = "SCSI Invalid TargetID";
498 break;
499
500 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
501 /*
502 * Inquiry is issued for device scanning
503 */
504 if (sc->cmnd[0] != 0x12)
505 desc = "SCSI Device Not There";
506 break;
507
508 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
509 desc = "SCSI Data Overrun";
510 break;
511
512 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
513 desc = "SCSI I/O Data Error";
514 break;
515
516 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
517 desc = "SCSI Protocol Error";
518 break;
519
520 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
521 desc = "SCSI Task Terminated";
522 break;
523
524 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
525 desc = "SCSI Residual Mismatch";
526 break;
527
528 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
529 desc = "SCSI Task Management Failed";
530 break;
531
532 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
533 desc = "SCSI IOC Terminated";
534 break;
535
536 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
537 desc = "SCSI Ext Terminated";
538 break;
539 }
540
541 if (!desc)
542 return;
543
544 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
545 "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
546 sc->device->host->host_no,
547 sc->device->channel, sc->device->id, sc->device->lun,
548 sc->cmnd[0], scsi_status, scsi_state);
549
550 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
551 ioc->name, ioc_status, desc, extend_desc);
552}
553#endif
554
1da177e4
LT
555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
556/*
557 * mptscsih_io_done - Main SCSI IO callback routine registered to
558 * Fusion MPT (base) driver
559 * @ioc: Pointer to MPT_ADAPTER structure
560 * @mf: Pointer to original MPT request frame
561 * @r: Pointer to MPT reply frame (NULL if TurboReply)
562 *
563 * This routine is called from mpt.c::mpt_interrupt() at the completion
564 * of any SCSI IO request.
565 * This routine is registered with the Fusion MPT (base) driver at driver
566 * load/init time via the mpt_register() API call.
567 *
568 * Returns 1 indicating alloc'd request frame ptr should be freed.
569 */
0d0c7974 570int
1da177e4
LT
571mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
572{
573 struct scsi_cmnd *sc;
574 MPT_SCSI_HOST *hd;
575 SCSIIORequest_t *pScsiReq;
576 SCSIIOReply_t *pScsiReply;
2254c86d 577 u16 req_idx, req_idx_MR;
786899b0
EM
578 VirtDevice *vdev;
579 VirtTarget *vtarget;
1da177e4
LT
580
581 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
582
583 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2254c86d
ME
584 req_idx_MR = (mr != NULL) ?
585 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
586 if ((req_idx != req_idx_MR) ||
587 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
588 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
589 ioc->name);
590 printk (MYIOC_s_ERR_FMT
591 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
592 ioc->name, req_idx, req_idx_MR, mf, mr,
593 hd->ScsiLookup[req_idx_MR]);
594 return 0;
595 }
596
1da177e4 597 sc = hd->ScsiLookup[req_idx];
3dc0b03f 598 hd->ScsiLookup[req_idx] = NULL;
1da177e4
LT
599 if (sc == NULL) {
600 MPIHeader_t *hdr = (MPIHeader_t *)mf;
601
602 /* Remark: writeSDP1 will use the ScsiDoneCtx
603 * If a SCSI I/O cmd, device disabled by OS and
604 * completion done. Cannot touch sc struct. Just free mem.
605 */
606 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
607 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
608 ioc->name);
609
610 mptscsih_freeChainBuffers(ioc, req_idx);
611 return 1;
612 }
613
3dc0b03f
EM
614 if ((unsigned char *)mf != sc->host_scribble) {
615 mptscsih_freeChainBuffers(ioc, req_idx);
616 return 1;
617 }
618
619 sc->host_scribble = NULL;
1da177e4
LT
620 sc->result = DID_OK << 16; /* Set default reply as OK */
621 pScsiReq = (SCSIIORequest_t *) mf;
622 pScsiReply = (SCSIIOReply_t *) mr;
623
c6678e0c
CH
624 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
625 dmfprintk((MYIOC_s_INFO_FMT
626 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
627 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
628 }else{
629 dmfprintk((MYIOC_s_INFO_FMT
630 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
631 ioc->name, mf, mr, sc, req_idx));
632 }
633
1da177e4
LT
634 if (pScsiReply == NULL) {
635 /* special context reply handling */
636 ;
637 } else {
638 u32 xfer_cnt;
639 u16 status;
640 u8 scsi_state, scsi_status;
c6c727a1 641 u32 log_info;
1da177e4
LT
642
643 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
644 scsi_state = pScsiReply->SCSIState;
645 scsi_status = pScsiReply->SCSIStatus;
646 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
1928d73f 647 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
c6c727a1 648 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
1da177e4 649
466544d8
MED
650 /*
651 * if we get a data underrun indication, yet no data was
652 * transferred and the SCSI status indicates that the
653 * command was never started, change the data underrun
654 * to success
655 */
656 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
657 (scsi_status == MPI_SCSI_STATUS_BUSY ||
658 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
659 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
660 status = MPI_IOCSTATUS_SUCCESS;
661 }
662
1da177e4 663 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
0d0c7974
MED
664 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
665
1da177e4
LT
666 /*
667 * Look for + dump FCP ResponseInfo[]!
668 */
466544d8
MED
669 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
670 pScsiReply->ResponseInfo) {
c6c727a1 671 printk(KERN_NOTICE "[%d:%d:%d:%d] "
466544d8 672 "FCP_ResponseInfo=%08xh\n",
c6c727a1
EM
673 sc->device->host->host_no, sc->device->channel,
674 sc->device->id, sc->device->lun,
1da177e4
LT
675 le32_to_cpu(pScsiReply->ResponseInfo));
676 }
677
678 switch(status) {
679 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
680 /* CHECKME!
681 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
682 * But not: DID_BUS_BUSY lest one risk
683 * killing interrupt handler:-(
684 */
685 sc->result = SAM_STAT_BUSY;
686 break;
687
688 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
689 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
690 sc->result = DID_BAD_TARGET << 16;
691 break;
692
693 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
694 /* Spoof to SCSI Selection Timeout! */
65207fed
ME
695 if (ioc->bus_type != FC)
696 sc->result = DID_NO_CONNECT << 16;
697 /* else fibre, just stall until rescan event */
698 else
699 sc->result = DID_REQUEUE << 16;
1da177e4
LT
700
701 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
702 hd->sel_timeout[pScsiReq->TargetID]++;
786899b0
EM
703
704 vdev = sc->device->hostdata;
705 if (!vdev)
706 break;
707 vtarget = vdev->vtarget;
708 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
709 mptscsih_issue_sep_command(ioc, vtarget,
710 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
711 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
712 }
1da177e4
LT
713 break;
714
1da177e4 715 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
bf451522
EM
716 if ( ioc->bus_type == SAS ) {
717 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
718 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
c6c727a1
EM
719 if ((log_info & SAS_LOGINFO_MASK)
720 == SAS_LOGINFO_NEXUS_LOSS) {
bf451522
EM
721 sc->result = (DID_BUS_BUSY << 16);
722 break;
723 }
724 }
86dd4242
EM
725 } else if (ioc->bus_type == FC) {
726 /*
727 * The FC IOC may kill a request for variety of
728 * reasons, some of which may be recovered by a
729 * retry, some which are unlikely to be
730 * recovered. Return DID_ERROR instead of
731 * DID_RESET to permit retry of the command,
732 * just not an infinite number of them
733 */
734 sc->result = DID_ERROR << 16;
735 break;
bf451522
EM
736 }
737
738 /*
739 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
740 */
741
742 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
1da177e4
LT
743 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
744 /* Linux handles an unsolicited DID_RESET better
745 * than an unsolicited DID_ABORT.
746 */
747 sc->result = DID_RESET << 16;
748
1da177e4
LT
749 break;
750
751 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
1928d73f 752 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
466544d8
MED
753 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
754 sc->result=DID_SOFT_ERROR << 16;
755 else /* Sufficient data transfer occurred */
1da177e4 756 sc->result = (DID_OK << 16) | scsi_status;
3dc0b03f 757 dreplyprintk((KERN_NOTICE
c6c727a1
EM
758 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
759 sc->result, sc->device->channel, sc->device->id));
1da177e4 760 break;
0d0c7974 761
1da177e4
LT
762 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
763 /*
764 * Do upfront check for valid SenseData and give it
765 * precedence!
766 */
767 sc->result = (DID_OK << 16) | scsi_status;
768 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
769 /* Have already saved the status and sense data
770 */
771 ;
772 } else {
773 if (xfer_cnt < sc->underflow) {
466544d8
MED
774 if (scsi_status == SAM_STAT_BUSY)
775 sc->result = SAM_STAT_BUSY;
776 else
777 sc->result = DID_SOFT_ERROR << 16;
1da177e4
LT
778 }
779 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
780 /* What to do?
781 */
782 sc->result = DID_SOFT_ERROR << 16;
783 }
784 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
785 /* Not real sure here either... */
786 sc->result = DID_RESET << 16;
787 }
788 }
789
790 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
791 sc->underflow));
792 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
793 /* Report Queue Full
794 */
795 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
796 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
0d0c7974 797
1da177e4
LT
798 break;
799
7e55147f 800 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
1928d73f 801 scsi_set_resid(sc, 0);
1da177e4
LT
802 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
803 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
ad8c31bb 804 sc->result = (DID_OK << 16) | scsi_status;
1da177e4
LT
805 if (scsi_state == 0) {
806 ;
807 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
808 /*
809 * If running against circa 200003dd 909 MPT f/w,
810 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
811 * (QUEUE_FULL) returned from device! --> get 0x0000?128
812 * and with SenseBytes set to 0.
813 */
814 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
815 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
816
817 }
818 else if (scsi_state &
819 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
820 ) {
821 /*
822 * What to do?
823 */
824 sc->result = DID_SOFT_ERROR << 16;
825 }
826 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
827 /* Not real sure here either... */
828 sc->result = DID_RESET << 16;
829 }
830 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
831 /* Device Inq. data indicates that it supports
832 * QTags, but rejects QTag messages.
833 * This command completed OK.
834 *
835 * Not real sure here either so do nothing... */
836 }
837
838 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
839 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
840
841 /* Add handling of:
842 * Reservation Conflict, Busy,
843 * Command Terminated, CHECK
844 */
845 break;
846
847 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
848 sc->result = DID_SOFT_ERROR << 16;
849 break;
850
851 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
852 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
853 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
854 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
855 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
856 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
857 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
1da177e4
LT
858 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
859 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
860 default:
861 /*
862 * What to do?
863 */
864 sc->result = DID_SOFT_ERROR << 16;
865 break;
866
867 } /* switch(status) */
868
c6c727a1
EM
869#ifdef MPT_DEBUG_REPLY
870 if (sc->result) {
871
872 mptscsih_iocstatus_info_scsiio(ioc, status,
873 scsi_status, scsi_state, sc);
874
875 dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
876 "result=0x%08x\n\tiocstatus=0x%04X "
877 "scsi_state=0x%02X scsi_status=0x%02X "
878 "loginfo=0x%08X\n", __FUNCTION__,
879 sc->device->host->host_no, sc->device->channel, sc->device->id,
880 sc->device->lun, sc->cmnd[0], sc->result, status,
881 scsi_state, scsi_status, log_info));
882
883 dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
1928d73f
FT
884 "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
885 sc->device->host->host_no,
886 sc->device->channel, sc->device->id,
887 sc->device->lun, scsi_get_resid(sc),
888 scsi_bufflen(sc), xfer_cnt));
c6c727a1
EM
889 }
890#endif
891
1da177e4
LT
892 } /* end of address reply case */
893
894 /* Unmap the DMA buffers, if any. */
1928d73f 895 scsi_dma_unmap(sc);
1da177e4 896
1da177e4
LT
897 sc->scsi_done(sc); /* Issue the command callback */
898
899 /* Free Chain buffers */
900 mptscsih_freeChainBuffers(ioc, req_idx);
901 return 1;
902}
903
1da177e4
LT
904/*
905 * mptscsih_flush_running_cmds - For each command found, search
906 * Scsi_Host instance taskQ and reply to OS.
907 * Called only if recovering from a FW reload.
908 * @hd: Pointer to a SCSI HOST structure
909 *
910 * Returns: None.
911 *
912 * Must be called while new I/Os are being queued.
913 */
914static void
915mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
916{
917 MPT_ADAPTER *ioc = hd->ioc;
918 struct scsi_cmnd *SCpnt;
919 MPT_FRAME_HDR *mf;
920 int ii;
921 int max = ioc->req_depth;
922
923 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
924 for (ii= 0; ii < max; ii++) {
925 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
926
927 /* Command found.
928 */
929
930 /* Null ScsiLookup index
931 */
932 hd->ScsiLookup[ii] = NULL;
933
934 mf = MPT_INDEX_2_MFPTR(ioc, ii);
935 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
936 mf, SCpnt));
937
3dc0b03f
EM
938 /* Free Chain buffers */
939 mptscsih_freeChainBuffers(ioc, ii);
940
941 /* Free Message frames */
942 mpt_free_msg_frame(ioc, mf);
943
944 if ((unsigned char *)mf != SCpnt->host_scribble)
945 continue;
946
1da177e4
LT
947 /* Set status, free OS resources (SG DMA buffers)
948 * Do OS callback
1da177e4 949 */
1928d73f
FT
950 scsi_dma_unmap(SCpnt);
951
1da177e4
LT
952 SCpnt->result = DID_RESET << 16;
953 SCpnt->host_scribble = NULL;
954
1da177e4
LT
955 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
956 }
957 }
958
959 return;
960}
961
962/*
963 * mptscsih_search_running_cmds - Delete any commands associated
964 * with the specified target and lun. Function called only
965 * when a lun is disable by mid-layer.
966 * Do NOT access the referenced scsi_cmnd structure or
967 * members. Will cause either a paging or NULL ptr error.
05e8ec17 968 * (BUT, BUT, BUT, the code does reference it! - mdr)
c7c82987
MED
969 * @hd: Pointer to a SCSI HOST structure
970 * @vdevice: per device private data
1da177e4
LT
971 *
972 * Returns: None.
973 *
974 * Called from slave_destroy.
975 */
976static void
c7c82987 977mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
1da177e4
LT
978{
979 SCSIIORequest_t *mf = NULL;
980 int ii;
981 int max = hd->ioc->req_depth;
466544d8 982 struct scsi_cmnd *sc;
793955f5 983 struct scsi_lun lun;
1da177e4 984
793955f5
EM
985 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
986 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
1da177e4
LT
987
988 for (ii=0; ii < max; ii++) {
466544d8 989 if ((sc = hd->ScsiLookup[ii]) != NULL) {
1da177e4
LT
990
991 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
3dc0b03f
EM
992 if (mf == NULL)
993 continue;
793955f5
EM
994 int_to_scsilun(vdevice->lun, &lun);
995 if ((mf->Bus != vdevice->vtarget->channel) ||
996 (mf->TargetID != vdevice->vtarget->id) ||
997 memcmp(lun.scsi_lun, mf->LUN, 8))
1da177e4 998 continue;
793955f5
EM
999 dsprintk(( "search_running: found (sc=%p, mf = %p) "
1000 "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
1001 mf, mf->Bus, mf->TargetID, vdevice->lun));
1da177e4
LT
1002
1003 /* Cleanup
1004 */
1005 hd->ScsiLookup[ii] = NULL;
1006 mptscsih_freeChainBuffers(hd->ioc, ii);
1007 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
3dc0b03f
EM
1008 if ((unsigned char *)mf != sc->host_scribble)
1009 continue;
1928d73f
FT
1010 scsi_dma_unmap(sc);
1011
466544d8
MED
1012 sc->host_scribble = NULL;
1013 sc->result = DID_NO_CONNECT << 16;
1014 sc->scsi_done(sc);
1da177e4
LT
1015 }
1016 }
1da177e4
LT
1017 return;
1018}
1019
1020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1da177e4
LT
1021
1022/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1023/*
1024 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1025 * from a SCSI target device.
1026 * @sc: Pointer to scsi_cmnd structure
1027 * @pScsiReply: Pointer to SCSIIOReply_t
1028 * @pScsiReq: Pointer to original SCSI request
1029 *
1030 * This routine periodically reports QUEUE_FULL status returned from a
1031 * SCSI target device. It reports this to the console via kernel
1032 * printk() API call, not more than once every 10 seconds.
1033 */
1034static void
1035mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1036{
1037 long time = jiffies;
1da177e4 1038 MPT_SCSI_HOST *hd;
1da177e4 1039
0d0c7974
MED
1040 if (sc->device == NULL)
1041 return;
1042 if (sc->device->host == NULL)
1043 return;
1044 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1045 return;
1da177e4 1046
0d0c7974
MED
1047 if (time - hd->last_queue_full > 10 * HZ) {
1048 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1049 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1050 hd->last_queue_full = time;
1da177e4 1051 }
1da177e4
LT
1052}
1053
1054/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1055/*
1056 * mptscsih_remove - Removed scsi devices
1057 * @pdev: Pointer to pci_dev structure
1058 *
1059 *
1060 */
0d0c7974 1061void
1da177e4
LT
1062mptscsih_remove(struct pci_dev *pdev)
1063{
1064 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1065 struct Scsi_Host *host = ioc->sh;
1066 MPT_SCSI_HOST *hd;
0d0c7974 1067 int sz1;
1da177e4 1068
466544d8
MED
1069 if(!host) {
1070 mpt_detach(pdev);
1da177e4 1071 return;
466544d8 1072 }
1da177e4
LT
1073
1074 scsi_remove_host(host);
1075
0d0c7974
MED
1076 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1077 return;
1078
d18c3db5 1079 mptscsih_shutdown(pdev);
1da177e4 1080
0d0c7974 1081 sz1=0;
1da177e4 1082
0d0c7974
MED
1083 if (hd->ScsiLookup != NULL) {
1084 sz1 = hd->ioc->req_depth * sizeof(void *);
1085 kfree(hd->ScsiLookup);
1086 hd->ScsiLookup = NULL;
1087 }
1da177e4 1088
0d0c7974
MED
1089 dprintk((MYIOC_s_INFO_FMT
1090 "Free'd ScsiLookup (%d) memory\n",
1091 hd->ioc->name, sz1));
1da177e4 1092
d485eb83 1093 kfree(hd->info_kbuf);
1da177e4 1094
0d0c7974
MED
1095 /* NULL the Scsi_Host pointer
1096 */
1097 hd->ioc->sh = NULL;
1da177e4
LT
1098
1099 scsi_host_put(host);
1da177e4 1100
0d0c7974 1101 mpt_detach(pdev);
c6678e0c 1102
1da177e4
LT
1103}
1104
1105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1106/*
1107 * mptscsih_shutdown - reboot notifier
1108 *
1109 */
0d0c7974 1110void
d18c3db5 1111mptscsih_shutdown(struct pci_dev *pdev)
1da177e4 1112{
d18c3db5 1113 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1da177e4
LT
1114 struct Scsi_Host *host = ioc->sh;
1115 MPT_SCSI_HOST *hd;
1116
1117 if(!host)
1118 return;
1119
1120 hd = (MPT_SCSI_HOST *)host->hostdata;
1121
1da177e4
LT
1122}
1123
1124#ifdef CONFIG_PM
1125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1126/*
0d0c7974 1127 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
1da177e4
LT
1128 *
1129 *
1130 */
0d0c7974 1131int
8d189f72 1132mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
1da177e4 1133{
d18c3db5 1134 mptscsih_shutdown(pdev);
0d0c7974 1135 return mpt_suspend(pdev,state);
1da177e4
LT
1136}
1137
1138/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1139/*
1140 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1141 *
1142 *
1143 */
0d0c7974 1144int
1da177e4
LT
1145mptscsih_resume(struct pci_dev *pdev)
1146{
b364fd50 1147 return mpt_resume(pdev);
1da177e4
LT
1148}
1149
1150#endif
1151
1da177e4
LT
1152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1153/**
1154 * mptscsih_info - Return information about MPT adapter
1155 * @SChost: Pointer to Scsi_Host structure
1156 *
1157 * (linux scsi_host_template.info routine)
1158 *
1159 * Returns pointer to buffer where information was written.
1160 */
0d0c7974 1161const char *
1da177e4
LT
1162mptscsih_info(struct Scsi_Host *SChost)
1163{
1164 MPT_SCSI_HOST *h;
1165 int size = 0;
1166
1da177e4 1167 h = (MPT_SCSI_HOST *)SChost->hostdata;
0d0c7974 1168
1da177e4 1169 if (h) {
0d0c7974
MED
1170 if (h->info_kbuf == NULL)
1171 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1172 return h->info_kbuf;
1173 h->info_kbuf[0] = '\0';
1174
1175 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1176 h->info_kbuf[size-1] = '\0';
1da177e4
LT
1177 }
1178
0d0c7974 1179 return h->info_kbuf;
1da177e4
LT
1180}
1181
1182struct info_str {
1183 char *buffer;
1184 int length;
1185 int offset;
1186 int pos;
1187};
1188
0d0c7974
MED
1189static void
1190mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
1da177e4
LT
1191{
1192 if (info->pos + len > info->length)
1193 len = info->length - info->pos;
1194
1195 if (info->pos + len < info->offset) {
1196 info->pos += len;
1197 return;
1198 }
1199
1200 if (info->pos < info->offset) {
1201 data += (info->offset - info->pos);
1202 len -= (info->offset - info->pos);
1203 }
1204
1205 if (len > 0) {
1206 memcpy(info->buffer + info->pos, data, len);
1207 info->pos += len;
1208 }
1209}
1210
0d0c7974
MED
1211static int
1212mptscsih_copy_info(struct info_str *info, char *fmt, ...)
1da177e4
LT
1213{
1214 va_list args;
1215 char buf[81];
1216 int len;
1217
1218 va_start(args, fmt);
1219 len = vsprintf(buf, fmt, args);
1220 va_end(args);
1221
0d0c7974 1222 mptscsih_copy_mem_info(info, buf, len);
1da177e4
LT
1223 return len;
1224}
1225
0d0c7974
MED
1226static int
1227mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
1da177e4
LT
1228{
1229 struct info_str info;
1230
1231 info.buffer = pbuf;
1232 info.length = len;
1233 info.offset = offset;
1234 info.pos = 0;
1235
0d0c7974
MED
1236 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1237 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1238 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1239 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
1da177e4
LT
1240
1241 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1242}
1243
1244/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1245/**
1246 * mptscsih_proc_info - Return information about MPT adapter
d9489fb6
RD
1247 * @host: scsi host struct
1248 * @buffer: if write, user data; if read, buffer for user
1249 * @start: returns the buffer address
1250 * @offset: if write, 0; if read, the current offset into the buffer from
1251 * the previous read.
1252 * @length: if write, return length;
1253 * @func: write = 1; read = 0
1da177e4
LT
1254 *
1255 * (linux scsi_host_template.info routine)
1da177e4 1256 */
0d0c7974 1257int
1da177e4
LT
1258mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1259 int length, int func)
1260{
1261 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1262 MPT_ADAPTER *ioc = hd->ioc;
1263 int size = 0;
1264
1265 if (func) {
c6678e0c
CH
1266 /*
1267 * write is not supported
1da177e4
LT
1268 */
1269 } else {
1270 if (start)
1271 *start = buffer;
1272
1273 size = mptscsih_host_info(ioc, buffer, offset, length);
1274 }
1275
1276 return size;
1277}
1278
1279/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1280#define ADD_INDEX_LOG(req_ent) do { } while(0)
1281
1282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1283/**
1284 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1285 * @SCpnt: Pointer to scsi_cmnd structure
1286 * @done: Pointer SCSI mid-layer IO completion function
1287 *
1288 * (linux scsi_host_template.queuecommand routine)
1289 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1290 * from a linux scsi_cmnd request and send it to the IOC.
1291 *
1292 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1293 */
0d0c7974 1294int
1da177e4
LT
1295mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1296{
1297 MPT_SCSI_HOST *hd;
1298 MPT_FRAME_HDR *mf;
1299 SCSIIORequest_t *pScsiReq;
c7c82987 1300 VirtDevice *vdev = SCpnt->device->hostdata;
1da177e4
LT
1301 int lun;
1302 u32 datalen;
1303 u32 scsictl;
1304 u32 scsidir;
1305 u32 cmd_len;
1306 int my_idx;
1307 int ii;
1308
1309 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
1da177e4
LT
1310 lun = SCpnt->device->lun;
1311 SCpnt->scsi_done = done;
1312
1da177e4
LT
1313 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1314 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1315
1316 if (hd->resetPending) {
1317 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1318 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1319 return SCSI_MLQUEUE_HOST_BUSY;
1320 }
1321
1322 /*
1323 * Put together a MPT SCSI request...
1324 */
0d0c7974 1325 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
1da177e4
LT
1326 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1327 hd->ioc->name));
1328 return SCSI_MLQUEUE_HOST_BUSY;
1329 }
1330
1331 pScsiReq = (SCSIIORequest_t *) mf;
1332
1333 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1334
1335 ADD_INDEX_LOG(my_idx);
1336
0d0c7974 1337 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
1da177e4
LT
1338 * Seems we may receive a buffer (datalen>0) even when there
1339 * will be no data transfer! GRRRRR...
1340 */
1341 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1928d73f 1342 datalen = scsi_bufflen(SCpnt);
1da177e4
LT
1343 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1344 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1928d73f 1345 datalen = scsi_bufflen(SCpnt);
1da177e4
LT
1346 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1347 } else {
1348 datalen = 0;
1349 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1350 }
1351
1352 /* Default to untagged. Once a target structure has been allocated,
1353 * use the Inquiry data to determine if device supports tagged.
1354 */
c7c82987
MED
1355 if (vdev
1356 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
1da177e4
LT
1357 && (SCpnt->device->tagged_supported)) {
1358 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1359 } else {
1360 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1361 }
1362
1363 /* Use the above information to set up the message frame
1364 */
793955f5
EM
1365 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1366 pScsiReq->Bus = vdev->vtarget->channel;
1da177e4 1367 pScsiReq->ChainOffset = 0;
c92f222e
JB
1368 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1369 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1370 else
1371 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1da177e4
LT
1372 pScsiReq->CDBLength = SCpnt->cmd_len;
1373 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1374 pScsiReq->Reserved = 0;
1375 pScsiReq->MsgFlags = mpt_msg_flags();
793955f5 1376 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
1da177e4
LT
1377 pScsiReq->Control = cpu_to_le32(scsictl);
1378
1379 /*
1380 * Write SCSI CDB into the message
1381 */
1382 cmd_len = SCpnt->cmd_len;
1383 for (ii=0; ii < cmd_len; ii++)
1384 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1385
1386 for (ii=cmd_len; ii < 16; ii++)
1387 pScsiReq->CDB[ii] = 0;
1388
1389 /* DataLength */
1390 pScsiReq->DataLength = cpu_to_le32(datalen);
1391
1392 /* SenseBuffer low address */
1393 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1394 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1395
1396 /* Now add the SG list
1397 * Always have a SGE even if null length.
1398 */
1399 if (datalen == 0) {
1400 /* Add a NULL SGE */
1401 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1402 (dma_addr_t) -1);
1403 } else {
1404 /* Add a 32 or 64 bit SGE */
1405 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1406 goto fail;
1407 }
1408
3dc0b03f 1409 SCpnt->host_scribble = (unsigned char *)mf;
1da177e4 1410 hd->ScsiLookup[my_idx] = SCpnt;
1da177e4 1411
0d0c7974 1412 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
1da177e4
LT
1413 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1414 hd->ioc->name, SCpnt, mf, my_idx));
1415 DBG_DUMP_REQUEST_FRAME(mf)
1416 return 0;
1417
1418 fail:
466544d8 1419 hd->ScsiLookup[my_idx] = NULL;
1da177e4
LT
1420 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1421 mpt_free_msg_frame(hd->ioc, mf);
1422 return SCSI_MLQUEUE_HOST_BUSY;
1423}
1424
1425/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1426/*
1427 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1428 * with a SCSI IO request
1429 * @hd: Pointer to the MPT_SCSI_HOST instance
1430 * @req_idx: Index of the SCSI IO request frame.
1431 *
1432 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1433 * No return.
1434 */
1435static void
1436mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1437{
1438 MPT_FRAME_HDR *chain;
1439 unsigned long flags;
1440 int chain_idx;
1441 int next;
1442
1443 /* Get the first chain index and reset
1444 * tracker state.
1445 */
1446 chain_idx = ioc->ReqToChain[req_idx];
1447 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1448
1449 while (chain_idx != MPT_HOST_NO_CHAIN) {
1450
1451 /* Save the next chain buffer index */
1452 next = ioc->ChainToChain[chain_idx];
1453
1454 /* Free this chain buffer and reset
1455 * tracker
1456 */
1457 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1458
1459 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1460 + (chain_idx * ioc->req_sz));
1461
1462 spin_lock_irqsave(&ioc->FreeQlock, flags);
1463 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1464 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1465
1466 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1467 ioc->name, chain_idx));
1468
1469 /* handle next */
1470 chain_idx = next;
1471 }
1472 return;
1473}
1474
1475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1476/*
1477 * Reset Handling
1478 */
1479
1480/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
cd2c6191 1481/**
1da177e4 1482 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1544d677 1483 * @hd: Pointer to MPT SCSI HOST structure
1da177e4 1484 * @type: Task Management type
1544d677 1485 * @channel: channel number for task management
793955f5 1486 * @id: Logical Target ID for reset (if appropriate)
1da177e4
LT
1487 * @lun: Logical Unit for reset (if appropriate)
1488 * @ctx2abort: Context for the task to be aborted (if appropriate)
1544d677
RD
1489 * @timeout: timeout for task management control
1490 *
1491 * Fall through to mpt_HardResetHandler if: not operational, too many
1492 * failed TM requests or handshake failure.
1da177e4
LT
1493 *
1494 * Remark: Currently invoked from a non-interrupt thread (_bh).
1495 *
1496 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1497 * will be active.
1498 *
1544d677 1499 * Returns 0 for SUCCESS, or %FAILED.
cd2c6191 1500 **/
663e1aa1 1501int
793955f5 1502mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
1da177e4
LT
1503{
1504 MPT_ADAPTER *ioc;
1505 int rc = -1;
1da177e4
LT
1506 u32 ioc_raw_state;
1507 unsigned long flags;
1508
1da177e4 1509 ioc = hd->ioc;
1da177e4
LT
1510 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1511
1512 // SJR - CHECKME - Can we avoid this here?
1513 // (mpt_HardResetHandler has this check...)
1514 spin_lock_irqsave(&ioc->diagLock, flags);
1515 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1516 spin_unlock_irqrestore(&ioc->diagLock, flags);
1517 return FAILED;
1518 }
1519 spin_unlock_irqrestore(&ioc->diagLock, flags);
1520
1521 /* Wait a fixed amount of time for the TM pending flag to be cleared.
cd2c6191
EM
1522 * If we time out and not bus reset, then we return a FAILED status
1523 * to the caller.
1524 * The call to mptscsih_tm_pending_wait() will set the pending flag
1525 * if we are
1da177e4
LT
1526 * successful. Otherwise, reload the FW.
1527 */
1528 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1529 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
c6678e0c 1530 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
1da177e4
LT
1531 "Timed out waiting for last TM (%d) to complete! \n",
1532 hd->ioc->name, hd->tmPending));
1533 return FAILED;
1534 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
cd2c6191
EM
1535 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1536 "reset: Timed out waiting for last TM (%d) "
1537 "to complete! \n", hd->ioc->name,
1538 hd->tmPending));
1da177e4
LT
1539 return FAILED;
1540 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
c6678e0c 1541 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
1da177e4
LT
1542 "Timed out waiting for last TM (%d) to complete! \n",
1543 hd->ioc->name, hd->tmPending));
cd2c6191 1544 return FAILED;
1da177e4
LT
1545 }
1546 } else {
1547 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1548 hd->tmPending |= (1 << type);
1549 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1550 }
1551
1da177e4
LT
1552 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1553
1da177e4
LT
1554 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1555 printk(MYIOC_s_WARN_FMT
cd2c6191
EM
1556 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1557 ioc->name, type, ioc_raw_state);
1558 printk(KERN_WARNING " Issuing HardReset!!\n");
1559 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1560 printk((KERN_WARNING "TMHandler: HardReset "
1561 "FAILED!!\n"));
1562 return FAILED;
1da177e4
LT
1563 }
1564
cd2c6191
EM
1565 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1566 printk(MYIOC_s_WARN_FMT
1567 "TM Handler for type=%x: ioc_state: "
1568 "DOORBELL_ACTIVE (0x%x)!\n",
1569 ioc->name, type, ioc_raw_state);
1570 return FAILED;
1da177e4
LT
1571 }
1572
cd2c6191 1573 /* Isse the Task Mgmt request.
3dc0b03f 1574 */
cd2c6191
EM
1575 if (hd->hard_resets < -1)
1576 hd->hard_resets++;
1577
1578 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1579 ctx2abort, timeout);
1580 if (rc)
1581 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1582 hd->ioc->name);
1583 else
1584 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1585 hd->ioc->name));
3dc0b03f 1586
1da177e4
LT
1587 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1588
1589 return rc;
1590}
1591
1592
1593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
cd2c6191 1594/**
1da177e4
LT
1595 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1596 * @hd: Pointer to MPT_SCSI_HOST structure
1597 * @type: Task Management type
1544d677 1598 * @channel: channel number for task management
793955f5 1599 * @id: Logical Target ID for reset (if appropriate)
1da177e4
LT
1600 * @lun: Logical Unit for reset (if appropriate)
1601 * @ctx2abort: Context for the task to be aborted (if appropriate)
1544d677 1602 * @timeout: timeout for task management control
1da177e4
LT
1603 *
1604 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1605 * or a non-interrupt thread. In the former, must not call schedule().
1606 *
1607 * Not all fields are meaningfull for all task types.
1608 *
cd2c6191
EM
1609 * Returns 0 for SUCCESS, or FAILED.
1610 *
1611 **/
1da177e4 1612static int
793955f5 1613mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
1da177e4
LT
1614{
1615 MPT_FRAME_HDR *mf;
1616 SCSITaskMgmt_t *pScsiTm;
1617 int ii;
1618 int retval;
1619
1620 /* Return Fail to calling function if no message frames available.
1621 */
0d0c7974 1622 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
1da177e4
LT
1623 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1624 hd->ioc->name));
c6678e0c 1625 return FAILED;
1da177e4
LT
1626 }
1627 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1628 hd->ioc->name, mf));
1629
1630 /* Format the Request
1631 */
1632 pScsiTm = (SCSITaskMgmt_t *) mf;
793955f5 1633 pScsiTm->TargetID = id;
1da177e4
LT
1634 pScsiTm->Bus = channel;
1635 pScsiTm->ChainOffset = 0;
1636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1637
1638 pScsiTm->Reserved = 0;
1639 pScsiTm->TaskType = type;
1640 pScsiTm->Reserved1 = 0;
1641 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1642 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1643
793955f5 1644 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
1da177e4
LT
1645
1646 for (ii=0; ii < 7; ii++)
1647 pScsiTm->Reserved2[ii] = 0;
1648
1649 pScsiTm->TaskMsgContext = ctx2abort;
1650
cd2c6191
EM
1651 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1652 "type=%d\n", hd->ioc->name, ctx2abort, type));
1da177e4
LT
1653
1654 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1655
0d0c7974 1656 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
cd2c6191
EM
1657 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1658 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1659 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1660 hd->ioc, mf, retval));
1661 goto fail_out;
1da177e4
LT
1662 }
1663
1664 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
cd2c6191 1665 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
1da177e4
LT
1666 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1667 hd->ioc, mf));
1da177e4
LT
1668 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1669 hd->ioc->name));
1670 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
cd2c6191
EM
1671 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1672 hd->ioc->name, retval));
1673 goto fail_out;
1da177e4
LT
1674 }
1675
cd2c6191
EM
1676 /*
1677 * Handle success case, see if theres a non-zero ioc_status.
1678 */
1679 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1680 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1681 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1682 retval = 0;
1683 else
1684 retval = FAILED;
1685
1da177e4 1686 return retval;
cd2c6191
EM
1687
1688 fail_out:
1689
1690 /*
1691 * Free task managment mf, and corresponding tm flags
1692 */
1693 mpt_free_msg_frame(hd->ioc, mf);
1694 hd->tmPending = 0;
1695 hd->tmState = TM_STATE_NONE;
1696 return FAILED;
1da177e4
LT
1697}
1698
d66c7a0f
CH
1699static int
1700mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1701{
1702 switch (ioc->bus_type) {
1703 case FC:
1704 return 40;
1705 case SAS:
1706 return 10;
1707 case SPI:
1708 default:
1709 return 2;
1710 }
1711}
1712
1da177e4
LT
1713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1714/**
1715 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1716 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1717 *
1718 * (linux scsi_host_template.eh_abort_handler routine)
1719 *
1720 * Returns SUCCESS or FAILED.
cd2c6191 1721 **/
0d0c7974 1722int
1da177e4
LT
1723mptscsih_abort(struct scsi_cmnd * SCpnt)
1724{
1725 MPT_SCSI_HOST *hd;
1da177e4
LT
1726 MPT_FRAME_HDR *mf;
1727 u32 ctx2abort;
1728 int scpnt_idx;
466544d8 1729 int retval;
958d4a32 1730 VirtDevice *vdevice;
3dc0b03f 1731 ulong sn = SCpnt->serial_number;
958d4a32 1732 MPT_ADAPTER *ioc;
1da177e4
LT
1733
1734 /* If we can't locate our host adapter structure, return FAILED status.
1735 */
1736 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1737 SCpnt->result = DID_RESET << 16;
1738 SCpnt->scsi_done(SCpnt);
958d4a32
EM
1739 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
1740 "host! (sc=%p)\n", SCpnt));
1da177e4
LT
1741 return FAILED;
1742 }
1743
958d4a32
EM
1744 ioc = hd->ioc;
1745 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1746 ioc->name, SCpnt);
1747 scsi_print_command(SCpnt);
1748
1749 vdevice = SCpnt->device->hostdata;
1750 if (!vdevice || !vdevice->vtarget) {
1751 dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
1752 "deleted (sc=%p)\n", ioc->name, SCpnt));
1753 SCpnt->result = DID_NO_CONNECT << 16;
1754 SCpnt->scsi_done(SCpnt);
1755 retval = 0;
1756 goto out;
1757 }
1758
1da177e4
LT
1759 /* Find this command
1760 */
1761 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
466544d8 1762 /* Cmd not found in ScsiLookup.
1da177e4
LT
1763 * Do OS callback.
1764 */
1765 SCpnt->result = DID_RESET << 16;
466544d8 1766 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
958d4a32
EM
1767 "Command not in the active list! (sc=%p)\n", ioc->name,
1768 SCpnt));
1769 retval = 0;
1770 goto out;
1da177e4
LT
1771 }
1772
958d4a32
EM
1773 if (hd->resetPending) {
1774 retval = FAILED;
1775 goto out;
1776 }
65207fed
ME
1777
1778 if (hd->timeouts < -1)
1779 hd->timeouts++;
1780
1da177e4
LT
1781 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1782 * (the IO to be ABORT'd)
1783 *
1784 * NOTE: Since we do not byteswap MsgContext, we do not
1785 * swap it here either. It is an opaque cookie to
1786 * the controller, so it does not matter. -DaveM
1787 */
1788 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1789 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1790
1791 hd->abortSCpnt = SCpnt;
1792
466544d8 1793 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
958d4a32
EM
1794 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1795 ctx2abort, mptscsih_get_tm_timeout(ioc));
1da177e4 1796
3dc0b03f 1797 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
cd2c6191 1798 SCpnt->serial_number == sn)
3dc0b03f 1799 retval = FAILED;
3dc0b03f 1800
958d4a32
EM
1801 out:
1802 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1803 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1da177e4 1804
466544d8
MED
1805 if (retval == 0)
1806 return SUCCESS;
cd2c6191
EM
1807 else
1808 return FAILED;
1da177e4
LT
1809}
1810
1811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1812/**
1813 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1814 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1815 *
1816 * (linux scsi_host_template.eh_dev_reset_handler routine)
1817 *
1818 * Returns SUCCESS or FAILED.
cd2c6191 1819 **/
0d0c7974 1820int
1da177e4
LT
1821mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1822{
1823 MPT_SCSI_HOST *hd;
466544d8 1824 int retval;
958d4a32
EM
1825 VirtDevice *vdevice;
1826 MPT_ADAPTER *ioc;
1da177e4
LT
1827
1828 /* If we can't locate our host adapter structure, return FAILED status.
1829 */
1830 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
958d4a32
EM
1831 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
1832 "locate host! (sc=%p)\n", SCpnt));
1da177e4
LT
1833 return FAILED;
1834 }
1835
958d4a32
EM
1836 ioc = hd->ioc;
1837 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1838 ioc->name, SCpnt);
466544d8 1839 scsi_print_command(SCpnt);
1da177e4 1840
958d4a32
EM
1841 if (hd->resetPending) {
1842 retval = FAILED;
1843 goto out;
1844 }
1845
1846 vdevice = SCpnt->device->hostdata;
1847 if (!vdevice || !vdevice->vtarget) {
1848 retval = 0;
1849 goto out;
1850 }
1851
466544d8 1852 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
958d4a32
EM
1853 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1854 mptscsih_get_tm_timeout(ioc));
466544d8 1855
958d4a32
EM
1856 out:
1857 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1858 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
466544d8
MED
1859
1860 if (retval == 0)
1861 return SUCCESS;
cd2c6191
EM
1862 else
1863 return FAILED;
1da177e4
LT
1864}
1865
cd2c6191 1866
1da177e4
LT
1867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1868/**
1869 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1870 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1871 *
1872 * (linux scsi_host_template.eh_bus_reset_handler routine)
1873 *
1874 * Returns SUCCESS or FAILED.
cd2c6191 1875 **/
0d0c7974 1876int
1da177e4
LT
1877mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1878{
1879 MPT_SCSI_HOST *hd;
466544d8 1880 int retval;
c7c82987 1881 VirtDevice *vdev;
958d4a32 1882 MPT_ADAPTER *ioc;
1da177e4
LT
1883
1884 /* If we can't locate our host adapter structure, return FAILED status.
1885 */
1886 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
958d4a32
EM
1887 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
1888 "locate host! (sc=%p)\n", SCpnt ));
1da177e4
LT
1889 return FAILED;
1890 }
1891
958d4a32
EM
1892 ioc = hd->ioc;
1893 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1894 ioc->name, SCpnt);
466544d8 1895 scsi_print_command(SCpnt);
1da177e4
LT
1896
1897 if (hd->timeouts < -1)
1898 hd->timeouts++;
1899
c7c82987 1900 vdev = SCpnt->device->hostdata;
466544d8 1901 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
958d4a32 1902 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
1da177e4 1903
958d4a32
EM
1904 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1905 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
466544d8
MED
1906
1907 if (retval == 0)
1908 return SUCCESS;
cd2c6191
EM
1909 else
1910 return FAILED;
1da177e4
LT
1911}
1912
1913/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1914/**
d9489fb6 1915 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
1da177e4
LT
1916 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1917 *
1918 * (linux scsi_host_template.eh_host_reset_handler routine)
1919 *
1920 * Returns SUCCESS or FAILED.
1921 */
0d0c7974 1922int
1da177e4
LT
1923mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1924{
1925 MPT_SCSI_HOST * hd;
958d4a32
EM
1926 int retval;
1927 MPT_ADAPTER *ioc;
1da177e4
LT
1928
1929 /* If we can't locate the host to reset, then we failed. */
1930 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
958d4a32
EM
1931 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
1932 "locate host! (sc=%p)\n", SCpnt));
1da177e4
LT
1933 return FAILED;
1934 }
1935
958d4a32
EM
1936 ioc = hd->ioc;
1937 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1938 ioc->name, SCpnt);
1da177e4
LT
1939
1940 /* If our attempts to reset the host failed, then return a failed
1941 * status. The host will be taken off line by the SCSI mid-layer.
1942 */
958d4a32
EM
1943 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
1944 retval = FAILED;
1da177e4
LT
1945 } else {
1946 /* Make sure TM pending is cleared and TM state is set to
1947 * NONE.
1948 */
958d4a32 1949 retval = 0;
1da177e4
LT
1950 hd->tmPending = 0;
1951 hd->tmState = TM_STATE_NONE;
1952 }
1da177e4 1953
958d4a32
EM
1954 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1955 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1da177e4 1956
958d4a32 1957 return retval;
1da177e4
LT
1958}
1959
1960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1961/**
d9489fb6 1962 * mptscsih_tm_pending_wait - wait for pending task management request to complete
1da177e4
LT
1963 * @hd: Pointer to MPT host structure.
1964 *
1965 * Returns {SUCCESS,FAILED}.
1966 */
1967static int
1968mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1969{
1970 unsigned long flags;
1971 int loop_count = 4 * 10; /* Wait 10 seconds */
1972 int status = FAILED;
1973
1974 do {
1975 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1976 if (hd->tmState == TM_STATE_NONE) {
1977 hd->tmState = TM_STATE_IN_PROGRESS;
1978 hd->tmPending = 1;
1da177e4 1979 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
c6678e0c 1980 status = SUCCESS;
1da177e4
LT
1981 break;
1982 }
1983 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1984 msleep(250);
1985 } while (--loop_count);
1986
1987 return status;
1988}
1989
1990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1991/**
1992 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1993 * @hd: Pointer to MPT host structure.
1544d677 1994 * @timeout: timeout value
1da177e4
LT
1995 *
1996 * Returns {SUCCESS,FAILED}.
1997 */
1998static int
1999mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2000{
2001 unsigned long flags;
2002 int loop_count = 4 * timeout;
2003 int status = FAILED;
2004
2005 do {
2006 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2007 if(hd->tmPending == 0) {
2008 status = SUCCESS;
c6678e0c 2009 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1da177e4
LT
2010 break;
2011 }
2012 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
d6be06c8 2013 msleep(250);
1da177e4
LT
2014 } while (--loop_count);
2015
2016 return status;
2017}
2018
9f63bb73
ME
2019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2020static void
2021mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2022{
2023 char *desc;
2024
2025 switch (response_code) {
2026 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2027 desc = "The task completed.";
2028 break;
2029 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2030 desc = "The IOC received an invalid frame status.";
2031 break;
2032 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2033 desc = "The task type is not supported.";
2034 break;
2035 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2036 desc = "The requested task failed.";
2037 break;
2038 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2039 desc = "The task completed successfully.";
2040 break;
2041 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2042 desc = "The LUN request is invalid.";
2043 break;
2044 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2045 desc = "The task is in the IOC queue and has not been sent to target.";
2046 break;
2047 default:
2048 desc = "unknown";
2049 break;
2050 }
2051 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2052 ioc->name, response_code, desc);
2053}
2054
1da177e4
LT
2055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2056/**
2057 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2058 * @ioc: Pointer to MPT_ADAPTER structure
2059 * @mf: Pointer to SCSI task mgmt request frame
2060 * @mr: Pointer to SCSI task mgmt reply frame
2061 *
2062 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2063 * of any SCSI task management request.
2064 * This routine is registered with the MPT (base) driver at driver
2065 * load/init time via the mpt_register() API call.
2066 *
2067 * Returns 1 indicating alloc'd request frame ptr should be freed.
cd2c6191 2068 **/
0d0c7974 2069int
1da177e4
LT
2070mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2071{
2072 SCSITaskMgmtReply_t *pScsiTmReply;
2073 SCSITaskMgmt_t *pScsiTmReq;
2074 MPT_SCSI_HOST *hd;
2075 unsigned long flags;
2076 u16 iocstatus;
2077 u8 tmType;
cd2c6191 2078 u32 termination_count;
1da177e4
LT
2079
2080 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
cd2c6191
EM
2081 ioc->name, mf, mr));
2082 if (!ioc->sh) {
2083 dtmprintk((MYIOC_s_WARN_FMT
2084 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
1da177e4
LT
2085 return 1;
2086 }
2087
2088 if (mr == NULL) {
cd2c6191
EM
2089 dtmprintk((MYIOC_s_WARN_FMT
2090 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
1da177e4 2091 return 1;
cd2c6191 2092 }
1da177e4 2093
cd2c6191
EM
2094 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2095 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2096 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2097 tmType = pScsiTmReq->TaskType;
2098 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2099 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2100
2101 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2102 pScsiTmReply->ResponseCode)
2103 mptscsih_taskmgmt_response_code(ioc,
2104 pScsiTmReply->ResponseCode);
2105 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2106
2107#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2108 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2109 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2110 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2111 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2112 le16_to_cpu(pScsiTmReply->IOCStatus),
2113 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2114 le32_to_cpu(pScsiTmReply->TerminationCount));
2115#endif
2116 if (!iocstatus) {
2117 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2118 hd->abortSCpnt = NULL;
2119 goto out;
2120 }
1da177e4 2121
cd2c6191 2122 /* Error? (anything non-zero?) */
9f63bb73 2123
cd2c6191
EM
2124 /* clear flags and continue.
2125 */
2126 switch (tmType) {
1da177e4 2127
cd2c6191
EM
2128 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2129 if (termination_count == 1)
2130 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2131 hd->abortSCpnt = NULL;
2132 break;
1da177e4 2133
cd2c6191 2134 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
1da177e4 2135
cd2c6191
EM
2136 /* If an internal command is present
2137 * or the TM failed - reload the FW.
2138 * FC FW may respond FAILED to an ABORT
2139 */
2140 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2141 hd->cmdPtr)
2142 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2143 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2144 break;
1da177e4 2145
cd2c6191
EM
2146 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2147 default:
2148 break;
1da177e4
LT
2149 }
2150
cd2c6191 2151 out:
1da177e4
LT
2152 spin_lock_irqsave(&ioc->FreeQlock, flags);
2153 hd->tmPending = 0;
1da177e4 2154 hd->tmState = TM_STATE_NONE;
cd2c6191
EM
2155 hd->tm_iocstatus = iocstatus;
2156 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1da177e4
LT
2157
2158 return 1;
2159}
2160
2161/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2162/*
2163 * This is anyones guess quite frankly.
2164 */
0d0c7974 2165int
1da177e4
LT
2166mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2167 sector_t capacity, int geom[])
2168{
2169 int heads;
2170 int sectors;
2171 sector_t cylinders;
2172 ulong dummy;
2173
2174 heads = 64;
2175 sectors = 32;
2176
2177 dummy = heads * sectors;
2178 cylinders = capacity;
2179 sector_div(cylinders,dummy);
2180
2181 /*
2182 * Handle extended translation size for logical drives
2183 * > 1Gb
2184 */
2185 if ((ulong)capacity >= 0x200000) {
2186 heads = 255;
2187 sectors = 63;
2188 dummy = heads * sectors;
2189 cylinders = capacity;
2190 sector_div(cylinders,dummy);
2191 }
2192
2193 /* return result */
2194 geom[0] = heads;
2195 geom[1] = sectors;
2196 geom[2] = cylinders;
2197
2198 dprintk((KERN_NOTICE
2199 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
793955f5 2200 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
1da177e4
LT
2201
2202 return 0;
2203}
2204
f44e5461
ME
2205/* Search IOC page 3 to determine if this is hidden physical disk
2206 *
2207 */
2208int
793955f5 2209mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
f44e5461 2210{
b506ade9 2211 struct inactive_raid_component_info *component_info;
f44e5461 2212 int i;
793955f5 2213 int rc = 0;
f44e5461 2214
793955f5
EM
2215 if (!ioc->raid_data.pIocPg3)
2216 goto out;
f44e5461 2217 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
793955f5
EM
2218 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2219 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2220 rc = 1;
2221 goto out;
2222 }
c92f222e
JB
2223 }
2224
b506ade9
EM
2225 /*
2226 * Check inactive list for matching phys disks
2227 */
2228 if (list_empty(&ioc->raid_data.inactive_list))
2229 goto out;
2230
2231 down(&ioc->raid_data.inactive_list_mutex);
2232 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2233 list) {
2234 if ((component_info->d.PhysDiskID == id) &&
2235 (component_info->d.PhysDiskBus == channel))
2236 rc = 1;
2237 }
2238 up(&ioc->raid_data.inactive_list_mutex);
2239
793955f5
EM
2240 out:
2241 return rc;
c7c82987 2242}
793955f5 2243EXPORT_SYMBOL(mptscsih_is_phys_disk);
c7c82987 2244
793955f5
EM
2245u8
2246mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
1da177e4 2247{
b506ade9 2248 struct inactive_raid_component_info *component_info;
793955f5
EM
2249 int i;
2250 int rc = -ENXIO;
c92f222e 2251
793955f5
EM
2252 if (!ioc->raid_data.pIocPg3)
2253 goto out;
2254 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2255 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2256 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2257 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2258 goto out;
1da177e4 2259 }
1da177e4 2260 }
1da177e4 2261
b506ade9
EM
2262 /*
2263 * Check inactive list for matching phys disks
2264 */
2265 if (list_empty(&ioc->raid_data.inactive_list))
2266 goto out;
2267
2268 down(&ioc->raid_data.inactive_list_mutex);
2269 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2270 list) {
2271 if ((component_info->d.PhysDiskID == id) &&
2272 (component_info->d.PhysDiskBus == channel))
2273 rc = component_info->d.PhysDiskNum;
2274 }
2275 up(&ioc->raid_data.inactive_list_mutex);
2276
793955f5
EM
2277 out:
2278 return rc;
c7c82987 2279}
793955f5 2280EXPORT_SYMBOL(mptscsih_raid_id_to_num);
1da177e4 2281
c7c82987
MED
2282/*
2283 * OS entry point to allow for host driver to free allocated memory
2284 * Called if no device present or device being unloaded
2285 */
2286void
2287mptscsih_slave_destroy(struct scsi_device *sdev)
2288{
2289 struct Scsi_Host *host = sdev->host;
2290 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2291 VirtTarget *vtarget;
2292 VirtDevice *vdevice;
2293 struct scsi_target *starget;
2294
2295 starget = scsi_target(sdev);
2296 vtarget = starget->hostdata;
2297 vdevice = sdev->hostdata;
2298
2299 mptscsih_search_running_cmds(hd, vdevice);
c7c82987 2300 vtarget->num_luns--;
c7c82987
MED
2301 mptscsih_synchronize_cache(hd, vdevice);
2302 kfree(vdevice);
2303 sdev->hostdata = NULL;
1da177e4
LT
2304}
2305
6e3815ba
MED
2306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2307/*
2308 * mptscsih_change_queue_depth - This function will set a devices queue depth
2309 * @sdev: per scsi_device pointer
2310 * @qdepth: requested queue depth
2311 *
2312 * Adding support for new 'change_queue_depth' api.
2313*/
2314int
2315mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
1da177e4 2316{
c7c82987
MED
2317 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2318 VirtTarget *vtarget;
2319 struct scsi_target *starget;
2320 int max_depth;
2321 int tagged;
1da177e4 2322
c7c82987
MED
2323 starget = scsi_target(sdev);
2324 vtarget = starget->hostdata;
6e3815ba 2325
a9b2937a 2326 if (hd->ioc->bus_type == SPI) {
c92f222e 2327 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
1da177e4 2328 max_depth = 1;
c92f222e
JB
2329 else if (sdev->type == TYPE_DISK &&
2330 vtarget->minSyncFactor <= MPT_ULTRA160)
2331 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2332 else
2333 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
1da177e4
LT
2334 } else
2335 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2336
2337 if (qdepth > max_depth)
2338 qdepth = max_depth;
2339 if (qdepth == 1)
2340 tagged = 0;
2341 else
2342 tagged = MSG_SIMPLE_TAG;
2343
6e3815ba
MED
2344 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2345 return sdev->queue_depth;
1da177e4
LT
2346}
2347
1da177e4
LT
2348/*
2349 * OS entry point to adjust the queue_depths on a per-device basis.
2350 * Called once per device the bus scan. Use it to force the queue_depth
2351 * member to 1 if a device does not support Q tags.
2352 * Return non-zero if fails.
2353 */
0d0c7974 2354int
c7c82987 2355mptscsih_slave_configure(struct scsi_device *sdev)
1da177e4 2356{
c7c82987
MED
2357 struct Scsi_Host *sh = sdev->host;
2358 VirtTarget *vtarget;
2359 VirtDevice *vdevice;
2360 struct scsi_target *starget;
1da177e4
LT
2361 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2362
c7c82987
MED
2363 starget = scsi_target(sdev);
2364 vtarget = starget->hostdata;
2365 vdevice = sdev->hostdata;
1da177e4
LT
2366
2367 dsprintk((MYIOC_s_INFO_FMT
793955f5
EM
2368 "device @ %p, channel=%d, id=%d, lun=%d\n",
2369 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
c7c82987
MED
2370 if (hd->ioc->bus_type == SPI)
2371 dsprintk((MYIOC_s_INFO_FMT
2372 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2373 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2374 sdev->ppr, sdev->inquiry_len));
2375
2376 if (sdev->id > sh->max_id) {
1da177e4 2377 /* error case, should never happen */
c7c82987 2378 scsi_adjust_queue_depth(sdev, 0, 1);
1da177e4
LT
2379 goto slave_configure_exit;
2380 }
2381
793955f5 2382 vdevice->configured_lun = 1;
c7c82987 2383 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
1da177e4
LT
2384
2385 dsprintk((MYIOC_s_INFO_FMT
2386 "Queue depth=%d, tflags=%x\n",
c7c82987 2387 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
1da177e4 2388
c7c82987
MED
2389 if (hd->ioc->bus_type == SPI)
2390 dsprintk((MYIOC_s_INFO_FMT
2391 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2392 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2393 vtarget->minSyncFactor));
1da177e4
LT
2394
2395slave_configure_exit:
2396
2397 dsprintk((MYIOC_s_INFO_FMT
2398 "tagged %d, simple %d, ordered %d\n",
c7c82987
MED
2399 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2400 sdev->ordered_tags));
1da177e4
LT
2401
2402 return 0;
2403}
2404
1da177e4
LT
2405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2406/*
2407 * Private routines...
2408 */
2409
2410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2411/* Utility function to copy sense data from the scsi_cmnd buffer
2412 * to the FC and SCSI target structures.
2413 *
2414 */
2415static void
0d0c7974 2416mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
1da177e4 2417{
c7c82987 2418 VirtDevice *vdev;
1da177e4
LT
2419 SCSIIORequest_t *pReq;
2420 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
1da177e4
LT
2421
2422 /* Get target structure
2423 */
2424 pReq = (SCSIIORequest_t *) mf;
c7c82987 2425 vdev = sc->device->hostdata;
1da177e4
LT
2426
2427 if (sense_count) {
2428 u8 *sense_data;
2429 int req_index;
2430
2431 /* Copy the sense received into the scsi command block. */
2432 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2433 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2434 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2435
2436 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2437 */
2438 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
c7c82987 2439 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
1da177e4
LT
2440 int idx;
2441 MPT_ADAPTER *ioc = hd->ioc;
2442
5b5ef4f6 2443 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
1da177e4
LT
2444 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2445 ioc->events[idx].eventContext = ioc->eventContext;
2446
3d9780b9
DJ
2447 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2448 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2449 (sc->device->channel << 8) | sc->device->id;
1da177e4 2450
3d9780b9 2451 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
1da177e4
LT
2452
2453 ioc->eventContext++;
786899b0
EM
2454 if (hd->ioc->pcidev->vendor ==
2455 PCI_VENDOR_ID_IBM) {
2456 mptscsih_issue_sep_command(hd->ioc,
2457 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2458 vdev->vtarget->tflags |=
2459 MPT_TARGET_FLAGS_LED_ON;
2460 }
1da177e4
LT
2461 }
2462 }
2463 } else {
2464 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2465 hd->ioc->name));
2466 }
2467}
2468
3dc0b03f 2469static int
1da177e4
LT
2470SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2471{
2472 MPT_SCSI_HOST *hd;
2473 int i;
2474
2475 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2476
2477 for (i = 0; i < hd->ioc->req_depth; i++) {
2478 if (hd->ScsiLookup[i] == sc) {
2479 return i;
2480 }
2481 }
2482
2483 return -1;
2484}
2485
2486/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
0d0c7974 2487int
1da177e4
LT
2488mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2489{
2490 MPT_SCSI_HOST *hd;
2491 unsigned long flags;
466544d8 2492 int ii;
1da177e4
LT
2493
2494 dtmprintk((KERN_WARNING MYNAM
2495 ": IOC %s_reset routed to SCSI host driver!\n",
2496 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2497 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2498
2499 /* If a FW reload request arrives after base installed but
2500 * before all scsi hosts have been attached, then an alt_ioc
2501 * may have a NULL sh pointer.
2502 */
2503 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2504 return 0;
2505 else
2506 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2507
2508 if (reset_phase == MPT_IOC_SETUP_RESET) {
2509 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2510
2511 /* Clean Up:
2512 * 1. Set Hard Reset Pending Flag
2513 * All new commands go to doneQ
2514 */
2515 hd->resetPending = 1;
2516
2517 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2518 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2519
2520 /* 2. Flush running commands
2521 * Clean ScsiLookup (and associated memory)
2522 * AND clean mytaskQ
2523 */
2524
2525 /* 2b. Reply to OS all known outstanding I/O commands.
2526 */
2527 mptscsih_flush_running_cmds(hd);
2528
2529 /* 2c. If there was an internal command that
2530 * has not completed, configuration or io request,
2531 * free these resources.
2532 */
2533 if (hd->cmdPtr) {
2534 del_timer(&hd->timer);
2535 mpt_free_msg_frame(ioc, hd->cmdPtr);
2536 }
2537
2538 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2539
2540 } else {
2541 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2542
2543 /* Once a FW reload begins, all new OS commands are
2544 * redirected to the doneQ w/ a reset status.
2545 * Init all control structures.
2546 */
2547
2548 /* ScsiLookup initialization
2549 */
466544d8
MED
2550 for (ii=0; ii < hd->ioc->req_depth; ii++)
2551 hd->ScsiLookup[ii] = NULL;
1da177e4
LT
2552
2553 /* 2. Chain Buffer initialization
2554 */
2555
a9b2937a 2556 /* 4. Renegotiate to all devices, if SPI
1da177e4 2557 */
1da177e4
LT
2558
2559 /* 5. Enable new commands to be posted
2560 */
2561 spin_lock_irqsave(&ioc->FreeQlock, flags);
2562 hd->tmPending = 0;
2563 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2564 hd->resetPending = 0;
2565 hd->tmState = TM_STATE_NONE;
2566
2567 /* 6. If there was an internal command,
2568 * wake this process up.
2569 */
2570 if (hd->cmdPtr) {
2571 /*
2572 * Wake up the original calling thread
2573 */
2574 hd->pLocal = &hd->localReply;
2575 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
0d0c7974
MED
2576 hd->scandv_wait_done = 1;
2577 wake_up(&hd->scandv_waitq);
1da177e4
LT
2578 hd->cmdPtr = NULL;
2579 }
2580
1da177e4
LT
2581 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2582
2583 }
2584
2585 return 1; /* currently means nothing really */
2586}
2587
2588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
0d0c7974 2589int
1da177e4
LT
2590mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2591{
2592 MPT_SCSI_HOST *hd;
2593 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2594
3a892bef 2595 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
1da177e4
LT
2596 ioc->name, event));
2597
466544d8
MED
2598 if (ioc->sh == NULL ||
2599 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2600 return 1;
2601
1da177e4
LT
2602 switch (event) {
2603 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2604 /* FIXME! */
2605 break;
2606 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2607 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
a9b2937a 2608 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
466544d8 2609 hd->soft_resets++;
1da177e4
LT
2610 break;
2611 case MPI_EVENT_LOGOUT: /* 09 */
2612 /* FIXME! */
2613 break;
2614
05e8ec17 2615 case MPI_EVENT_RESCAN: /* 06 */
05e8ec17
MR
2616 break;
2617
1da177e4
LT
2618 /*
2619 * CHECKME! Don't think we need to do
2620 * anything for these, but...
2621 */
1da177e4
LT
2622 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2623 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2624 /*
2625 * CHECKME! Falling thru...
2626 */
2627 break;
2628
2629 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
466544d8 2630 break;
1da177e4 2631
1da177e4
LT
2632 case MPI_EVENT_NONE: /* 00 */
2633 case MPI_EVENT_LOG_DATA: /* 01 */
2634 case MPI_EVENT_STATE_CHANGE: /* 02 */
2635 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2636 default:
2637 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2638 break;
2639 }
2640
2641 return 1; /* currently means nothing really */
2642}
2643
1da177e4
LT
2644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2645/*
2646 * Bus Scan and Domain Validation functionality ...
2647 */
2648
2649/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2650/*
2651 * mptscsih_scandv_complete - Scan and DV callback routine registered
2652 * to Fustion MPT (base) driver.
2653 *
2654 * @ioc: Pointer to MPT_ADAPTER structure
2655 * @mf: Pointer to original MPT request frame
2656 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2657 *
2658 * This routine is called from mpt.c::mpt_interrupt() at the completion
2659 * of any SCSI IO request.
2660 * This routine is registered with the Fusion MPT (base) driver at driver
2661 * load/init time via the mpt_register() API call.
2662 *
2663 * Returns 1 indicating alloc'd request frame ptr should be freed.
2664 *
2665 * Remark: Sets a completion code and (possibly) saves sense data
2666 * in the IOC member localReply structure.
2667 * Used ONLY for DV and other internal commands.
2668 */
0d0c7974 2669int
1da177e4
LT
2670mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2671{
2672 MPT_SCSI_HOST *hd;
2673 SCSIIORequest_t *pReq;
2674 int completionCode;
2675 u16 req_idx;
2676
0d0c7974
MED
2677 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2678
1da177e4
LT
2679 if ((mf == NULL) ||
2680 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2681 printk(MYIOC_s_ERR_FMT
2682 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2683 ioc->name, mf?"BAD":"NULL", (void *) mf);
2684 goto wakeup;
2685 }
2686
1da177e4
LT
2687 del_timer(&hd->timer);
2688 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2689 hd->ScsiLookup[req_idx] = NULL;
2690 pReq = (SCSIIORequest_t *) mf;
2691
2692 if (mf != hd->cmdPtr) {
2693 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2694 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2695 }
2696 hd->cmdPtr = NULL;
2697
2698 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2699 hd->ioc->name, mf, mr, req_idx));
2700
2701 hd->pLocal = &hd->localReply;
2702 hd->pLocal->scsiStatus = 0;
2703
2704 /* If target struct exists, clear sense valid flag.
2705 */
2706 if (mr == NULL) {
2707 completionCode = MPT_SCANDV_GOOD;
2708 } else {
2709 SCSIIOReply_t *pReply;
2710 u16 status;
2711 u8 scsi_status;
2712
2713 pReply = (SCSIIOReply_t *) mr;
2714
2715 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2716 scsi_status = pReply->SCSIStatus;
2717
2718 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2719 status, pReply->SCSIState, scsi_status,
2720 le32_to_cpu(pReply->IOCLogInfo)));
2721
2722 switch(status) {
2723
2724 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2725 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2726 break;
2727
2728 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2729 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2730 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2731 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2732 completionCode = MPT_SCANDV_DID_RESET;
2733 break;
2734
2735 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2736 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2737 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2738 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2739 ConfigReply_t *pr = (ConfigReply_t *)mr;
2740 completionCode = MPT_SCANDV_GOOD;
2741 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2742 hd->pLocal->header.PageLength = pr->Header.PageLength;
2743 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2744 hd->pLocal->header.PageType = pr->Header.PageType;
2745
2746 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2747 /* If the RAID Volume request is successful,
2748 * return GOOD, else indicate that
2749 * some type of error occurred.
2750 */
2751 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
637fa99b 2752 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
1da177e4
LT
2753 completionCode = MPT_SCANDV_GOOD;
2754 else
2755 completionCode = MPT_SCANDV_SOME_ERROR;
c92f222e 2756 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
1da177e4
LT
2757
2758 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2759 u8 *sense_data;
2760 int sz;
2761
2762 /* save sense data in global structure
2763 */
2764 completionCode = MPT_SCANDV_SENSE;
2765 hd->pLocal->scsiStatus = scsi_status;
2766 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2767 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2768
2769 sz = min_t(int, pReq->SenseBufferLength,
2770 SCSI_STD_SENSE_BYTES);
2771 memcpy(hd->pLocal->sense, sense_data, sz);
2772
2773 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2774 sense_data));
2775 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2776 if (pReq->CDB[0] == INQUIRY)
2777 completionCode = MPT_SCANDV_ISSUE_SENSE;
2778 else
2779 completionCode = MPT_SCANDV_DID_RESET;
2780 }
2781 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2782 completionCode = MPT_SCANDV_DID_RESET;
2783 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2784 completionCode = MPT_SCANDV_DID_RESET;
2785 else {
2786 completionCode = MPT_SCANDV_GOOD;
2787 hd->pLocal->scsiStatus = scsi_status;
2788 }
2789 break;
2790
2791 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2792 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2793 completionCode = MPT_SCANDV_DID_RESET;
2794 else
2795 completionCode = MPT_SCANDV_SOME_ERROR;
2796 break;
2797
2798 default:
2799 completionCode = MPT_SCANDV_SOME_ERROR;
2800 break;
2801
2802 } /* switch(status) */
2803
2804 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2805 completionCode));
2806 } /* end of address reply case */
2807
2808 hd->pLocal->completion = completionCode;
2809
2810 /* MF and RF are freed in mpt_interrupt
2811 */
2812wakeup:
2813 /* Free Chain buffers (will never chain) in scan or dv */
2814 //mptscsih_freeChainBuffers(ioc, req_idx);
2815
2816 /*
2817 * Wake up the original calling thread
2818 */
0d0c7974
MED
2819 hd->scandv_wait_done = 1;
2820 wake_up(&hd->scandv_waitq);
1da177e4
LT
2821
2822 return 1;
2823}
2824
2825/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2826/* mptscsih_timer_expired - Call back for timer process.
2827 * Used only for dv functionality.
2828 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2829 *
2830 */
0d0c7974
MED
2831void
2832mptscsih_timer_expired(unsigned long data)
1da177e4
LT
2833{
2834 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2835
2836 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2837
2838 if (hd->cmdPtr) {
2839 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2840
2841 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2842 /* Desire to issue a task management request here.
2843 * TM requests MUST be single threaded.
2844 * If old eh code and no TM current, issue request.
2845 * If new eh code, do nothing. Wait for OS cmd timeout
2846 * for bus reset.
2847 */
2848 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2849 } else {
2850 /* Perform a FW reload */
2851 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2852 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2853 }
2854 }
2855 } else {
2856 /* This should NEVER happen */
2857 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2858 }
2859
2860 /* No more processing.
2861 * TM call will generate an interrupt for SCSI TM Management.
2862 * The FW will reply to all outstanding commands, callback will finish cleanup.
2863 * Hard reset clean-up will free all resources.
2864 */
2865 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2866
2867 return;
2868}
2869
1da177e4
LT
2870
2871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2872/**
2873 * mptscsih_do_cmd - Do internal command.
2874 * @hd: MPT_SCSI_HOST pointer
2875 * @io: INTERNAL_CMD pointer.
2876 *
2877 * Issue the specified internally generated command and do command
2878 * specific cleanup. For bus scan / DV only.
2879 * NOTES: If command is Inquiry and status is good,
2880 * initialize a target structure, save the data
2881 *
2882 * Remark: Single threaded access only.
2883 *
2884 * Return:
2885 * < 0 if an illegal command or no resources
2886 *
2887 * 0 if good
2888 *
2889 * > 0 if command complete but some type of completion error.
2890 */
2891static int
2892mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2893{
2894 MPT_FRAME_HDR *mf;
2895 SCSIIORequest_t *pScsiReq;
2896 SCSIIORequest_t ReqCopy;
2897 int my_idx, ii, dir;
2898 int rc, cmdTimeout;
2899 int in_isr;
2900 char cmdLen;
2901 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2902 char cmd = io->cmd;
2903
2904 in_isr = in_interrupt();
2905 if (in_isr) {
2906 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2907 hd->ioc->name));
2908 return -EPERM;
2909 }
2910
2911
2912 /* Set command specific information
2913 */
2914 switch (cmd) {
2915 case INQUIRY:
2916 cmdLen = 6;
2917 dir = MPI_SCSIIO_CONTROL_READ;
2918 CDB[0] = cmd;
2919 CDB[4] = io->size;
2920 cmdTimeout = 10;
2921 break;
2922
2923 case TEST_UNIT_READY:
2924 cmdLen = 6;
2925 dir = MPI_SCSIIO_CONTROL_READ;
2926 cmdTimeout = 10;
2927 break;
2928
2929 case START_STOP:
2930 cmdLen = 6;
2931 dir = MPI_SCSIIO_CONTROL_READ;
2932 CDB[0] = cmd;
2933 CDB[4] = 1; /*Spin up the disk */
2934 cmdTimeout = 15;
2935 break;
2936
2937 case REQUEST_SENSE:
2938 cmdLen = 6;
2939 CDB[0] = cmd;
2940 CDB[4] = io->size;
2941 dir = MPI_SCSIIO_CONTROL_READ;
2942 cmdTimeout = 10;
2943 break;
2944
2945 case READ_BUFFER:
2946 cmdLen = 10;
2947 dir = MPI_SCSIIO_CONTROL_READ;
2948 CDB[0] = cmd;
2949 if (io->flags & MPT_ICFLAG_ECHO) {
2950 CDB[1] = 0x0A;
2951 } else {
2952 CDB[1] = 0x02;
2953 }
2954
2955 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2956 CDB[1] |= 0x01;
2957 }
2958 CDB[6] = (io->size >> 16) & 0xFF;
2959 CDB[7] = (io->size >> 8) & 0xFF;
2960 CDB[8] = io->size & 0xFF;
2961 cmdTimeout = 10;
2962 break;
2963
2964 case WRITE_BUFFER:
2965 cmdLen = 10;
2966 dir = MPI_SCSIIO_CONTROL_WRITE;
2967 CDB[0] = cmd;
2968 if (io->flags & MPT_ICFLAG_ECHO) {
2969 CDB[1] = 0x0A;
2970 } else {
2971 CDB[1] = 0x02;
2972 }
2973 CDB[6] = (io->size >> 16) & 0xFF;
2974 CDB[7] = (io->size >> 8) & 0xFF;
2975 CDB[8] = io->size & 0xFF;
2976 cmdTimeout = 10;
2977 break;
2978
2979 case RESERVE:
2980 cmdLen = 6;
2981 dir = MPI_SCSIIO_CONTROL_READ;
2982 CDB[0] = cmd;
2983 cmdTimeout = 10;
2984 break;
2985
2986 case RELEASE:
2987 cmdLen = 6;
2988 dir = MPI_SCSIIO_CONTROL_READ;
2989 CDB[0] = cmd;
2990 cmdTimeout = 10;
2991 break;
2992
2993 case SYNCHRONIZE_CACHE:
2994 cmdLen = 10;
2995 dir = MPI_SCSIIO_CONTROL_READ;
2996 CDB[0] = cmd;
2997// CDB[1] = 0x02; /* set immediate bit */
2998 cmdTimeout = 10;
2999 break;
3000
3001 default:
3002 /* Error Case */
3003 return -EFAULT;
3004 }
3005
3006 /* Get and Populate a free Frame
3007 */
0d0c7974 3008 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
1da177e4
LT
3009 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3010 hd->ioc->name));
3011 return -EBUSY;
3012 }
3013
3014 pScsiReq = (SCSIIORequest_t *) mf;
3015
3016 /* Get the request index */
3017 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3018 ADD_INDEX_LOG(my_idx); /* for debug */
3019
3020 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3021 pScsiReq->TargetID = io->physDiskNum;
3022 pScsiReq->Bus = 0;
3023 pScsiReq->ChainOffset = 0;
3024 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3025 } else {
3026 pScsiReq->TargetID = io->id;
793955f5 3027 pScsiReq->Bus = io->channel;
1da177e4
LT
3028 pScsiReq->ChainOffset = 0;
3029 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3030 }
3031
3032 pScsiReq->CDBLength = cmdLen;
3033 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3034
3035 pScsiReq->Reserved = 0;
3036
3037 pScsiReq->MsgFlags = mpt_msg_flags();
3038 /* MsgContext set in mpt_get_msg_fram call */
3039
793955f5 3040 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
1da177e4
LT
3041
3042 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3043 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3044 else
3045 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3046
3047 if (cmd == REQUEST_SENSE) {
3048 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3049 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3050 hd->ioc->name, cmd));
3051 }
3052
3053 for (ii=0; ii < 16; ii++)
3054 pScsiReq->CDB[ii] = CDB[ii];
3055
3056 pScsiReq->DataLength = cpu_to_le32(io->size);
3057 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3058 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3059
3060 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
793955f5 3061 hd->ioc->name, cmd, io->channel, io->id, io->lun));
1da177e4
LT
3062
3063 if (dir == MPI_SCSIIO_CONTROL_READ) {
3064 mpt_add_sge((char *) &pScsiReq->SGL,
3065 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3066 io->data_dma);
3067 } else {
3068 mpt_add_sge((char *) &pScsiReq->SGL,
3069 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3070 io->data_dma);
3071 }
3072
3073 /* The ISR will free the request frame, but we need
3074 * the information to initialize the target. Duplicate.
3075 */
3076 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3077
3078 /* Issue this command after:
3079 * finish init
3080 * add timer
3081 * Wait until the reply has been received
3082 * ScsiScanDvCtx callback function will
3083 * set hd->pLocal;
3084 * set scandv_wait_done and call wake_up
3085 */
3086 hd->pLocal = NULL;
3087 hd->timer.expires = jiffies + HZ*cmdTimeout;
0d0c7974 3088 hd->scandv_wait_done = 0;
1da177e4
LT
3089
3090 /* Save cmd pointer, for resource free if timeout or
3091 * FW reload occurs
3092 */
3093 hd->cmdPtr = mf;
3094
3095 add_timer(&hd->timer);
0d0c7974
MED
3096 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3097 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
1da177e4
LT
3098
3099 if (hd->pLocal) {
3100 rc = hd->pLocal->completion;
3101 hd->pLocal->skip = 0;
3102
3103 /* Always set fatal error codes in some cases.
3104 */
3105 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3106 rc = -ENXIO;
3107 else if (rc == MPT_SCANDV_SOME_ERROR)
3108 rc = -rc;
3109 } else {
3110 rc = -EFAULT;
3111 /* This should never happen. */
3112 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3113 hd->ioc->name));
3114 }
3115
3116 return rc;
3117}
3118
c7c82987
MED
3119/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3120/**
3121 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3122 * @hd: Pointer to a SCSI HOST structure
d9489fb6 3123 * @vdevice: virtual target device
c7c82987
MED
3124 *
3125 * Uses the ISR, but with special processing.
3126 * MUST be single-threaded.
3127 *
3128 */
3129static void
3130mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3131{
3132 INTERNAL_CMD iocmd;
1da177e4 3133
c7c82987
MED
3134 /* Following parameters will not change
3135 * in this routine.
3136 */
3137 iocmd.cmd = SYNCHRONIZE_CACHE;
3138 iocmd.flags = 0;
3139 iocmd.physDiskNum = -1;
3140 iocmd.data = NULL;
3141 iocmd.data_dma = -1;
3142 iocmd.size = 0;
3143 iocmd.rsvd = iocmd.rsvd2 = 0;
793955f5
EM
3144 iocmd.channel = vdevice->vtarget->channel;
3145 iocmd.id = vdevice->vtarget->id;
3146 iocmd.lun = vdevice->lun;
1da177e4 3147
c92f222e 3148 if ((vdevice->vtarget->type == TYPE_DISK) &&
c7c82987
MED
3149 (vdevice->configured_lun))
3150 mptscsih_do_cmd(hd, &iocmd);
1da177e4
LT
3151}
3152
0d0c7974
MED
3153EXPORT_SYMBOL(mptscsih_remove);
3154EXPORT_SYMBOL(mptscsih_shutdown);
3155#ifdef CONFIG_PM
3156EXPORT_SYMBOL(mptscsih_suspend);
3157EXPORT_SYMBOL(mptscsih_resume);
3158#endif
3159EXPORT_SYMBOL(mptscsih_proc_info);
3160EXPORT_SYMBOL(mptscsih_info);
3161EXPORT_SYMBOL(mptscsih_qcmd);
0d0c7974
MED
3162EXPORT_SYMBOL(mptscsih_slave_destroy);
3163EXPORT_SYMBOL(mptscsih_slave_configure);
3164EXPORT_SYMBOL(mptscsih_abort);
3165EXPORT_SYMBOL(mptscsih_dev_reset);
3166EXPORT_SYMBOL(mptscsih_bus_reset);
3167EXPORT_SYMBOL(mptscsih_host_reset);
3168EXPORT_SYMBOL(mptscsih_bios_param);
3169EXPORT_SYMBOL(mptscsih_io_done);
3170EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3171EXPORT_SYMBOL(mptscsih_scandv_complete);
3172EXPORT_SYMBOL(mptscsih_event_process);
3173EXPORT_SYMBOL(mptscsih_ioc_reset);
6e3815ba 3174EXPORT_SYMBOL(mptscsih_change_queue_depth);
0d0c7974 3175EXPORT_SYMBOL(mptscsih_timer_expired);
663e1aa1 3176EXPORT_SYMBOL(mptscsih_TMHandler);
1da177e4 3177
0d0c7974 3178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/