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