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