blob: d70cb11de5c99c600af24bf809ea33e5d7e8ab24 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04006 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * (mailto:mpt_linux_developer@lsil.com)
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
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>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060065#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060069#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
72#define my_NAME "Fusion MPT SCSI Host driver"
73#define my_VERSION MPT_LINUX_VERSION_COMMON
74#define MYNAM "mptscsih"
75
76MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
81
82typedef struct _BIG_SENSE_BUF {
83 u8 data[MPT_SENSE_BUFFER_ALLOC];
84} BIG_SENSE_BUF;
85
86#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
87#define MPT_SCANDV_DID_RESET (0x00000001)
88#define MPT_SCANDV_SENSE (0x00000002)
89#define MPT_SCANDV_SOME_ERROR (0x00000004)
90#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
91#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
92#define MPT_SCANDV_FALLBACK (0x00000020)
93
94#define MPT_SCANDV_MAX_RETRIES (10)
95
96#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
97#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
Moore, Eric Dean466544d2005-09-14 18:09:10 -060098#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
99#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
100#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
102#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
103
104typedef struct _internal_cmd {
105 char *data; /* data pointer */
106 dma_addr_t data_dma; /* data dma address */
107 int size; /* transfer size */
108 u8 cmd; /* SCSI Op Code */
109 u8 bus; /* bus number */
110 u8 id; /* SCSI ID (virtual) */
111 u8 lun;
112 u8 flags; /* Bit Field - See above */
113 u8 physDiskNum; /* Phys disk number, -1 else */
114 u8 rsvd2;
115 u8 rsvd;
116} INTERNAL_CMD;
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*
119 * Other private/forward protos...
120 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400121int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400123int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
126 SCSIIORequest_t *pReq, int req_idx);
127static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400128static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
130static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -0600131static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
134
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400135int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
136int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
James Bottomleyc92f2222006-03-01 09:02:49 -0600138static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
139static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400141int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700143static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400145void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700146void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400148int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
149int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150#endif
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
155/**
156 * mptscsih_add_sge - Place a simple SGE at address pAddr.
157 * @pAddr: virtual address for SGE
158 * @flagslength: SGE flags and data transfer length
159 * @dma_addr: Physical address
160 *
161 * This routine places a MPT request frame back on the MPT adapter's
162 * FreeQ.
163 */
164static inline void
165mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
166{
167 if (sizeof(dma_addr_t) == sizeof(u64)) {
168 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
169 u32 tmp = dma_addr & 0xFFFFFFFF;
170
171 pSge->FlagsLength = cpu_to_le32(flagslength);
172 pSge->Address.Low = cpu_to_le32(tmp);
173 tmp = (u32) ((u64)dma_addr >> 32);
174 pSge->Address.High = cpu_to_le32(tmp);
175
176 } else {
177 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
178 pSge->FlagsLength = cpu_to_le32(flagslength);
179 pSge->Address = cpu_to_le32(dma_addr);
180 }
181} /* mptscsih_add_sge() */
182
183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
184/**
185 * mptscsih_add_chain - Place a chain SGE at address pAddr.
186 * @pAddr: virtual address for SGE
187 * @next: nextChainOffset value (u32's)
188 * @length: length of next SGL segment
189 * @dma_addr: Physical address
190 *
191 * This routine places a MPT request frame back on the MPT adapter's
192 * FreeQ.
193 */
194static inline void
195mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
196{
197 if (sizeof(dma_addr_t) == sizeof(u64)) {
198 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
199 u32 tmp = dma_addr & 0xFFFFFFFF;
200
201 pChain->Length = cpu_to_le16(length);
202 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
203
204 pChain->NextChainOffset = next;
205
206 pChain->Address.Low = cpu_to_le32(tmp);
207 tmp = (u32) ((u64)dma_addr >> 32);
208 pChain->Address.High = cpu_to_le32(tmp);
209 } else {
210 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
211 pChain->Length = cpu_to_le16(length);
212 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
213 pChain->NextChainOffset = next;
214 pChain->Address = cpu_to_le32(dma_addr);
215 }
216} /* mptscsih_add_chain() */
217
218/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
219/*
220 * mptscsih_getFreeChainBuffer - Function to get a free chain
221 * from the MPT_SCSI_HOST FreeChainQ.
222 * @ioc: Pointer to MPT_ADAPTER structure
223 * @req_idx: Index of the SCSI IO request frame. (output)
224 *
225 * return SUCCESS or FAILED
226 */
227static inline int
228mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
229{
230 MPT_FRAME_HDR *chainBuf;
231 unsigned long flags;
232 int rc;
233 int chain_idx;
234
235 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
236 ioc->name));
237 spin_lock_irqsave(&ioc->FreeQlock, flags);
238 if (!list_empty(&ioc->FreeChainQ)) {
239 int offset;
240
241 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
242 u.frame.linkage.list);
243 list_del(&chainBuf->u.frame.linkage.list);
244 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
245 chain_idx = offset / ioc->req_sz;
246 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200247 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
248 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 } else {
250 rc = FAILED;
251 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200252 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 ioc->name));
254 }
255 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
256
257 *retIndex = chain_idx;
258 return rc;
259} /* mptscsih_getFreeChainBuffer() */
260
261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
262/*
263 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
264 * SCSIIORequest_t Message Frame.
265 * @ioc: Pointer to MPT_ADAPTER structure
266 * @SCpnt: Pointer to scsi_cmnd structure
267 * @pReq: Pointer to SCSIIORequest_t structure
268 *
269 * Returns ...
270 */
271static int
272mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
273 SCSIIORequest_t *pReq, int req_idx)
274{
275 char *psge;
276 char *chainSge;
277 struct scatterlist *sg;
278 int frm_sz;
279 int sges_left, sg_done;
280 int chain_idx = MPT_HOST_NO_CHAIN;
281 int sgeOffset;
282 int numSgeSlots, numSgeThisFrame;
283 u32 sgflags, sgdir, thisxfer = 0;
284 int chain_dma_off = 0;
285 int newIndex;
286 int ii;
287 dma_addr_t v2;
288 u32 RequestNB;
289
290 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
291 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
292 sgdir = MPT_TRANSFER_HOST_TO_IOC;
293 } else {
294 sgdir = MPT_TRANSFER_IOC_TO_HOST;
295 }
296
297 psge = (char *) &pReq->SGL;
298 frm_sz = ioc->req_sz;
299
300 /* Map the data portion, if any.
301 * sges_left = 0 if no data transfer.
302 */
303 if ( (sges_left = SCpnt->use_sg) ) {
304 sges_left = pci_map_sg(ioc->pcidev,
305 (struct scatterlist *) SCpnt->request_buffer,
306 SCpnt->use_sg,
307 SCpnt->sc_data_direction);
308 if (sges_left == 0)
309 return FAILED;
310 } else if (SCpnt->request_bufflen) {
311 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
312 SCpnt->request_buffer,
313 SCpnt->request_bufflen,
314 SCpnt->sc_data_direction);
315 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
316 ioc->name, SCpnt, SCpnt->request_bufflen));
317 mptscsih_add_sge((char *) &pReq->SGL,
318 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
319 SCpnt->SCp.dma_handle);
320
321 return SUCCESS;
322 }
323
324 /* Handle the SG case.
325 */
326 sg = (struct scatterlist *) SCpnt->request_buffer;
327 sg_done = 0;
328 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
329 chainSge = NULL;
330
331 /* Prior to entering this loop - the following must be set
332 * current MF: sgeOffset (bytes)
333 * chainSge (Null if original MF is not a chain buffer)
334 * sg_done (num SGE done for this MF)
335 */
336
337nextSGEset:
338 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
339 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
340
341 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
342
343 /* Get first (num - 1) SG elements
344 * Skip any SG entries with a length of 0
345 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
346 */
347 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
348 thisxfer = sg_dma_len(sg);
349 if (thisxfer == 0) {
350 sg ++; /* Get next SG element from the OS */
351 sg_done++;
352 continue;
353 }
354
355 v2 = sg_dma_address(sg);
356 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
357
358 sg++; /* Get next SG element from the OS */
359 psge += (sizeof(u32) + sizeof(dma_addr_t));
360 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
361 sg_done++;
362 }
363
364 if (numSgeThisFrame == sges_left) {
365 /* Add last element, end of buffer and end of list flags.
366 */
367 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
368 MPT_SGE_FLAGS_END_OF_BUFFER |
369 MPT_SGE_FLAGS_END_OF_LIST;
370
371 /* Add last SGE and set termination flags.
372 * Note: Last SGE may have a length of 0 - which should be ok.
373 */
374 thisxfer = sg_dma_len(sg);
375
376 v2 = sg_dma_address(sg);
377 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
378 /*
379 sg++;
380 psge += (sizeof(u32) + sizeof(dma_addr_t));
381 */
382 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
383 sg_done++;
384
385 if (chainSge) {
386 /* The current buffer is a chain buffer,
387 * but there is not another one.
388 * Update the chain element
389 * Offset and Length fields.
390 */
391 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
392 } else {
393 /* The current buffer is the original MF
394 * and there is no Chain buffer.
395 */
396 pReq->ChainOffset = 0;
397 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200398 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
400 ioc->RequestNB[req_idx] = RequestNB;
401 }
402 } else {
403 /* At least one chain buffer is needed.
404 * Complete the first MF
405 * - last SGE element, set the LastElement bit
406 * - set ChainOffset (words) for orig MF
407 * (OR finish previous MF chain buffer)
408 * - update MFStructPtr ChainIndex
409 * - Populate chain element
410 * Also
411 * Loop until done.
412 */
413
414 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
415 ioc->name, sg_done));
416
417 /* Set LAST_ELEMENT flag for last non-chain element
418 * in the buffer. Since psge points at the NEXT
419 * SGE element, go back one SGE element, update the flags
420 * and reset the pointer. (Note: sgflags & thisxfer are already
421 * set properly).
422 */
423 if (sg_done) {
424 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
425 sgflags = le32_to_cpu(*ptmp);
426 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
427 *ptmp = cpu_to_le32(sgflags);
428 }
429
430 if (chainSge) {
431 /* The current buffer is a chain buffer.
432 * chainSge points to the previous Chain Element.
433 * Update its chain element Offset and Length (must
434 * include chain element size) fields.
435 * Old chain element is now complete.
436 */
437 u8 nextChain = (u8) (sgeOffset >> 2);
438 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
439 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
440 } else {
441 /* The original MF buffer requires a chain buffer -
442 * set the offset.
443 * Last element in this MF is a chain element.
444 */
445 pReq->ChainOffset = (u8) (sgeOffset >> 2);
446 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
447 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
448 ioc->RequestNB[req_idx] = RequestNB;
449 }
450
451 sges_left -= sg_done;
452
453
454 /* NOTE: psge points to the beginning of the chain element
455 * in current buffer. Get a chain buffer.
456 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200457 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
458 dfailprintk((MYIOC_s_INFO_FMT
459 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
460 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 /* Update the tracking arrays.
465 * If chainSge == NULL, update ReqToChain, else ChainToChain
466 */
467 if (chainSge) {
468 ioc->ChainToChain[chain_idx] = newIndex;
469 } else {
470 ioc->ReqToChain[req_idx] = newIndex;
471 }
472 chain_idx = newIndex;
473 chain_dma_off = ioc->req_sz * chain_idx;
474
475 /* Populate the chainSGE for the current buffer.
476 * - Set chain buffer pointer to psge and fill
477 * out the Address and Flags fields.
478 */
479 chainSge = (char *) psge;
480 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
481 psge, req_idx));
482
483 /* Start the SGE for the next buffer
484 */
485 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
486 sgeOffset = 0;
487 sg_done = 0;
488
489 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
490 psge, chain_idx));
491
492 /* Start the SGE for the next buffer
493 */
494
495 goto nextSGEset;
496 }
497
498 return SUCCESS;
499} /* mptscsih_AddSGE() */
500
Eric Moore786899b2006-07-11 17:22:22 -0600501static void
502mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
503 U32 SlotStatus)
504{
505 MPT_FRAME_HDR *mf;
506 SEPRequest_t *SEPMsg;
507
508 if (ioc->bus_type == FC)
509 return;
510
511 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
512 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
513 ioc->name,__FUNCTION__));
514 return;
515 }
516
517 SEPMsg = (SEPRequest_t *)mf;
518 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
519 SEPMsg->Bus = vtarget->bus_id;
520 SEPMsg->TargetID = vtarget->target_id;
521 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
522 SEPMsg->SlotStatus = SlotStatus;
523 devtverboseprintk((MYIOC_s_WARN_FMT
524 "Sending SEP cmd=%x id=%d bus=%d\n",
525 ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
526 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
527}
528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
530/*
531 * mptscsih_io_done - Main SCSI IO callback routine registered to
532 * Fusion MPT (base) driver
533 * @ioc: Pointer to MPT_ADAPTER structure
534 * @mf: Pointer to original MPT request frame
535 * @r: Pointer to MPT reply frame (NULL if TurboReply)
536 *
537 * This routine is called from mpt.c::mpt_interrupt() at the completion
538 * of any SCSI IO request.
539 * This routine is registered with the Fusion MPT (base) driver at driver
540 * load/init time via the mpt_register() API call.
541 *
542 * Returns 1 indicating alloc'd request frame ptr should be freed.
543 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400544int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
546{
547 struct scsi_cmnd *sc;
548 MPT_SCSI_HOST *hd;
549 SCSIIORequest_t *pScsiReq;
550 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700551 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600552 VirtDevice *vdev;
553 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
556
557 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700558 req_idx_MR = (mr != NULL) ?
559 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
560 if ((req_idx != req_idx_MR) ||
561 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
562 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
563 ioc->name);
564 printk (MYIOC_s_ERR_FMT
565 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
566 ioc->name, req_idx, req_idx_MR, mf, mr,
567 hd->ScsiLookup[req_idx_MR]);
568 return 0;
569 }
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600572 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 if (sc == NULL) {
574 MPIHeader_t *hdr = (MPIHeader_t *)mf;
575
576 /* Remark: writeSDP1 will use the ScsiDoneCtx
577 * If a SCSI I/O cmd, device disabled by OS and
578 * completion done. Cannot touch sc struct. Just free mem.
579 */
580 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
581 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
582 ioc->name);
583
584 mptscsih_freeChainBuffers(ioc, req_idx);
585 return 1;
586 }
587
Eric Moore3dc0b032006-07-11 17:32:33 -0600588 if ((unsigned char *)mf != sc->host_scribble) {
589 mptscsih_freeChainBuffers(ioc, req_idx);
590 return 1;
591 }
592
593 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 sc->result = DID_OK << 16; /* Set default reply as OK */
595 pScsiReq = (SCSIIORequest_t *) mf;
596 pScsiReply = (SCSIIOReply_t *) mr;
597
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200598 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
599 dmfprintk((MYIOC_s_INFO_FMT
600 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
601 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
602 }else{
603 dmfprintk((MYIOC_s_INFO_FMT
604 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
605 ioc->name, mf, mr, sc, req_idx));
606 }
607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 if (pScsiReply == NULL) {
609 /* special context reply handling */
610 ;
611 } else {
612 u32 xfer_cnt;
613 u16 status;
614 u8 scsi_state, scsi_status;
615
616 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
617 scsi_state = pScsiReply->SCSIState;
618 scsi_status = pScsiReply->SCSIStatus;
619 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
620 sc->resid = sc->request_bufflen - xfer_cnt;
621
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600622 /*
623 * if we get a data underrun indication, yet no data was
624 * transferred and the SCSI status indicates that the
625 * command was never started, change the data underrun
626 * to success
627 */
628 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
629 (scsi_status == MPI_SCSI_STATUS_BUSY ||
630 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
631 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
632 status = MPI_IOCSTATUS_SUCCESS;
633 }
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
636 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
637 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700638 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600639 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 sc->request_bufflen, xfer_cnt));
641
642 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400643 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 /*
646 * Look for + dump FCP ResponseInfo[]!
647 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600648 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
649 pScsiReply->ResponseInfo) {
650 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
651 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700652 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 le32_to_cpu(pScsiReply->ResponseInfo));
654 }
655
656 switch(status) {
657 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
658 /* CHECKME!
659 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
660 * But not: DID_BUS_BUSY lest one risk
661 * killing interrupt handler:-(
662 */
663 sc->result = SAM_STAT_BUSY;
664 break;
665
666 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
667 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
668 sc->result = DID_BAD_TARGET << 16;
669 break;
670
671 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
672 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600673 if (ioc->bus_type != FC)
674 sc->result = DID_NO_CONNECT << 16;
675 /* else fibre, just stall until rescan event */
676 else
677 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
680 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600681
682 vdev = sc->device->hostdata;
683 if (!vdev)
684 break;
685 vtarget = vdev->vtarget;
686 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
687 mptscsih_issue_sep_command(ioc, vtarget,
688 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
689 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 break;
692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600694 if ( ioc->bus_type == SAS ) {
695 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
696 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
697 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
698 log_info &=SAS_LOGINFO_MASK;
699 if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
700 sc->result = (DID_BUS_BUSY << 16);
701 break;
702 }
703 }
Eric Moore86dd4242007-01-04 20:44:01 -0700704 } else if (ioc->bus_type == FC) {
705 /*
706 * The FC IOC may kill a request for variety of
707 * reasons, some of which may be recovered by a
708 * retry, some which are unlikely to be
709 * recovered. Return DID_ERROR instead of
710 * DID_RESET to permit retry of the command,
711 * just not an infinite number of them
712 */
713 sc->result = DID_ERROR << 16;
714 break;
Eric Moorebf451522006-07-11 17:25:35 -0600715 }
716
717 /*
718 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
719 */
720
721 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
723 /* Linux handles an unsolicited DID_RESET better
724 * than an unsolicited DID_ABORT.
725 */
726 sc->result = DID_RESET << 16;
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 break;
729
730 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600731 sc->resid = sc->request_bufflen - xfer_cnt;
732 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
733 sc->result=DID_SOFT_ERROR << 16;
734 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600736 dreplyprintk((KERN_NOTICE
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600737 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
741 /*
742 * Do upfront check for valid SenseData and give it
743 * precedence!
744 */
745 sc->result = (DID_OK << 16) | scsi_status;
746 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
747 /* Have already saved the status and sense data
748 */
749 ;
750 } else {
751 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600752 if (scsi_status == SAM_STAT_BUSY)
753 sc->result = SAM_STAT_BUSY;
754 else
755 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 }
757 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
758 /* What to do?
759 */
760 sc->result = DID_SOFT_ERROR << 16;
761 }
762 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
763 /* Not real sure here either... */
764 sc->result = DID_RESET << 16;
765 }
766 }
767
768 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
769 sc->underflow));
770 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
771 /* Report Queue Full
772 */
773 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
774 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 break;
777
Moore, Eric7e551472006-01-16 18:53:21 -0700778 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
779 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
781 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600782 if (scsi_status == MPI_SCSI_STATUS_BUSY)
783 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
784 else
785 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (scsi_state == 0) {
787 ;
788 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
789 /*
790 * If running against circa 200003dd 909 MPT f/w,
791 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
792 * (QUEUE_FULL) returned from device! --> get 0x0000?128
793 * and with SenseBytes set to 0.
794 */
795 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
796 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
797
798 }
799 else if (scsi_state &
800 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
801 ) {
802 /*
803 * What to do?
804 */
805 sc->result = DID_SOFT_ERROR << 16;
806 }
807 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
808 /* Not real sure here either... */
809 sc->result = DID_RESET << 16;
810 }
811 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
812 /* Device Inq. data indicates that it supports
813 * QTags, but rejects QTag messages.
814 * This command completed OK.
815 *
816 * Not real sure here either so do nothing... */
817 }
818
819 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
820 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
821
822 /* Add handling of:
823 * Reservation Conflict, Busy,
824 * Command Terminated, CHECK
825 */
826 break;
827
828 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
829 sc->result = DID_SOFT_ERROR << 16;
830 break;
831
832 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
833 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
834 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
835 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
836 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
837 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
838 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
840 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
841 default:
842 /*
843 * What to do?
844 */
845 sc->result = DID_SOFT_ERROR << 16;
846 break;
847
848 } /* switch(status) */
849
850 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
851 } /* end of address reply case */
852
853 /* Unmap the DMA buffers, if any. */
854 if (sc->use_sg) {
855 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
856 sc->use_sg, sc->sc_data_direction);
857 } else if (sc->request_bufflen) {
858 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
859 sc->request_bufflen, sc->sc_data_direction);
860 }
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 sc->scsi_done(sc); /* Issue the command callback */
863
864 /* Free Chain buffers */
865 mptscsih_freeChainBuffers(ioc, req_idx);
866 return 1;
867}
868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869/*
870 * mptscsih_flush_running_cmds - For each command found, search
871 * Scsi_Host instance taskQ and reply to OS.
872 * Called only if recovering from a FW reload.
873 * @hd: Pointer to a SCSI HOST structure
874 *
875 * Returns: None.
876 *
877 * Must be called while new I/Os are being queued.
878 */
879static void
880mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
881{
882 MPT_ADAPTER *ioc = hd->ioc;
883 struct scsi_cmnd *SCpnt;
884 MPT_FRAME_HDR *mf;
885 int ii;
886 int max = ioc->req_depth;
887
888 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
889 for (ii= 0; ii < max; ii++) {
890 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
891
892 /* Command found.
893 */
894
895 /* Null ScsiLookup index
896 */
897 hd->ScsiLookup[ii] = NULL;
898
899 mf = MPT_INDEX_2_MFPTR(ioc, ii);
900 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
901 mf, SCpnt));
902
Eric Moore3dc0b032006-07-11 17:32:33 -0600903 /* Free Chain buffers */
904 mptscsih_freeChainBuffers(ioc, ii);
905
906 /* Free Message frames */
907 mpt_free_msg_frame(ioc, mf);
908
909 if ((unsigned char *)mf != SCpnt->host_scribble)
910 continue;
911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 /* Set status, free OS resources (SG DMA buffers)
913 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400915 if (SCpnt->use_sg) {
916 pci_unmap_sg(ioc->pcidev,
917 (struct scatterlist *) SCpnt->request_buffer,
918 SCpnt->use_sg,
919 SCpnt->sc_data_direction);
920 } else if (SCpnt->request_bufflen) {
921 pci_unmap_single(ioc->pcidev,
922 SCpnt->SCp.dma_handle,
923 SCpnt->request_bufflen,
924 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926 SCpnt->result = DID_RESET << 16;
927 SCpnt->host_scribble = NULL;
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
930 }
931 }
932
933 return;
934}
935
936/*
937 * mptscsih_search_running_cmds - Delete any commands associated
938 * with the specified target and lun. Function called only
939 * when a lun is disable by mid-layer.
940 * Do NOT access the referenced scsi_cmnd structure or
941 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600942 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700943 * @hd: Pointer to a SCSI HOST structure
944 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 *
946 * Returns: None.
947 *
948 * Called from slave_destroy.
949 */
950static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700951mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 SCSIIORequest_t *mf = NULL;
954 int ii;
955 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600956 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Ericbd23e942006-04-17 12:43:04 -0600959 vdevice->vtarget->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600962 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
964 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600965 if (mf == NULL)
966 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
968 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
Moore, Eric914c2d82006-03-14 09:19:36 -0700969 if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 continue;
971
972 /* Cleanup
973 */
974 hd->ScsiLookup[ii] = NULL;
975 mptscsih_freeChainBuffers(hd->ioc, ii);
976 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -0600977 if ((unsigned char *)mf != sc->host_scribble)
978 continue;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600979 if (sc->use_sg) {
980 pci_unmap_sg(hd->ioc->pcidev,
981 (struct scatterlist *) sc->request_buffer,
982 sc->use_sg,
983 sc->sc_data_direction);
984 } else if (sc->request_bufflen) {
985 pci_unmap_single(hd->ioc->pcidev,
986 sc->SCp.dma_handle,
987 sc->request_bufflen,
988 sc->sc_data_direction);
989 }
990 sc->host_scribble = NULL;
991 sc->result = DID_NO_CONNECT << 16;
992 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 }
994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 return;
996}
997
998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1001/*
1002 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1003 * from a SCSI target device.
1004 * @sc: Pointer to scsi_cmnd structure
1005 * @pScsiReply: Pointer to SCSIIOReply_t
1006 * @pScsiReq: Pointer to original SCSI request
1007 *
1008 * This routine periodically reports QUEUE_FULL status returned from a
1009 * SCSI target device. It reports this to the console via kernel
1010 * printk() API call, not more than once every 10 seconds.
1011 */
1012static void
1013mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1014{
1015 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001018 if (sc->device == NULL)
1019 return;
1020 if (sc->device->host == NULL)
1021 return;
1022 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1023 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001025 if (time - hd->last_queue_full > 10 * HZ) {
1026 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1027 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1028 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030}
1031
1032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1033/*
1034 * mptscsih_remove - Removed scsi devices
1035 * @pdev: Pointer to pci_dev structure
1036 *
1037 *
1038 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001039void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040mptscsih_remove(struct pci_dev *pdev)
1041{
1042 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1043 struct Scsi_Host *host = ioc->sh;
1044 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001045 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001047 if(!host) {
1048 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052 scsi_remove_host(host);
1053
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001054 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1055 return;
1056
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001057 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001059 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001061 if (hd->ScsiLookup != NULL) {
1062 sz1 = hd->ioc->req_depth * sizeof(void *);
1063 kfree(hd->ScsiLookup);
1064 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 }
1066
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001067 /*
1068 * Free pointer array.
1069 */
1070 kfree(hd->Targets);
1071 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001073 dprintk((MYIOC_s_INFO_FMT
1074 "Free'd ScsiLookup (%d) memory\n",
1075 hd->ioc->name, sz1));
1076
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001077 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001078
1079 /* NULL the Scsi_Host pointer
1080 */
1081 hd->ioc->sh = NULL;
1082
1083 scsi_host_put(host);
1084
1085 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087}
1088
1089/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1090/*
1091 * mptscsih_shutdown - reboot notifier
1092 *
1093 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001094void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001095mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001097 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 struct Scsi_Host *host = ioc->sh;
1099 MPT_SCSI_HOST *hd;
1100
1101 if(!host)
1102 return;
1103
1104 hd = (MPT_SCSI_HOST *)host->hostdata;
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
1108#ifdef CONFIG_PM
1109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1110/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001111 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 *
1113 *
1114 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001115int
Pavel Machek8d189f72005-04-16 15:25:28 -07001116mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001118 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001119 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
1122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1123/*
1124 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1125 *
1126 *
1127 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129mptscsih_resume(struct pci_dev *pdev)
1130{
1131 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1132 struct Scsi_Host *host = ioc->sh;
1133 MPT_SCSI_HOST *hd;
1134
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001135 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if(!host)
1138 return 0;
1139
1140 hd = (MPT_SCSI_HOST *)host->hostdata;
1141 if(!hd)
1142 return 0;
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return 0;
1145}
1146
1147#endif
1148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1150/**
1151 * mptscsih_info - Return information about MPT adapter
1152 * @SChost: Pointer to Scsi_Host structure
1153 *
1154 * (linux scsi_host_template.info routine)
1155 *
1156 * Returns pointer to buffer where information was written.
1157 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001158const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159mptscsih_info(struct Scsi_Host *SChost)
1160{
1161 MPT_SCSI_HOST *h;
1162 int size = 0;
1163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001167 if (h->info_kbuf == NULL)
1168 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1169 return h->info_kbuf;
1170 h->info_kbuf[0] = '\0';
1171
1172 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1173 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001176 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177}
1178
1179struct info_str {
1180 char *buffer;
1181 int length;
1182 int offset;
1183 int pos;
1184};
1185
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001186static void
1187mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
1189 if (info->pos + len > info->length)
1190 len = info->length - info->pos;
1191
1192 if (info->pos + len < info->offset) {
1193 info->pos += len;
1194 return;
1195 }
1196
1197 if (info->pos < info->offset) {
1198 data += (info->offset - info->pos);
1199 len -= (info->offset - info->pos);
1200 }
1201
1202 if (len > 0) {
1203 memcpy(info->buffer + info->pos, data, len);
1204 info->pos += len;
1205 }
1206}
1207
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001208static int
1209mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210{
1211 va_list args;
1212 char buf[81];
1213 int len;
1214
1215 va_start(args, fmt);
1216 len = vsprintf(buf, fmt, args);
1217 va_end(args);
1218
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001219 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 return len;
1221}
1222
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001223static int
1224mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225{
1226 struct info_str info;
1227
1228 info.buffer = pbuf;
1229 info.length = len;
1230 info.offset = offset;
1231 info.pos = 0;
1232
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001233 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1234 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1235 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1236 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
1238 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1239}
1240
1241/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1242/**
1243 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001244 * @host: scsi host struct
1245 * @buffer: if write, user data; if read, buffer for user
1246 * @start: returns the buffer address
1247 * @offset: if write, 0; if read, the current offset into the buffer from
1248 * the previous read.
1249 * @length: if write, return length;
1250 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 *
1252 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001254int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1256 int length, int func)
1257{
1258 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1259 MPT_ADAPTER *ioc = hd->ioc;
1260 int size = 0;
1261
1262 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001263 /*
1264 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 */
1266 } else {
1267 if (start)
1268 *start = buffer;
1269
1270 size = mptscsih_host_info(ioc, buffer, offset, length);
1271 }
1272
1273 return size;
1274}
1275
1276/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1277#define ADD_INDEX_LOG(req_ent) do { } while(0)
1278
1279/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1280/**
1281 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1282 * @SCpnt: Pointer to scsi_cmnd structure
1283 * @done: Pointer SCSI mid-layer IO completion function
1284 *
1285 * (linux scsi_host_template.queuecommand routine)
1286 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1287 * from a linux scsi_cmnd request and send it to the IOC.
1288 *
1289 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1290 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001291int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1293{
1294 MPT_SCSI_HOST *hd;
1295 MPT_FRAME_HDR *mf;
1296 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001297 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 int lun;
1299 u32 datalen;
1300 u32 scsictl;
1301 u32 scsidir;
1302 u32 cmd_len;
1303 int my_idx;
1304 int ii;
1305
1306 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 lun = SCpnt->device->lun;
1308 SCpnt->scsi_done = done;
1309
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1311 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1312
1313 if (hd->resetPending) {
1314 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1315 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1316 return SCSI_MLQUEUE_HOST_BUSY;
1317 }
1318
Moore, Ericf44e5462006-03-14 09:14:21 -07001319 if ((hd->ioc->bus_type == SPI) &&
1320 vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001321 mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
1322 SCpnt->result = DID_NO_CONNECT << 16;
1323 done(SCpnt);
1324 return 0;
1325 }
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 /*
1328 * Put together a MPT SCSI request...
1329 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001330 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1332 hd->ioc->name));
1333 return SCSI_MLQUEUE_HOST_BUSY;
1334 }
1335
1336 pScsiReq = (SCSIIORequest_t *) mf;
1337
1338 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1339
1340 ADD_INDEX_LOG(my_idx);
1341
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001342 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 * Seems we may receive a buffer (datalen>0) even when there
1344 * will be no data transfer! GRRRRR...
1345 */
1346 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1347 datalen = SCpnt->request_bufflen;
1348 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1349 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1350 datalen = SCpnt->request_bufflen;
1351 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1352 } else {
1353 datalen = 0;
1354 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1355 }
1356
1357 /* Default to untagged. Once a target structure has been allocated,
1358 * use the Inquiry data to determine if device supports tagged.
1359 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001360 if (vdev
1361 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 && (SCpnt->device->tagged_supported)) {
1363 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1364 } else {
1365 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1366 }
1367
1368 /* Use the above information to set up the message frame
1369 */
Moore, Eric914c2d82006-03-14 09:19:36 -07001370 pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
1371 pScsiReq->Bus = vdev->vtarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001373 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1374 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1375 else
1376 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 pScsiReq->CDBLength = SCpnt->cmd_len;
1378 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1379 pScsiReq->Reserved = 0;
1380 pScsiReq->MsgFlags = mpt_msg_flags();
1381 pScsiReq->LUN[0] = 0;
1382 pScsiReq->LUN[1] = lun;
1383 pScsiReq->LUN[2] = 0;
1384 pScsiReq->LUN[3] = 0;
1385 pScsiReq->LUN[4] = 0;
1386 pScsiReq->LUN[5] = 0;
1387 pScsiReq->LUN[6] = 0;
1388 pScsiReq->LUN[7] = 0;
1389 pScsiReq->Control = cpu_to_le32(scsictl);
1390
1391 /*
1392 * Write SCSI CDB into the message
1393 */
1394 cmd_len = SCpnt->cmd_len;
1395 for (ii=0; ii < cmd_len; ii++)
1396 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1397
1398 for (ii=cmd_len; ii < 16; ii++)
1399 pScsiReq->CDB[ii] = 0;
1400
1401 /* DataLength */
1402 pScsiReq->DataLength = cpu_to_le32(datalen);
1403
1404 /* SenseBuffer low address */
1405 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1406 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1407
1408 /* Now add the SG list
1409 * Always have a SGE even if null length.
1410 */
1411 if (datalen == 0) {
1412 /* Add a NULL SGE */
1413 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1414 (dma_addr_t) -1);
1415 } else {
1416 /* Add a 32 or 64 bit SGE */
1417 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1418 goto fail;
1419 }
1420
Eric Moore3dc0b032006-07-11 17:32:33 -06001421 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001424 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1426 hd->ioc->name, SCpnt, mf, my_idx));
1427 DBG_DUMP_REQUEST_FRAME(mf)
1428 return 0;
1429
1430 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001431 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1433 mpt_free_msg_frame(hd->ioc, mf);
1434 return SCSI_MLQUEUE_HOST_BUSY;
1435}
1436
1437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1438/*
1439 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1440 * with a SCSI IO request
1441 * @hd: Pointer to the MPT_SCSI_HOST instance
1442 * @req_idx: Index of the SCSI IO request frame.
1443 *
1444 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1445 * No return.
1446 */
1447static void
1448mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1449{
1450 MPT_FRAME_HDR *chain;
1451 unsigned long flags;
1452 int chain_idx;
1453 int next;
1454
1455 /* Get the first chain index and reset
1456 * tracker state.
1457 */
1458 chain_idx = ioc->ReqToChain[req_idx];
1459 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1460
1461 while (chain_idx != MPT_HOST_NO_CHAIN) {
1462
1463 /* Save the next chain buffer index */
1464 next = ioc->ChainToChain[chain_idx];
1465
1466 /* Free this chain buffer and reset
1467 * tracker
1468 */
1469 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1470
1471 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1472 + (chain_idx * ioc->req_sz));
1473
1474 spin_lock_irqsave(&ioc->FreeQlock, flags);
1475 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1476 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1477
1478 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1479 ioc->name, chain_idx));
1480
1481 /* handle next */
1482 chain_idx = next;
1483 }
1484 return;
1485}
1486
1487/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1488/*
1489 * Reset Handling
1490 */
1491
1492/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1493/*
1494 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1495 * Fall through to mpt_HardResetHandler if: not operational, too many
1496 * failed TM requests or handshake failure.
1497 *
1498 * @ioc: Pointer to MPT_ADAPTER structure
1499 * @type: Task Management type
1500 * @target: Logical Target ID for reset (if appropriate)
1501 * @lun: Logical Unit for reset (if appropriate)
1502 * @ctx2abort: Context for the task to be aborted (if appropriate)
1503 *
1504 * Remark: Currently invoked from a non-interrupt thread (_bh).
1505 *
1506 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1507 * will be active.
1508 *
1509 * Returns 0 for SUCCESS or -1 if FAILED.
1510 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001511int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1513{
1514 MPT_ADAPTER *ioc;
1515 int rc = -1;
1516 int doTask = 1;
1517 u32 ioc_raw_state;
1518 unsigned long flags;
1519
1520 /* If FW is being reloaded currently, return success to
1521 * the calling function.
1522 */
1523 if (hd == NULL)
1524 return 0;
1525
1526 ioc = hd->ioc;
1527 if (ioc == NULL) {
1528 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1529 return FAILED;
1530 }
1531 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1532
1533 // SJR - CHECKME - Can we avoid this here?
1534 // (mpt_HardResetHandler has this check...)
1535 spin_lock_irqsave(&ioc->diagLock, flags);
1536 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1537 spin_unlock_irqrestore(&ioc->diagLock, flags);
1538 return FAILED;
1539 }
1540 spin_unlock_irqrestore(&ioc->diagLock, flags);
1541
1542 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1543 * If we time out and not bus reset, then we return a FAILED status to the caller.
1544 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1545 * successful. Otherwise, reload the FW.
1546 */
1547 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1548 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001549 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 "Timed out waiting for last TM (%d) to complete! \n",
1551 hd->ioc->name, hd->tmPending));
1552 return FAILED;
1553 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001554 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 "Timed out waiting for last TM (%d) to complete! \n",
1556 hd->ioc->name, hd->tmPending));
1557 return FAILED;
1558 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001559 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 "Timed out waiting for last TM (%d) to complete! \n",
1561 hd->ioc->name, hd->tmPending));
1562 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1563 return FAILED;
1564
1565 doTask = 0;
1566 }
1567 } else {
1568 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1569 hd->tmPending |= (1 << type);
1570 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1571 }
1572
1573 /* Is operational?
1574 */
1575 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1576
1577#ifdef MPT_DEBUG_RESET
1578 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1579 printk(MYIOC_s_WARN_FMT
1580 "TM Handler: IOC Not operational(0x%x)!\n",
1581 hd->ioc->name, ioc_raw_state);
1582 }
1583#endif
1584
1585 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1586 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1587
1588 /* Isse the Task Mgmt request.
1589 */
1590 if (hd->hard_resets < -1)
1591 hd->hard_resets++;
1592 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1593 if (rc) {
1594 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1595 } else {
1596 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1597 }
1598 }
1599
1600 /* Only fall through to the HRH if this is a bus reset
1601 */
1602 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1603 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1604 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1605 hd->ioc->name));
1606 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1607 }
1608
Eric Moore3dc0b032006-07-11 17:32:33 -06001609 /*
1610 * Check IOCStatus from TM reply message
1611 */
1612 if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
1613 rc = FAILED;
1614
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1616
1617 return rc;
1618}
1619
1620
1621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1622/*
1623 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1624 * @hd: Pointer to MPT_SCSI_HOST structure
1625 * @type: Task Management type
1626 * @target: Logical Target ID for reset (if appropriate)
1627 * @lun: Logical Unit for reset (if appropriate)
1628 * @ctx2abort: Context for the task to be aborted (if appropriate)
1629 *
1630 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1631 * or a non-interrupt thread. In the former, must not call schedule().
1632 *
1633 * Not all fields are meaningfull for all task types.
1634 *
1635 * Returns 0 for SUCCESS, -999 for "no msg frames",
1636 * else other non-zero value returned.
1637 */
1638static int
1639mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1640{
1641 MPT_FRAME_HDR *mf;
1642 SCSITaskMgmt_t *pScsiTm;
1643 int ii;
1644 int retval;
1645
1646 /* Return Fail to calling function if no message frames available.
1647 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001648 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1650 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001651 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 }
1653 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1654 hd->ioc->name, mf));
1655
1656 /* Format the Request
1657 */
1658 pScsiTm = (SCSITaskMgmt_t *) mf;
1659 pScsiTm->TargetID = target;
1660 pScsiTm->Bus = channel;
1661 pScsiTm->ChainOffset = 0;
1662 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1663
1664 pScsiTm->Reserved = 0;
1665 pScsiTm->TaskType = type;
1666 pScsiTm->Reserved1 = 0;
1667 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1668 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1669
1670 for (ii= 0; ii < 8; ii++) {
1671 pScsiTm->LUN[ii] = 0;
1672 }
1673 pScsiTm->LUN[1] = lun;
1674
1675 for (ii=0; ii < 7; ii++)
1676 pScsiTm->Reserved2[ii] = 0;
1677
1678 pScsiTm->TaskMsgContext = ctx2abort;
1679
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001680 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1681 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1684
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001685 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1687 CAN_SLEEP)) != 0) {
1688 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1689 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1690 hd->ioc, mf));
1691 mpt_free_msg_frame(hd->ioc, mf);
1692 return retval;
1693 }
1694
1695 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1696 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1697 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1698 hd->ioc, mf));
1699 mpt_free_msg_frame(hd->ioc, mf);
1700 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1701 hd->ioc->name));
1702 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1703 }
1704
1705 return retval;
1706}
1707
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001708static int
1709mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1710{
1711 switch (ioc->bus_type) {
1712 case FC:
1713 return 40;
1714 case SAS:
1715 return 10;
1716 case SPI:
1717 default:
1718 return 2;
1719 }
1720}
1721
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1723/**
1724 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1725 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1726 *
1727 * (linux scsi_host_template.eh_abort_handler routine)
1728 *
1729 * Returns SUCCESS or FAILED.
1730 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001731int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732mptscsih_abort(struct scsi_cmnd * SCpnt)
1733{
1734 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 MPT_FRAME_HDR *mf;
1736 u32 ctx2abort;
1737 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001738 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001739 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001740 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
1742 /* If we can't locate our host adapter structure, return FAILED status.
1743 */
1744 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1745 SCpnt->result = DID_RESET << 16;
1746 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001747 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 "Can't locate host! (sc=%p)\n",
1749 SCpnt));
1750 return FAILED;
1751 }
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 /* Find this command
1754 */
1755 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001756 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 * Do OS callback.
1758 */
1759 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001760 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 "Command not in the active list! (sc=%p)\n",
1762 hd->ioc->name, SCpnt));
1763 return SUCCESS;
1764 }
1765
Moore, Eric65207fe2006-04-21 16:14:35 -06001766 if (hd->resetPending) {
1767 return FAILED;
1768 }
1769
1770 if (hd->timeouts < -1)
1771 hd->timeouts++;
1772
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001773 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1774 hd->ioc->name, SCpnt);
1775 scsi_print_command(SCpnt);
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1778 * (the IO to be ABORT'd)
1779 *
1780 * NOTE: Since we do not byteswap MsgContext, we do not
1781 * swap it here either. It is an opaque cookie to
1782 * the controller, so it does not matter. -DaveM
1783 */
1784 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1785 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1786
1787 hd->abortSCpnt = SCpnt;
1788
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001789 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001790 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric914c2d82006-03-14 09:19:36 -07001791 vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001792 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Eric Moore3dc0b032006-07-11 17:32:33 -06001794 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
1795 SCpnt->serial_number == sn) {
1796 retval = FAILED;
1797 }
1798
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1800 hd->ioc->name,
1801 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001803 if (retval == 0)
1804 return SUCCESS;
1805
1806 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 hd->tmPending = 0;
1808 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001810 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811}
1812
1813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1814/**
1815 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1816 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1817 *
1818 * (linux scsi_host_template.eh_dev_reset_handler routine)
1819 *
1820 * Returns SUCCESS or FAILED.
1821 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001822int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1824{
1825 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001826 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001827 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
1829 /* If we can't locate our host adapter structure, return FAILED status.
1830 */
1831 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001832 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 "Can't locate host! (sc=%p)\n",
1834 SCpnt));
1835 return FAILED;
1836 }
1837
1838 if (hd->resetPending)
1839 return FAILED;
1840
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001841 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001843 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001845 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001846 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -07001847 vdev->vtarget->bus_id, vdev->vtarget->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001848 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001849
1850 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1851 hd->ioc->name,
1852 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1853
1854 if (retval == 0)
1855 return SUCCESS;
1856
1857 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 hd->tmPending = 0;
1859 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001861 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
1864/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1865/**
1866 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1867 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1868 *
1869 * (linux scsi_host_template.eh_bus_reset_handler routine)
1870 *
1871 * Returns SUCCESS or FAILED.
1872 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001873int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1875{
1876 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001877 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001878 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880 /* If we can't locate our host adapter structure, return FAILED status.
1881 */
1882 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001883 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 "Can't locate host! (sc=%p)\n",
1885 SCpnt ) );
1886 return FAILED;
1887 }
1888
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001889 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001891 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
1893 if (hd->timeouts < -1)
1894 hd->timeouts++;
1895
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001896 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001897 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric914c2d82006-03-14 09:19:36 -07001898 vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001900 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1901 hd->ioc->name,
1902 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1903
1904 if (retval == 0)
1905 return SUCCESS;
1906
1907 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 hd->tmPending = 0;
1909 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001911 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912}
1913
1914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1915/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001916 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1918 *
1919 * (linux scsi_host_template.eh_host_reset_handler routine)
1920 *
1921 * Returns SUCCESS or FAILED.
1922 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001923int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1925{
1926 MPT_SCSI_HOST * hd;
1927 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
1929 /* If we can't locate the host to reset, then we failed. */
1930 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001931 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 "Can't locate host! (sc=%p)\n",
1933 SCpnt ) );
1934 return FAILED;
1935 }
1936
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001937 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 hd->ioc->name, SCpnt);
1939
1940 /* If our attempts to reset the host failed, then return a failed
1941 * status. The host will be taken off line by the SCSI mid-layer.
1942 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1944 status = FAILED;
1945 } else {
1946 /* Make sure TM pending is cleared and TM state is set to
1947 * NONE.
1948 */
1949 hd->tmPending = 0;
1950 hd->tmState = TM_STATE_NONE;
1951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001953 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 "Status = %s\n",
1955 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1956
1957 return status;
1958}
1959
1960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1961/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001962 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 * @hd: Pointer to MPT host structure.
1964 *
1965 * Returns {SUCCESS,FAILED}.
1966 */
1967static int
1968mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1969{
1970 unsigned long flags;
1971 int loop_count = 4 * 10; /* Wait 10 seconds */
1972 int status = FAILED;
1973
1974 do {
1975 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1976 if (hd->tmState == TM_STATE_NONE) {
1977 hd->tmState = TM_STATE_IN_PROGRESS;
1978 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001980 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 break;
1982 }
1983 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1984 msleep(250);
1985 } while (--loop_count);
1986
1987 return status;
1988}
1989
1990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1991/**
1992 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1993 * @hd: Pointer to MPT host structure.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001994 * @timeout: timeout in seconds
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 *
1996 * Returns {SUCCESS,FAILED}.
1997 */
1998static int
1999mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2000{
2001 unsigned long flags;
2002 int loop_count = 4 * timeout;
2003 int status = FAILED;
2004
2005 do {
2006 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2007 if(hd->tmPending == 0) {
2008 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002009 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 break;
2011 }
2012 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002013 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 } while (--loop_count);
2015
2016 return status;
2017}
2018
2019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002020static void
2021mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2022{
2023 char *desc;
2024
2025 switch (response_code) {
2026 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2027 desc = "The task completed.";
2028 break;
2029 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2030 desc = "The IOC received an invalid frame status.";
2031 break;
2032 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2033 desc = "The task type is not supported.";
2034 break;
2035 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2036 desc = "The requested task failed.";
2037 break;
2038 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2039 desc = "The task completed successfully.";
2040 break;
2041 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2042 desc = "The LUN request is invalid.";
2043 break;
2044 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2045 desc = "The task is in the IOC queue and has not been sent to target.";
2046 break;
2047 default:
2048 desc = "unknown";
2049 break;
2050 }
2051 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2052 ioc->name, response_code, desc);
2053}
2054
2055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056/**
2057 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2058 * @ioc: Pointer to MPT_ADAPTER structure
2059 * @mf: Pointer to SCSI task mgmt request frame
2060 * @mr: Pointer to SCSI task mgmt reply frame
2061 *
2062 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2063 * of any SCSI task management request.
2064 * This routine is registered with the MPT (base) driver at driver
2065 * load/init time via the mpt_register() API call.
2066 *
2067 * Returns 1 indicating alloc'd request frame ptr should be freed.
2068 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002069int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2071{
2072 SCSITaskMgmtReply_t *pScsiTmReply;
2073 SCSITaskMgmt_t *pScsiTmReq;
2074 MPT_SCSI_HOST *hd;
2075 unsigned long flags;
2076 u16 iocstatus;
2077 u8 tmType;
2078
2079 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2080 ioc->name, mf, mr));
2081 if (ioc->sh) {
2082 /* Depending on the thread, a timer is activated for
2083 * the TM request. Delete this timer on completion of TM.
2084 * Decrement count of outstanding TM requests.
2085 */
2086 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2087 } else {
2088 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2089 ioc->name));
2090 return 1;
2091 }
2092
2093 if (mr == NULL) {
2094 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2095 ioc->name, mf));
2096 return 1;
2097 } else {
2098 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2099 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2100
2101 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2102 tmType = pScsiTmReq->TaskType;
2103
Moore, Eric9f63bb72006-01-16 18:53:26 -07002104 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2105 pScsiTmReply->ResponseCode)
2106 mptscsih_taskmgmt_response_code(ioc,
2107 pScsiTmReply->ResponseCode);
2108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2110 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2111 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2112
2113 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore3dc0b032006-07-11 17:32:33 -06002114 hd->tm_iocstatus = iocstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2116 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2117 /* Error? (anything non-zero?) */
2118 if (iocstatus) {
2119
2120 /* clear flags and continue.
2121 */
2122 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2123 hd->abortSCpnt = NULL;
2124
2125 /* If an internal command is present
2126 * or the TM failed - reload the FW.
2127 * FC FW may respond FAILED to an ABORT
2128 */
2129 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2130 if ((hd->cmdPtr) ||
2131 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2132 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2133 printk((KERN_WARNING
2134 " Firmware Reload FAILED!!\n"));
2135 }
2136 }
2137 }
2138 } else {
2139 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2140
2141 hd->abortSCpnt = NULL;
2142
2143 }
2144 }
2145
2146 spin_lock_irqsave(&ioc->FreeQlock, flags);
2147 hd->tmPending = 0;
2148 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2149 hd->tmState = TM_STATE_NONE;
2150
2151 return 1;
2152}
2153
2154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2155/*
2156 * This is anyones guess quite frankly.
2157 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002158int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2160 sector_t capacity, int geom[])
2161{
2162 int heads;
2163 int sectors;
2164 sector_t cylinders;
2165 ulong dummy;
2166
2167 heads = 64;
2168 sectors = 32;
2169
2170 dummy = heads * sectors;
2171 cylinders = capacity;
2172 sector_div(cylinders,dummy);
2173
2174 /*
2175 * Handle extended translation size for logical drives
2176 * > 1Gb
2177 */
2178 if ((ulong)capacity >= 0x200000) {
2179 heads = 255;
2180 sectors = 63;
2181 dummy = heads * sectors;
2182 cylinders = capacity;
2183 sector_div(cylinders,dummy);
2184 }
2185
2186 /* return result */
2187 geom[0] = heads;
2188 geom[1] = sectors;
2189 geom[2] = cylinders;
2190
2191 dprintk((KERN_NOTICE
2192 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2193 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2194
2195 return 0;
2196}
2197
Moore, Ericf44e5462006-03-14 09:14:21 -07002198/* Search IOC page 3 to determine if this is hidden physical disk
2199 *
2200 */
2201int
2202mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2203{
2204 int i;
2205
2206 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2207 return 0;
2208 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2209 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2210 return 1;
2211 }
2212 return 0;
2213}
2214EXPORT_SYMBOL(mptscsih_is_phys_disk);
2215
James Bottomleyc92f2222006-03-01 09:02:49 -06002216int
2217mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2218{
2219 int i;
2220
2221 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2222 return -ENXIO;
2223
2224 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2225 if (physdiskid ==
2226 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2227 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2228 }
2229
2230 return -ENXIO;
2231}
2232EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2233
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2235/*
2236 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002237 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002240int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002241mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002243 VirtTarget *vtarget;
2244
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002245 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002246 if (!vtarget)
2247 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002248 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002249 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002250 return 0;
2251}
2252
2253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2254/*
2255 * OS entry point to allow host driver to alloc memory
2256 * for each scsi device. Called once per device the bus scan.
2257 * Return non-zero if allocation fails.
2258 */
2259int
2260mptscsih_slave_alloc(struct scsi_device *sdev)
2261{
2262 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002264 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002266 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002268 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 if (!vdev) {
2270 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2271 hd->ioc->name, sizeof(VirtDevice));
2272 return -ENOMEM;
2273 }
2274
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002275 vdev->lun = sdev->lun;
2276 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002278 starget = scsi_target(sdev);
2279 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002280
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002281 vdev->vtarget = vtarget;
2282
2283 if (vtarget->num_luns == 0) {
2284 hd->Targets[sdev->id] = vtarget;
2285 vtarget->ioc_id = hd->ioc->id;
2286 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2287 vtarget->target_id = sdev->id;
2288 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002289 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2290 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2291 vtarget->raidVolume = 1;
2292 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002293 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002294 }
2295 }
2296 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 return 0;
2298}
2299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300/*
2301 * OS entry point to allow for host driver to free allocated memory
2302 * Called if no device present or device being unloaded
2303 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002304void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002305mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002307 if (starget->hostdata)
2308 kfree(starget->hostdata);
2309 starget->hostdata = NULL;
2310}
2311
2312/*
2313 * OS entry point to allow for host driver to free allocated memory
2314 * Called if no device present or device being unloaded
2315 */
2316void
2317mptscsih_slave_destroy(struct scsi_device *sdev)
2318{
2319 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002321 VirtTarget *vtarget;
2322 VirtDevice *vdevice;
2323 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002325 starget = scsi_target(sdev);
2326 vtarget = starget->hostdata;
2327 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002329 mptscsih_search_running_cmds(hd, vdevice);
2330 vtarget->luns[0] &= ~(1 << vdevice->lun);
2331 vtarget->num_luns--;
2332 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002333 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002335 mptscsih_synchronize_cache(hd, vdevice);
2336 kfree(vdevice);
2337 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338}
2339
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002340/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2341/*
2342 * mptscsih_change_queue_depth - This function will set a devices queue depth
2343 * @sdev: per scsi_device pointer
2344 * @qdepth: requested queue depth
2345 *
2346 * Adding support for new 'change_queue_depth' api.
2347*/
2348int
2349mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002351 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2352 VirtTarget *vtarget;
2353 struct scsi_target *starget;
2354 int max_depth;
2355 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002357 starget = scsi_target(sdev);
2358 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002359
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002360 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002361 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002363 else if (sdev->type == TYPE_DISK &&
2364 vtarget->minSyncFactor <= MPT_ULTRA160)
2365 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2366 else
2367 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 } else
2369 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2370
2371 if (qdepth > max_depth)
2372 qdepth = max_depth;
2373 if (qdepth == 1)
2374 tagged = 0;
2375 else
2376 tagged = MSG_SIMPLE_TAG;
2377
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002378 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2379 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380}
2381
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382/*
2383 * OS entry point to adjust the queue_depths on a per-device basis.
2384 * Called once per device the bus scan. Use it to force the queue_depth
2385 * member to 1 if a device does not support Q tags.
2386 * Return non-zero if fails.
2387 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002388int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002389mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002391 struct Scsi_Host *sh = sdev->host;
2392 VirtTarget *vtarget;
2393 VirtDevice *vdevice;
2394 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002396 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002398 starget = scsi_target(sdev);
2399 vtarget = starget->hostdata;
2400 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 dsprintk((MYIOC_s_INFO_FMT
2403 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002404 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2405 if (hd->ioc->bus_type == SPI)
2406 dsprintk((MYIOC_s_INFO_FMT
2407 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2408 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2409 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002413 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 goto slave_configure_exit;
2415 }
2416
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002417 vdevice->configured_lun=1;
2418 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2419 indexed_lun = (vdevice->lun % 32);
2420 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002421 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002422 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424 dsprintk((MYIOC_s_INFO_FMT
2425 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002426 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002428 if (hd->ioc->bus_type == SPI)
2429 dsprintk((MYIOC_s_INFO_FMT
2430 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2431 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2432 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434slave_configure_exit:
2435
2436 dsprintk((MYIOC_s_INFO_FMT
2437 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002438 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2439 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441 return 0;
2442}
2443
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2445/*
2446 * Private routines...
2447 */
2448
2449/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2450/* Utility function to copy sense data from the scsi_cmnd buffer
2451 * to the FC and SCSI target structures.
2452 *
2453 */
2454static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002455mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002457 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 SCSIIORequest_t *pReq;
2459 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
2461 /* Get target structure
2462 */
2463 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002464 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
2466 if (sense_count) {
2467 u8 *sense_data;
2468 int req_index;
2469
2470 /* Copy the sense received into the scsi command block. */
2471 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2472 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2473 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2474
2475 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2476 */
2477 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002478 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 int idx;
2480 MPT_ADAPTER *ioc = hd->ioc;
2481
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002482 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2484 ioc->events[idx].eventContext = ioc->eventContext;
2485
2486 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2487 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002488 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2491
2492 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002493 if (hd->ioc->pcidev->vendor ==
2494 PCI_VENDOR_ID_IBM) {
2495 mptscsih_issue_sep_command(hd->ioc,
2496 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2497 vdev->vtarget->tflags |=
2498 MPT_TARGET_FLAGS_LED_ON;
2499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501 }
2502 } else {
2503 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2504 hd->ioc->name));
2505 }
2506}
2507
Eric Moore3dc0b032006-07-11 17:32:33 -06002508static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2510{
2511 MPT_SCSI_HOST *hd;
2512 int i;
2513
2514 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2515
2516 for (i = 0; i < hd->ioc->req_depth; i++) {
2517 if (hd->ScsiLookup[i] == sc) {
2518 return i;
2519 }
2520 }
2521
2522 return -1;
2523}
2524
2525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002526int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2528{
2529 MPT_SCSI_HOST *hd;
2530 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002531 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
2533 dtmprintk((KERN_WARNING MYNAM
2534 ": IOC %s_reset routed to SCSI host driver!\n",
2535 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2536 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2537
2538 /* If a FW reload request arrives after base installed but
2539 * before all scsi hosts have been attached, then an alt_ioc
2540 * may have a NULL sh pointer.
2541 */
2542 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2543 return 0;
2544 else
2545 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2546
2547 if (reset_phase == MPT_IOC_SETUP_RESET) {
2548 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2549
2550 /* Clean Up:
2551 * 1. Set Hard Reset Pending Flag
2552 * All new commands go to doneQ
2553 */
2554 hd->resetPending = 1;
2555
2556 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2557 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2558
2559 /* 2. Flush running commands
2560 * Clean ScsiLookup (and associated memory)
2561 * AND clean mytaskQ
2562 */
2563
2564 /* 2b. Reply to OS all known outstanding I/O commands.
2565 */
2566 mptscsih_flush_running_cmds(hd);
2567
2568 /* 2c. If there was an internal command that
2569 * has not completed, configuration or io request,
2570 * free these resources.
2571 */
2572 if (hd->cmdPtr) {
2573 del_timer(&hd->timer);
2574 mpt_free_msg_frame(ioc, hd->cmdPtr);
2575 }
2576
2577 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2578
2579 } else {
2580 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2581
2582 /* Once a FW reload begins, all new OS commands are
2583 * redirected to the doneQ w/ a reset status.
2584 * Init all control structures.
2585 */
2586
2587 /* ScsiLookup initialization
2588 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002589 for (ii=0; ii < hd->ioc->req_depth; ii++)
2590 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
2592 /* 2. Chain Buffer initialization
2593 */
2594
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002595 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597
2598 /* 5. Enable new commands to be posted
2599 */
2600 spin_lock_irqsave(&ioc->FreeQlock, flags);
2601 hd->tmPending = 0;
2602 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2603 hd->resetPending = 0;
2604 hd->tmState = TM_STATE_NONE;
2605
2606 /* 6. If there was an internal command,
2607 * wake this process up.
2608 */
2609 if (hd->cmdPtr) {
2610 /*
2611 * Wake up the original calling thread
2612 */
2613 hd->pLocal = &hd->localReply;
2614 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002615 hd->scandv_wait_done = 1;
2616 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 hd->cmdPtr = NULL;
2618 }
2619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2621
2622 }
2623
2624 return 1; /* currently means nothing really */
2625}
2626
2627/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002628int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2630{
2631 MPT_SCSI_HOST *hd;
2632 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2633
Moore, Eric3a892be2006-03-14 09:14:03 -07002634 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 ioc->name, event));
2636
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002637 if (ioc->sh == NULL ||
2638 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2639 return 1;
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 switch (event) {
2642 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2643 /* FIXME! */
2644 break;
2645 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2646 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002647 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002648 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 break;
2650 case MPI_EVENT_LOGOUT: /* 09 */
2651 /* FIXME! */
2652 break;
2653
Michael Reed05e8ec12006-01-13 14:31:54 -06002654 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002655 break;
2656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 /*
2658 * CHECKME! Don't think we need to do
2659 * anything for these, but...
2660 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2662 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2663 /*
2664 * CHECKME! Falling thru...
2665 */
2666 break;
2667
2668 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 case MPI_EVENT_NONE: /* 00 */
2672 case MPI_EVENT_LOG_DATA: /* 01 */
2673 case MPI_EVENT_STATE_CHANGE: /* 02 */
2674 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2675 default:
2676 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2677 break;
2678 }
2679
2680 return 1; /* currently means nothing really */
2681}
2682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2684/*
2685 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2686 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002687 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002688 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 *
2690 * NOTE: It's only SAFE to call this routine if data points to
2691 * sane & valid STANDARD INQUIRY data!
2692 *
2693 * Allocate and initialize memory for this target.
2694 * Save inquiry data.
2695 *
2696 */
2697static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002698mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2699 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Eric Mooref99be432007-01-04 20:46:54 -07002702 hd->ioc->name, vtarget->bus_id, vtarget->target_id,
2703 sdev->lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 /* Is LUN supported? If so, upper 2 bits will be 0
2706 * in first byte of inquiry data.
2707 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002708 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 return;
2710
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002711 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
James Bottomleyc92f2222006-03-01 09:02:49 -06002714 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002716 if (hd->ioc->bus_type != SPI)
2717 return;
2718
James Bottomleyc92f2222006-03-01 09:02:49 -06002719 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002720 /* Treat all Processors as SAF-TE if
2721 * command line option is set */
2722 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2723 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002724 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002725 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002726 if (sdev->inquiry_len > 49 ) {
2727 if (sdev->inquiry[44] == 'S' &&
2728 sdev->inquiry[45] == 'A' &&
2729 sdev->inquiry[46] == 'F' &&
2730 sdev->inquiry[47] == '-' &&
2731 sdev->inquiry[48] == 'T' &&
2732 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002733 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2734 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 }
2736 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002737 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002738 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739}
2740
2741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2742/*
2743 * Update the target negotiation parameters based on the
2744 * the Inquiry data, adapter capabilities, and NVRAM settings.
2745 *
2746 */
2747static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002748mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2749 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002751 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 int id = (int) target->target_id;
2753 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 u8 width = MPT_NARROW;
2755 u8 factor = MPT_ASYNC;
2756 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002757 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 u8 noQas = 1;
2759
2760 target->negoFlags = pspi_data->noQas;
2761
James Bottomleyc92f2222006-03-01 09:02:49 -06002762 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
James Bottomleyc92f2222006-03-01 09:02:49 -06002764 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 width = 0;
2766 factor = MPT_ULTRA2;
2767 offset = pspi_data->maxSyncOffset;
2768 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2769 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002770 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 width = 1;
2772 }
2773
James Bottomleyc92f2222006-03-01 09:02:49 -06002774 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002776 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002778 else {
2779 if (!scsi_device_ius(sdev) &&
2780 !scsi_device_qas(sdev))
2781 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002783 factor = MPT_ULTRA320;
2784 if (scsi_device_qas(sdev)) {
Eric Mooref99be432007-01-04 20:46:54 -07002785 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
James Bottomleyc92f2222006-03-01 09:02:49 -06002786 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002788 if (sdev->type == TYPE_TAPE &&
2789 scsi_device_ius(sdev))
2790 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 offset = pspi_data->maxSyncOffset;
2794
2795 /* If RAID, never disable QAS
2796 * else if non RAID, do not disable
2797 * QAS if bit 1 is set
2798 * bit 1 QAS support, non-raid only
2799 * bit 0 IU support
2800 */
2801 if (target->raidVolume == 1) {
2802 noQas = 0;
2803 }
2804 } else {
2805 factor = MPT_ASYNC;
2806 offset = 0;
2807 }
2808 }
2809
James Bottomleyc92f2222006-03-01 09:02:49 -06002810 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2812 }
2813
2814 /* Update tflags based on NVRAM settings. (SCSI only)
2815 */
2816 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2817 nvram = pspi_data->nvram[id];
2818 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2819
2820 if (width)
2821 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2822
2823 if (offset > 0) {
2824 /* Ensure factor is set to the
2825 * maximum of: adapter, nvram, inquiry
2826 */
2827 if (nfactor) {
2828 if (nfactor < pspi_data->minSyncFactor )
2829 nfactor = pspi_data->minSyncFactor;
2830
2831 factor = max(factor, nfactor);
2832 if (factor == MPT_ASYNC)
2833 offset = 0;
2834 } else {
2835 offset = 0;
2836 factor = MPT_ASYNC;
2837 }
2838 } else {
2839 factor = MPT_ASYNC;
2840 }
2841 }
2842
2843 /* Make sure data is consistent
2844 */
2845 if ((!width) && (factor < MPT_ULTRA2)) {
2846 factor = MPT_ULTRA2;
2847 }
2848
2849 /* Save the data to the target structure.
2850 */
2851 target->minSyncFactor = factor;
2852 target->maxOffset = offset;
2853 target->maxWidth = width;
2854
2855 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2856
2857 /* Disable unused features.
2858 */
2859 if (!width)
2860 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2861
2862 if (!offset)
2863 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2864
2865 if ( factor > MPT_ULTRA320 )
2866 noQas = 0;
2867
James Bottomleyc92f2222006-03-01 09:02:49 -06002868 if (noQas && (pspi_data->noQas == 0)) {
2869 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2870 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
James Bottomleyc92f2222006-03-01 09:02:49 -06002872 /* Disable QAS in a mixed configuration case
2873 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
James Bottomleyc92f2222006-03-01 09:02:49 -06002875 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 }
2877}
2878
2879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
2881/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2882/*
2883 * SCSI Config Page functionality ...
2884 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
2886/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887/* mptscsih_writeIOCPage4 - write IOC Page 4
2888 * @hd: Pointer to a SCSI Host Structure
2889 * @target_id: write IOC Page4 for this ID & Bus
2890 *
2891 * Return: -EAGAIN if unable to obtain a Message Frame
2892 * or 0 if success.
2893 *
2894 * Remark: We do not wait for a return, write pages sequentially.
2895 */
2896static int
2897mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2898{
2899 MPT_ADAPTER *ioc = hd->ioc;
2900 Config_t *pReq;
2901 IOCPage4_t *IOCPage4Ptr;
2902 MPT_FRAME_HDR *mf;
2903 dma_addr_t dataDma;
2904 u16 req_idx;
2905 u32 frameOffset;
2906 u32 flagsLength;
2907 int ii;
2908
2909 /* Get a MF for this command.
2910 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002911 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002912 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 ioc->name));
2914 return -EAGAIN;
2915 }
2916
2917 /* Set the request and the data pointers.
2918 * Place data at end of MF.
2919 */
2920 pReq = (Config_t *)mf;
2921
2922 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2923 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2924
2925 /* Complete the request frame (same for all requests).
2926 */
2927 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2928 pReq->Reserved = 0;
2929 pReq->ChainOffset = 0;
2930 pReq->Function = MPI_FUNCTION_CONFIG;
2931 pReq->ExtPageLength = 0;
2932 pReq->ExtPageType = 0;
2933 pReq->MsgFlags = 0;
2934 for (ii=0; ii < 8; ii++) {
2935 pReq->Reserved2[ii] = 0;
2936 }
2937
2938 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2939 dataDma = ioc->spi_data.IocPg4_dma;
2940 ii = IOCPage4Ptr->ActiveSEP++;
2941 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2942 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2943 pReq->Header = IOCPage4Ptr->Header;
2944 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2945
2946 /* Add a SGE to the config request.
2947 */
2948 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2949 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2950
2951 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2952
2953 dinitprintk((MYIOC_s_INFO_FMT
2954 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2955 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2956
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002957 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
2959 return 0;
2960}
2961
2962/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2963/*
2964 * Bus Scan and Domain Validation functionality ...
2965 */
2966
2967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2968/*
2969 * mptscsih_scandv_complete - Scan and DV callback routine registered
2970 * to Fustion MPT (base) driver.
2971 *
2972 * @ioc: Pointer to MPT_ADAPTER structure
2973 * @mf: Pointer to original MPT request frame
2974 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2975 *
2976 * This routine is called from mpt.c::mpt_interrupt() at the completion
2977 * of any SCSI IO request.
2978 * This routine is registered with the Fusion MPT (base) driver at driver
2979 * load/init time via the mpt_register() API call.
2980 *
2981 * Returns 1 indicating alloc'd request frame ptr should be freed.
2982 *
2983 * Remark: Sets a completion code and (possibly) saves sense data
2984 * in the IOC member localReply structure.
2985 * Used ONLY for DV and other internal commands.
2986 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002987int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2989{
2990 MPT_SCSI_HOST *hd;
2991 SCSIIORequest_t *pReq;
2992 int completionCode;
2993 u16 req_idx;
2994
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002995 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2996
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 if ((mf == NULL) ||
2998 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2999 printk(MYIOC_s_ERR_FMT
3000 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3001 ioc->name, mf?"BAD":"NULL", (void *) mf);
3002 goto wakeup;
3003 }
3004
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 del_timer(&hd->timer);
3006 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3007 hd->ScsiLookup[req_idx] = NULL;
3008 pReq = (SCSIIORequest_t *) mf;
3009
3010 if (mf != hd->cmdPtr) {
3011 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3012 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3013 }
3014 hd->cmdPtr = NULL;
3015
3016 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3017 hd->ioc->name, mf, mr, req_idx));
3018
3019 hd->pLocal = &hd->localReply;
3020 hd->pLocal->scsiStatus = 0;
3021
3022 /* If target struct exists, clear sense valid flag.
3023 */
3024 if (mr == NULL) {
3025 completionCode = MPT_SCANDV_GOOD;
3026 } else {
3027 SCSIIOReply_t *pReply;
3028 u16 status;
3029 u8 scsi_status;
3030
3031 pReply = (SCSIIOReply_t *) mr;
3032
3033 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3034 scsi_status = pReply->SCSIStatus;
3035
3036 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3037 status, pReply->SCSIState, scsi_status,
3038 le32_to_cpu(pReply->IOCLogInfo)));
3039
3040 switch(status) {
3041
3042 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3043 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3044 break;
3045
3046 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3047 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3048 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3049 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3050 completionCode = MPT_SCANDV_DID_RESET;
3051 break;
3052
3053 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3054 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3055 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3056 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3057 ConfigReply_t *pr = (ConfigReply_t *)mr;
3058 completionCode = MPT_SCANDV_GOOD;
3059 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3060 hd->pLocal->header.PageLength = pr->Header.PageLength;
3061 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3062 hd->pLocal->header.PageType = pr->Header.PageType;
3063
3064 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3065 /* If the RAID Volume request is successful,
3066 * return GOOD, else indicate that
3067 * some type of error occurred.
3068 */
3069 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003070 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 completionCode = MPT_SCANDV_GOOD;
3072 else
3073 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06003074 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075
3076 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3077 u8 *sense_data;
3078 int sz;
3079
3080 /* save sense data in global structure
3081 */
3082 completionCode = MPT_SCANDV_SENSE;
3083 hd->pLocal->scsiStatus = scsi_status;
3084 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3085 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3086
3087 sz = min_t(int, pReq->SenseBufferLength,
3088 SCSI_STD_SENSE_BYTES);
3089 memcpy(hd->pLocal->sense, sense_data, sz);
3090
3091 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3092 sense_data));
3093 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3094 if (pReq->CDB[0] == INQUIRY)
3095 completionCode = MPT_SCANDV_ISSUE_SENSE;
3096 else
3097 completionCode = MPT_SCANDV_DID_RESET;
3098 }
3099 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3100 completionCode = MPT_SCANDV_DID_RESET;
3101 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3102 completionCode = MPT_SCANDV_DID_RESET;
3103 else {
3104 completionCode = MPT_SCANDV_GOOD;
3105 hd->pLocal->scsiStatus = scsi_status;
3106 }
3107 break;
3108
3109 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3110 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3111 completionCode = MPT_SCANDV_DID_RESET;
3112 else
3113 completionCode = MPT_SCANDV_SOME_ERROR;
3114 break;
3115
3116 default:
3117 completionCode = MPT_SCANDV_SOME_ERROR;
3118 break;
3119
3120 } /* switch(status) */
3121
3122 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3123 completionCode));
3124 } /* end of address reply case */
3125
3126 hd->pLocal->completion = completionCode;
3127
3128 /* MF and RF are freed in mpt_interrupt
3129 */
3130wakeup:
3131 /* Free Chain buffers (will never chain) in scan or dv */
3132 //mptscsih_freeChainBuffers(ioc, req_idx);
3133
3134 /*
3135 * Wake up the original calling thread
3136 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003137 hd->scandv_wait_done = 1;
3138 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139
3140 return 1;
3141}
3142
3143/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3144/* mptscsih_timer_expired - Call back for timer process.
3145 * Used only for dv functionality.
3146 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3147 *
3148 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003149void
3150mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151{
3152 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3153
3154 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3155
3156 if (hd->cmdPtr) {
3157 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3158
3159 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3160 /* Desire to issue a task management request here.
3161 * TM requests MUST be single threaded.
3162 * If old eh code and no TM current, issue request.
3163 * If new eh code, do nothing. Wait for OS cmd timeout
3164 * for bus reset.
3165 */
3166 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3167 } else {
3168 /* Perform a FW reload */
3169 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3170 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3171 }
3172 }
3173 } else {
3174 /* This should NEVER happen */
3175 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3176 }
3177
3178 /* No more processing.
3179 * TM call will generate an interrupt for SCSI TM Management.
3180 * The FW will reply to all outstanding commands, callback will finish cleanup.
3181 * Hard reset clean-up will free all resources.
3182 */
3183 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3184
3185 return;
3186}
3187
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
3189/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3190/**
3191 * mptscsih_do_cmd - Do internal command.
3192 * @hd: MPT_SCSI_HOST pointer
3193 * @io: INTERNAL_CMD pointer.
3194 *
3195 * Issue the specified internally generated command and do command
3196 * specific cleanup. For bus scan / DV only.
3197 * NOTES: If command is Inquiry and status is good,
3198 * initialize a target structure, save the data
3199 *
3200 * Remark: Single threaded access only.
3201 *
3202 * Return:
3203 * < 0 if an illegal command or no resources
3204 *
3205 * 0 if good
3206 *
3207 * > 0 if command complete but some type of completion error.
3208 */
3209static int
3210mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3211{
3212 MPT_FRAME_HDR *mf;
3213 SCSIIORequest_t *pScsiReq;
3214 SCSIIORequest_t ReqCopy;
3215 int my_idx, ii, dir;
3216 int rc, cmdTimeout;
3217 int in_isr;
3218 char cmdLen;
3219 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3220 char cmd = io->cmd;
3221
3222 in_isr = in_interrupt();
3223 if (in_isr) {
3224 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3225 hd->ioc->name));
3226 return -EPERM;
3227 }
3228
3229
3230 /* Set command specific information
3231 */
3232 switch (cmd) {
3233 case INQUIRY:
3234 cmdLen = 6;
3235 dir = MPI_SCSIIO_CONTROL_READ;
3236 CDB[0] = cmd;
3237 CDB[4] = io->size;
3238 cmdTimeout = 10;
3239 break;
3240
3241 case TEST_UNIT_READY:
3242 cmdLen = 6;
3243 dir = MPI_SCSIIO_CONTROL_READ;
3244 cmdTimeout = 10;
3245 break;
3246
3247 case START_STOP:
3248 cmdLen = 6;
3249 dir = MPI_SCSIIO_CONTROL_READ;
3250 CDB[0] = cmd;
3251 CDB[4] = 1; /*Spin up the disk */
3252 cmdTimeout = 15;
3253 break;
3254
3255 case REQUEST_SENSE:
3256 cmdLen = 6;
3257 CDB[0] = cmd;
3258 CDB[4] = io->size;
3259 dir = MPI_SCSIIO_CONTROL_READ;
3260 cmdTimeout = 10;
3261 break;
3262
3263 case READ_BUFFER:
3264 cmdLen = 10;
3265 dir = MPI_SCSIIO_CONTROL_READ;
3266 CDB[0] = cmd;
3267 if (io->flags & MPT_ICFLAG_ECHO) {
3268 CDB[1] = 0x0A;
3269 } else {
3270 CDB[1] = 0x02;
3271 }
3272
3273 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3274 CDB[1] |= 0x01;
3275 }
3276 CDB[6] = (io->size >> 16) & 0xFF;
3277 CDB[7] = (io->size >> 8) & 0xFF;
3278 CDB[8] = io->size & 0xFF;
3279 cmdTimeout = 10;
3280 break;
3281
3282 case WRITE_BUFFER:
3283 cmdLen = 10;
3284 dir = MPI_SCSIIO_CONTROL_WRITE;
3285 CDB[0] = cmd;
3286 if (io->flags & MPT_ICFLAG_ECHO) {
3287 CDB[1] = 0x0A;
3288 } else {
3289 CDB[1] = 0x02;
3290 }
3291 CDB[6] = (io->size >> 16) & 0xFF;
3292 CDB[7] = (io->size >> 8) & 0xFF;
3293 CDB[8] = io->size & 0xFF;
3294 cmdTimeout = 10;
3295 break;
3296
3297 case RESERVE:
3298 cmdLen = 6;
3299 dir = MPI_SCSIIO_CONTROL_READ;
3300 CDB[0] = cmd;
3301 cmdTimeout = 10;
3302 break;
3303
3304 case RELEASE:
3305 cmdLen = 6;
3306 dir = MPI_SCSIIO_CONTROL_READ;
3307 CDB[0] = cmd;
3308 cmdTimeout = 10;
3309 break;
3310
3311 case SYNCHRONIZE_CACHE:
3312 cmdLen = 10;
3313 dir = MPI_SCSIIO_CONTROL_READ;
3314 CDB[0] = cmd;
3315// CDB[1] = 0x02; /* set immediate bit */
3316 cmdTimeout = 10;
3317 break;
3318
3319 default:
3320 /* Error Case */
3321 return -EFAULT;
3322 }
3323
3324 /* Get and Populate a free Frame
3325 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003326 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3328 hd->ioc->name));
3329 return -EBUSY;
3330 }
3331
3332 pScsiReq = (SCSIIORequest_t *) mf;
3333
3334 /* Get the request index */
3335 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3336 ADD_INDEX_LOG(my_idx); /* for debug */
3337
3338 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3339 pScsiReq->TargetID = io->physDiskNum;
3340 pScsiReq->Bus = 0;
3341 pScsiReq->ChainOffset = 0;
3342 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3343 } else {
3344 pScsiReq->TargetID = io->id;
3345 pScsiReq->Bus = io->bus;
3346 pScsiReq->ChainOffset = 0;
3347 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3348 }
3349
3350 pScsiReq->CDBLength = cmdLen;
3351 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3352
3353 pScsiReq->Reserved = 0;
3354
3355 pScsiReq->MsgFlags = mpt_msg_flags();
3356 /* MsgContext set in mpt_get_msg_fram call */
3357
3358 for (ii=0; ii < 8; ii++)
3359 pScsiReq->LUN[ii] = 0;
3360 pScsiReq->LUN[1] = io->lun;
3361
3362 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3363 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3364 else
3365 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3366
3367 if (cmd == REQUEST_SENSE) {
3368 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3369 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3370 hd->ioc->name, cmd));
3371 }
3372
3373 for (ii=0; ii < 16; ii++)
3374 pScsiReq->CDB[ii] = CDB[ii];
3375
3376 pScsiReq->DataLength = cpu_to_le32(io->size);
3377 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3378 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3379
3380 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3381 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3382
3383 if (dir == MPI_SCSIIO_CONTROL_READ) {
3384 mpt_add_sge((char *) &pScsiReq->SGL,
3385 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3386 io->data_dma);
3387 } else {
3388 mpt_add_sge((char *) &pScsiReq->SGL,
3389 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3390 io->data_dma);
3391 }
3392
3393 /* The ISR will free the request frame, but we need
3394 * the information to initialize the target. Duplicate.
3395 */
3396 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3397
3398 /* Issue this command after:
3399 * finish init
3400 * add timer
3401 * Wait until the reply has been received
3402 * ScsiScanDvCtx callback function will
3403 * set hd->pLocal;
3404 * set scandv_wait_done and call wake_up
3405 */
3406 hd->pLocal = NULL;
3407 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003408 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
3410 /* Save cmd pointer, for resource free if timeout or
3411 * FW reload occurs
3412 */
3413 hd->cmdPtr = mf;
3414
3415 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003416 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3417 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418
3419 if (hd->pLocal) {
3420 rc = hd->pLocal->completion;
3421 hd->pLocal->skip = 0;
3422
3423 /* Always set fatal error codes in some cases.
3424 */
3425 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3426 rc = -ENXIO;
3427 else if (rc == MPT_SCANDV_SOME_ERROR)
3428 rc = -rc;
3429 } else {
3430 rc = -EFAULT;
3431 /* This should never happen. */
3432 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3433 hd->ioc->name));
3434 }
3435
3436 return rc;
3437}
3438
3439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3440/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003441 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3442 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003443 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003444 *
3445 * Uses the ISR, but with special processing.
3446 * MUST be single-threaded.
3447 *
3448 */
3449static void
3450mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3451{
3452 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
3454 /* Following parameters will not change
3455 * in this routine.
3456 */
3457 iocmd.cmd = SYNCHRONIZE_CACHE;
3458 iocmd.flags = 0;
3459 iocmd.physDiskNum = -1;
3460 iocmd.data = NULL;
3461 iocmd.data_dma = -1;
3462 iocmd.size = 0;
3463 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003464 iocmd.bus = vdevice->vtarget->bus_id;
3465 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003466 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
James Bottomleyc92f2222006-03-01 09:02:49 -06003468 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003469 (vdevice->configured_lun))
3470 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471}
3472
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003473EXPORT_SYMBOL(mptscsih_remove);
3474EXPORT_SYMBOL(mptscsih_shutdown);
3475#ifdef CONFIG_PM
3476EXPORT_SYMBOL(mptscsih_suspend);
3477EXPORT_SYMBOL(mptscsih_resume);
3478#endif
3479EXPORT_SYMBOL(mptscsih_proc_info);
3480EXPORT_SYMBOL(mptscsih_info);
3481EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003482EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003483EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003484EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003485EXPORT_SYMBOL(mptscsih_slave_destroy);
3486EXPORT_SYMBOL(mptscsih_slave_configure);
3487EXPORT_SYMBOL(mptscsih_abort);
3488EXPORT_SYMBOL(mptscsih_dev_reset);
3489EXPORT_SYMBOL(mptscsih_bus_reset);
3490EXPORT_SYMBOL(mptscsih_host_reset);
3491EXPORT_SYMBOL(mptscsih_bios_param);
3492EXPORT_SYMBOL(mptscsih_io_done);
3493EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3494EXPORT_SYMBOL(mptscsih_scandv_complete);
3495EXPORT_SYMBOL(mptscsih_event_process);
3496EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003497EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003498EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003499EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003501/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/