blob: 2c72c36b8171cd67f26114c9c2f97b4d70b0b2d6 [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 }
704 }
705
706 /*
707 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
708 */
709
710 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
712 /* Linux handles an unsolicited DID_RESET better
713 * than an unsolicited DID_ABORT.
714 */
715 sc->result = DID_RESET << 16;
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 break;
718
719 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600720 sc->resid = sc->request_bufflen - xfer_cnt;
721 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
722 sc->result=DID_SOFT_ERROR << 16;
723 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600725 dreplyprintk((KERN_NOTICE
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600726 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
730 /*
731 * Do upfront check for valid SenseData and give it
732 * precedence!
733 */
734 sc->result = (DID_OK << 16) | scsi_status;
735 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
736 /* Have already saved the status and sense data
737 */
738 ;
739 } else {
740 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600741 if (scsi_status == SAM_STAT_BUSY)
742 sc->result = SAM_STAT_BUSY;
743 else
744 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 }
746 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
747 /* What to do?
748 */
749 sc->result = DID_SOFT_ERROR << 16;
750 }
751 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
752 /* Not real sure here either... */
753 sc->result = DID_RESET << 16;
754 }
755 }
756
757 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
758 sc->underflow));
759 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
760 /* Report Queue Full
761 */
762 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
763 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 break;
766
Moore, Eric7e551472006-01-16 18:53:21 -0700767 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
768 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
770 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600771 if (scsi_status == MPI_SCSI_STATUS_BUSY)
772 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
773 else
774 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (scsi_state == 0) {
776 ;
777 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
778 /*
779 * If running against circa 200003dd 909 MPT f/w,
780 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
781 * (QUEUE_FULL) returned from device! --> get 0x0000?128
782 * and with SenseBytes set to 0.
783 */
784 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
785 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
786
787 }
788 else if (scsi_state &
789 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
790 ) {
791 /*
792 * What to do?
793 */
794 sc->result = DID_SOFT_ERROR << 16;
795 }
796 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
797 /* Not real sure here either... */
798 sc->result = DID_RESET << 16;
799 }
800 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
801 /* Device Inq. data indicates that it supports
802 * QTags, but rejects QTag messages.
803 * This command completed OK.
804 *
805 * Not real sure here either so do nothing... */
806 }
807
808 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
809 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
810
811 /* Add handling of:
812 * Reservation Conflict, Busy,
813 * Command Terminated, CHECK
814 */
815 break;
816
817 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
818 sc->result = DID_SOFT_ERROR << 16;
819 break;
820
821 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
822 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
823 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
824 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
825 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
826 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
827 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
829 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
830 default:
831 /*
832 * What to do?
833 */
834 sc->result = DID_SOFT_ERROR << 16;
835 break;
836
837 } /* switch(status) */
838
839 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
840 } /* end of address reply case */
841
842 /* Unmap the DMA buffers, if any. */
843 if (sc->use_sg) {
844 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
845 sc->use_sg, sc->sc_data_direction);
846 } else if (sc->request_bufflen) {
847 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
848 sc->request_bufflen, sc->sc_data_direction);
849 }
850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 sc->scsi_done(sc); /* Issue the command callback */
852
853 /* Free Chain buffers */
854 mptscsih_freeChainBuffers(ioc, req_idx);
855 return 1;
856}
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858/*
859 * mptscsih_flush_running_cmds - For each command found, search
860 * Scsi_Host instance taskQ and reply to OS.
861 * Called only if recovering from a FW reload.
862 * @hd: Pointer to a SCSI HOST structure
863 *
864 * Returns: None.
865 *
866 * Must be called while new I/Os are being queued.
867 */
868static void
869mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
870{
871 MPT_ADAPTER *ioc = hd->ioc;
872 struct scsi_cmnd *SCpnt;
873 MPT_FRAME_HDR *mf;
874 int ii;
875 int max = ioc->req_depth;
876
877 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
878 for (ii= 0; ii < max; ii++) {
879 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
880
881 /* Command found.
882 */
883
884 /* Null ScsiLookup index
885 */
886 hd->ScsiLookup[ii] = NULL;
887
888 mf = MPT_INDEX_2_MFPTR(ioc, ii);
889 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
890 mf, SCpnt));
891
Eric Moore3dc0b032006-07-11 17:32:33 -0600892 /* Free Chain buffers */
893 mptscsih_freeChainBuffers(ioc, ii);
894
895 /* Free Message frames */
896 mpt_free_msg_frame(ioc, mf);
897
898 if ((unsigned char *)mf != SCpnt->host_scribble)
899 continue;
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 /* Set status, free OS resources (SG DMA buffers)
902 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400904 if (SCpnt->use_sg) {
905 pci_unmap_sg(ioc->pcidev,
906 (struct scatterlist *) SCpnt->request_buffer,
907 SCpnt->use_sg,
908 SCpnt->sc_data_direction);
909 } else if (SCpnt->request_bufflen) {
910 pci_unmap_single(ioc->pcidev,
911 SCpnt->SCp.dma_handle,
912 SCpnt->request_bufflen,
913 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 }
915 SCpnt->result = DID_RESET << 16;
916 SCpnt->host_scribble = NULL;
917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
919 }
920 }
921
922 return;
923}
924
925/*
926 * mptscsih_search_running_cmds - Delete any commands associated
927 * with the specified target and lun. Function called only
928 * when a lun is disable by mid-layer.
929 * Do NOT access the referenced scsi_cmnd structure or
930 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600931 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700932 * @hd: Pointer to a SCSI HOST structure
933 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 *
935 * Returns: None.
936 *
937 * Called from slave_destroy.
938 */
939static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700940mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
942 SCSIIORequest_t *mf = NULL;
943 int ii;
944 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600945 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Ericbd23e942006-04-17 12:43:04 -0600948 vdevice->vtarget->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600951 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600954 if (mf == NULL)
955 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
957 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
Moore, Eric914c2d82006-03-14 09:19:36 -0700958 if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 continue;
960
961 /* Cleanup
962 */
963 hd->ScsiLookup[ii] = NULL;
964 mptscsih_freeChainBuffers(hd->ioc, ii);
965 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -0600966 if ((unsigned char *)mf != sc->host_scribble)
967 continue;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600968 if (sc->use_sg) {
969 pci_unmap_sg(hd->ioc->pcidev,
970 (struct scatterlist *) sc->request_buffer,
971 sc->use_sg,
972 sc->sc_data_direction);
973 } else if (sc->request_bufflen) {
974 pci_unmap_single(hd->ioc->pcidev,
975 sc->SCp.dma_handle,
976 sc->request_bufflen,
977 sc->sc_data_direction);
978 }
979 sc->host_scribble = NULL;
980 sc->result = DID_NO_CONNECT << 16;
981 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return;
985}
986
987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
990/*
991 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
992 * from a SCSI target device.
993 * @sc: Pointer to scsi_cmnd structure
994 * @pScsiReply: Pointer to SCSIIOReply_t
995 * @pScsiReq: Pointer to original SCSI request
996 *
997 * This routine periodically reports QUEUE_FULL status returned from a
998 * SCSI target device. It reports this to the console via kernel
999 * printk() API call, not more than once every 10 seconds.
1000 */
1001static void
1002mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1003{
1004 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001007 if (sc->device == NULL)
1008 return;
1009 if (sc->device->host == NULL)
1010 return;
1011 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1012 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001014 if (time - hd->last_queue_full > 10 * HZ) {
1015 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1016 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1017 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019}
1020
1021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1022/*
1023 * mptscsih_remove - Removed scsi devices
1024 * @pdev: Pointer to pci_dev structure
1025 *
1026 *
1027 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001028void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029mptscsih_remove(struct pci_dev *pdev)
1030{
1031 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1032 struct Scsi_Host *host = ioc->sh;
1033 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001036 if(!host) {
1037 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 scsi_remove_host(host);
1042
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001043 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1044 return;
1045
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001046 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001048 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001050 if (hd->ScsiLookup != NULL) {
1051 sz1 = hd->ioc->req_depth * sizeof(void *);
1052 kfree(hd->ScsiLookup);
1053 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
1055
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001056 /*
1057 * Free pointer array.
1058 */
1059 kfree(hd->Targets);
1060 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001062 dprintk((MYIOC_s_INFO_FMT
1063 "Free'd ScsiLookup (%d) memory\n",
1064 hd->ioc->name, sz1));
1065
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001066 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001067
1068 /* NULL the Scsi_Host pointer
1069 */
1070 hd->ioc->sh = NULL;
1071
1072 scsi_host_put(host);
1073
1074 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001075
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076}
1077
1078/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1079/*
1080 * mptscsih_shutdown - reboot notifier
1081 *
1082 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001083void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001084mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001086 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 struct Scsi_Host *host = ioc->sh;
1088 MPT_SCSI_HOST *hd;
1089
1090 if(!host)
1091 return;
1092
1093 hd = (MPT_SCSI_HOST *)host->hostdata;
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
1097#ifdef CONFIG_PM
1098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1099/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001100 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 *
1102 *
1103 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001104int
Pavel Machek8d189f72005-04-16 15:25:28 -07001105mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001107 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001108 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109}
1110
1111/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1112/*
1113 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1114 *
1115 *
1116 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001117int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118mptscsih_resume(struct pci_dev *pdev)
1119{
1120 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1121 struct Scsi_Host *host = ioc->sh;
1122 MPT_SCSI_HOST *hd;
1123
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001124 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001125
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 if(!host)
1127 return 0;
1128
1129 hd = (MPT_SCSI_HOST *)host->hostdata;
1130 if(!hd)
1131 return 0;
1132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return 0;
1134}
1135
1136#endif
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1139/**
1140 * mptscsih_info - Return information about MPT adapter
1141 * @SChost: Pointer to Scsi_Host structure
1142 *
1143 * (linux scsi_host_template.info routine)
1144 *
1145 * Returns pointer to buffer where information was written.
1146 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001147const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148mptscsih_info(struct Scsi_Host *SChost)
1149{
1150 MPT_SCSI_HOST *h;
1151 int size = 0;
1152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156 if (h->info_kbuf == NULL)
1157 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1158 return h->info_kbuf;
1159 h->info_kbuf[0] = '\0';
1160
1161 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1162 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
1164
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001165 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
1168struct info_str {
1169 char *buffer;
1170 int length;
1171 int offset;
1172 int pos;
1173};
1174
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001175static void
1176mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
1178 if (info->pos + len > info->length)
1179 len = info->length - info->pos;
1180
1181 if (info->pos + len < info->offset) {
1182 info->pos += len;
1183 return;
1184 }
1185
1186 if (info->pos < info->offset) {
1187 data += (info->offset - info->pos);
1188 len -= (info->offset - info->pos);
1189 }
1190
1191 if (len > 0) {
1192 memcpy(info->buffer + info->pos, data, len);
1193 info->pos += len;
1194 }
1195}
1196
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001197static int
1198mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 va_list args;
1201 char buf[81];
1202 int len;
1203
1204 va_start(args, fmt);
1205 len = vsprintf(buf, fmt, args);
1206 va_end(args);
1207
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001208 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 return len;
1210}
1211
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001212static int
1213mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 struct info_str info;
1216
1217 info.buffer = pbuf;
1218 info.length = len;
1219 info.offset = offset;
1220 info.pos = 0;
1221
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001222 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1223 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1224 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1225 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1228}
1229
1230/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1231/**
1232 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001233 * @host: scsi host struct
1234 * @buffer: if write, user data; if read, buffer for user
1235 * @start: returns the buffer address
1236 * @offset: if write, 0; if read, the current offset into the buffer from
1237 * the previous read.
1238 * @length: if write, return length;
1239 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 *
1241 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001243int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1245 int length, int func)
1246{
1247 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1248 MPT_ADAPTER *ioc = hd->ioc;
1249 int size = 0;
1250
1251 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001252 /*
1253 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 */
1255 } else {
1256 if (start)
1257 *start = buffer;
1258
1259 size = mptscsih_host_info(ioc, buffer, offset, length);
1260 }
1261
1262 return size;
1263}
1264
1265/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1266#define ADD_INDEX_LOG(req_ent) do { } while(0)
1267
1268/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1269/**
1270 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1271 * @SCpnt: Pointer to scsi_cmnd structure
1272 * @done: Pointer SCSI mid-layer IO completion function
1273 *
1274 * (linux scsi_host_template.queuecommand routine)
1275 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1276 * from a linux scsi_cmnd request and send it to the IOC.
1277 *
1278 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1279 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001280int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1282{
1283 MPT_SCSI_HOST *hd;
1284 MPT_FRAME_HDR *mf;
1285 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001286 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 int lun;
1288 u32 datalen;
1289 u32 scsictl;
1290 u32 scsidir;
1291 u32 cmd_len;
1292 int my_idx;
1293 int ii;
1294
1295 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 lun = SCpnt->device->lun;
1297 SCpnt->scsi_done = done;
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1300 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1301
1302 if (hd->resetPending) {
1303 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1304 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1305 return SCSI_MLQUEUE_HOST_BUSY;
1306 }
1307
Moore, Ericf44e5462006-03-14 09:14:21 -07001308 if ((hd->ioc->bus_type == SPI) &&
1309 vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001310 mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
1311 SCpnt->result = DID_NO_CONNECT << 16;
1312 done(SCpnt);
1313 return 0;
1314 }
1315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 /*
1317 * Put together a MPT SCSI request...
1318 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001319 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1321 hd->ioc->name));
1322 return SCSI_MLQUEUE_HOST_BUSY;
1323 }
1324
1325 pScsiReq = (SCSIIORequest_t *) mf;
1326
1327 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1328
1329 ADD_INDEX_LOG(my_idx);
1330
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001331 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 * Seems we may receive a buffer (datalen>0) even when there
1333 * will be no data transfer! GRRRRR...
1334 */
1335 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1336 datalen = SCpnt->request_bufflen;
1337 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1338 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1339 datalen = SCpnt->request_bufflen;
1340 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1341 } else {
1342 datalen = 0;
1343 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1344 }
1345
1346 /* Default to untagged. Once a target structure has been allocated,
1347 * use the Inquiry data to determine if device supports tagged.
1348 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001349 if (vdev
1350 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 && (SCpnt->device->tagged_supported)) {
1352 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1353 } else {
1354 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1355 }
1356
1357 /* Use the above information to set up the message frame
1358 */
Moore, Eric914c2d82006-03-14 09:19:36 -07001359 pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
1360 pScsiReq->Bus = vdev->vtarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001362 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1363 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1364 else
1365 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 pScsiReq->CDBLength = SCpnt->cmd_len;
1367 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1368 pScsiReq->Reserved = 0;
1369 pScsiReq->MsgFlags = mpt_msg_flags();
1370 pScsiReq->LUN[0] = 0;
1371 pScsiReq->LUN[1] = lun;
1372 pScsiReq->LUN[2] = 0;
1373 pScsiReq->LUN[3] = 0;
1374 pScsiReq->LUN[4] = 0;
1375 pScsiReq->LUN[5] = 0;
1376 pScsiReq->LUN[6] = 0;
1377 pScsiReq->LUN[7] = 0;
1378 pScsiReq->Control = cpu_to_le32(scsictl);
1379
1380 /*
1381 * Write SCSI CDB into the message
1382 */
1383 cmd_len = SCpnt->cmd_len;
1384 for (ii=0; ii < cmd_len; ii++)
1385 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1386
1387 for (ii=cmd_len; ii < 16; ii++)
1388 pScsiReq->CDB[ii] = 0;
1389
1390 /* DataLength */
1391 pScsiReq->DataLength = cpu_to_le32(datalen);
1392
1393 /* SenseBuffer low address */
1394 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1395 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1396
1397 /* Now add the SG list
1398 * Always have a SGE even if null length.
1399 */
1400 if (datalen == 0) {
1401 /* Add a NULL SGE */
1402 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1403 (dma_addr_t) -1);
1404 } else {
1405 /* Add a 32 or 64 bit SGE */
1406 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1407 goto fail;
1408 }
1409
Eric Moore3dc0b032006-07-11 17:32:33 -06001410 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001413 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1415 hd->ioc->name, SCpnt, mf, my_idx));
1416 DBG_DUMP_REQUEST_FRAME(mf)
1417 return 0;
1418
1419 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001420 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1422 mpt_free_msg_frame(hd->ioc, mf);
1423 return SCSI_MLQUEUE_HOST_BUSY;
1424}
1425
1426/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1427/*
1428 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1429 * with a SCSI IO request
1430 * @hd: Pointer to the MPT_SCSI_HOST instance
1431 * @req_idx: Index of the SCSI IO request frame.
1432 *
1433 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1434 * No return.
1435 */
1436static void
1437mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1438{
1439 MPT_FRAME_HDR *chain;
1440 unsigned long flags;
1441 int chain_idx;
1442 int next;
1443
1444 /* Get the first chain index and reset
1445 * tracker state.
1446 */
1447 chain_idx = ioc->ReqToChain[req_idx];
1448 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1449
1450 while (chain_idx != MPT_HOST_NO_CHAIN) {
1451
1452 /* Save the next chain buffer index */
1453 next = ioc->ChainToChain[chain_idx];
1454
1455 /* Free this chain buffer and reset
1456 * tracker
1457 */
1458 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1459
1460 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1461 + (chain_idx * ioc->req_sz));
1462
1463 spin_lock_irqsave(&ioc->FreeQlock, flags);
1464 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1465 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1466
1467 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1468 ioc->name, chain_idx));
1469
1470 /* handle next */
1471 chain_idx = next;
1472 }
1473 return;
1474}
1475
1476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1477/*
1478 * Reset Handling
1479 */
1480
1481/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1482/*
1483 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1484 * Fall through to mpt_HardResetHandler if: not operational, too many
1485 * failed TM requests or handshake failure.
1486 *
1487 * @ioc: Pointer to MPT_ADAPTER structure
1488 * @type: Task Management type
1489 * @target: Logical Target ID for reset (if appropriate)
1490 * @lun: Logical Unit for reset (if appropriate)
1491 * @ctx2abort: Context for the task to be aborted (if appropriate)
1492 *
1493 * Remark: Currently invoked from a non-interrupt thread (_bh).
1494 *
1495 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1496 * will be active.
1497 *
1498 * Returns 0 for SUCCESS or -1 if FAILED.
1499 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001500int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1502{
1503 MPT_ADAPTER *ioc;
1504 int rc = -1;
1505 int doTask = 1;
1506 u32 ioc_raw_state;
1507 unsigned long flags;
1508
1509 /* If FW is being reloaded currently, return success to
1510 * the calling function.
1511 */
1512 if (hd == NULL)
1513 return 0;
1514
1515 ioc = hd->ioc;
1516 if (ioc == NULL) {
1517 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1518 return FAILED;
1519 }
1520 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1521
1522 // SJR - CHECKME - Can we avoid this here?
1523 // (mpt_HardResetHandler has this check...)
1524 spin_lock_irqsave(&ioc->diagLock, flags);
1525 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1526 spin_unlock_irqrestore(&ioc->diagLock, flags);
1527 return FAILED;
1528 }
1529 spin_unlock_irqrestore(&ioc->diagLock, flags);
1530
1531 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1532 * If we time out and not bus reset, then we return a FAILED status to the caller.
1533 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1534 * successful. Otherwise, reload the FW.
1535 */
1536 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1537 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001538 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 "Timed out waiting for last TM (%d) to complete! \n",
1540 hd->ioc->name, hd->tmPending));
1541 return FAILED;
1542 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001543 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 "Timed out waiting for last TM (%d) to complete! \n",
1545 hd->ioc->name, hd->tmPending));
1546 return FAILED;
1547 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001548 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 "Timed out waiting for last TM (%d) to complete! \n",
1550 hd->ioc->name, hd->tmPending));
1551 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1552 return FAILED;
1553
1554 doTask = 0;
1555 }
1556 } else {
1557 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1558 hd->tmPending |= (1 << type);
1559 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1560 }
1561
1562 /* Is operational?
1563 */
1564 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1565
1566#ifdef MPT_DEBUG_RESET
1567 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1568 printk(MYIOC_s_WARN_FMT
1569 "TM Handler: IOC Not operational(0x%x)!\n",
1570 hd->ioc->name, ioc_raw_state);
1571 }
1572#endif
1573
1574 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1575 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1576
1577 /* Isse the Task Mgmt request.
1578 */
1579 if (hd->hard_resets < -1)
1580 hd->hard_resets++;
1581 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1582 if (rc) {
1583 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1584 } else {
1585 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1586 }
1587 }
1588
1589 /* Only fall through to the HRH if this is a bus reset
1590 */
1591 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1592 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1593 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1594 hd->ioc->name));
1595 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1596 }
1597
Eric Moore3dc0b032006-07-11 17:32:33 -06001598 /*
1599 * Check IOCStatus from TM reply message
1600 */
1601 if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
1602 rc = FAILED;
1603
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1605
1606 return rc;
1607}
1608
1609
1610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1611/*
1612 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1613 * @hd: Pointer to MPT_SCSI_HOST structure
1614 * @type: Task Management type
1615 * @target: Logical Target ID for reset (if appropriate)
1616 * @lun: Logical Unit for reset (if appropriate)
1617 * @ctx2abort: Context for the task to be aborted (if appropriate)
1618 *
1619 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1620 * or a non-interrupt thread. In the former, must not call schedule().
1621 *
1622 * Not all fields are meaningfull for all task types.
1623 *
1624 * Returns 0 for SUCCESS, -999 for "no msg frames",
1625 * else other non-zero value returned.
1626 */
1627static int
1628mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1629{
1630 MPT_FRAME_HDR *mf;
1631 SCSITaskMgmt_t *pScsiTm;
1632 int ii;
1633 int retval;
1634
1635 /* Return Fail to calling function if no message frames available.
1636 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001637 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1639 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001640 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 }
1642 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1643 hd->ioc->name, mf));
1644
1645 /* Format the Request
1646 */
1647 pScsiTm = (SCSITaskMgmt_t *) mf;
1648 pScsiTm->TargetID = target;
1649 pScsiTm->Bus = channel;
1650 pScsiTm->ChainOffset = 0;
1651 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1652
1653 pScsiTm->Reserved = 0;
1654 pScsiTm->TaskType = type;
1655 pScsiTm->Reserved1 = 0;
1656 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1657 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1658
1659 for (ii= 0; ii < 8; ii++) {
1660 pScsiTm->LUN[ii] = 0;
1661 }
1662 pScsiTm->LUN[1] = lun;
1663
1664 for (ii=0; ii < 7; ii++)
1665 pScsiTm->Reserved2[ii] = 0;
1666
1667 pScsiTm->TaskMsgContext = ctx2abort;
1668
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001669 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1670 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1673
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001674 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1676 CAN_SLEEP)) != 0) {
1677 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1678 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1679 hd->ioc, mf));
1680 mpt_free_msg_frame(hd->ioc, mf);
1681 return retval;
1682 }
1683
1684 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1685 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1686 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1687 hd->ioc, mf));
1688 mpt_free_msg_frame(hd->ioc, mf);
1689 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1690 hd->ioc->name));
1691 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1692 }
1693
1694 return retval;
1695}
1696
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001697static int
1698mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1699{
1700 switch (ioc->bus_type) {
1701 case FC:
1702 return 40;
1703 case SAS:
1704 return 10;
1705 case SPI:
1706 default:
1707 return 2;
1708 }
1709}
1710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1712/**
1713 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1714 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1715 *
1716 * (linux scsi_host_template.eh_abort_handler routine)
1717 *
1718 * Returns SUCCESS or FAILED.
1719 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001720int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721mptscsih_abort(struct scsi_cmnd * SCpnt)
1722{
1723 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 MPT_FRAME_HDR *mf;
1725 u32 ctx2abort;
1726 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001727 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001728 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001729 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
1731 /* If we can't locate our host adapter structure, return FAILED status.
1732 */
1733 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1734 SCpnt->result = DID_RESET << 16;
1735 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001736 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 "Can't locate host! (sc=%p)\n",
1738 SCpnt));
1739 return FAILED;
1740 }
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 /* Find this command
1743 */
1744 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001745 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 * Do OS callback.
1747 */
1748 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001749 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 "Command not in the active list! (sc=%p)\n",
1751 hd->ioc->name, SCpnt));
1752 return SUCCESS;
1753 }
1754
Moore, Eric65207fe2006-04-21 16:14:35 -06001755 if (hd->resetPending) {
1756 return FAILED;
1757 }
1758
1759 if (hd->timeouts < -1)
1760 hd->timeouts++;
1761
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001762 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1763 hd->ioc->name, SCpnt);
1764 scsi_print_command(SCpnt);
1765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1767 * (the IO to be ABORT'd)
1768 *
1769 * NOTE: Since we do not byteswap MsgContext, we do not
1770 * swap it here either. It is an opaque cookie to
1771 * the controller, so it does not matter. -DaveM
1772 */
1773 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1774 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1775
1776 hd->abortSCpnt = SCpnt;
1777
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001778 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001779 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric914c2d82006-03-14 09:19:36 -07001780 vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001781 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Eric Moore3dc0b032006-07-11 17:32:33 -06001783 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
1784 SCpnt->serial_number == sn) {
1785 retval = FAILED;
1786 }
1787
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001788 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1789 hd->ioc->name,
1790 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001792 if (retval == 0)
1793 return SUCCESS;
1794
1795 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 hd->tmPending = 0;
1797 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800}
1801
1802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1803/**
1804 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1805 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1806 *
1807 * (linux scsi_host_template.eh_dev_reset_handler routine)
1808 *
1809 * Returns SUCCESS or FAILED.
1810 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001811int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1813{
1814 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001815 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001816 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818 /* If we can't locate our host adapter structure, return FAILED status.
1819 */
1820 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001821 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 "Can't locate host! (sc=%p)\n",
1823 SCpnt));
1824 return FAILED;
1825 }
1826
1827 if (hd->resetPending)
1828 return FAILED;
1829
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001830 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001832 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001834 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001835 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -07001836 vdev->vtarget->bus_id, vdev->vtarget->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001837 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001838
1839 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1840 hd->ioc->name,
1841 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1842
1843 if (retval == 0)
1844 return SUCCESS;
1845
1846 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 hd->tmPending = 0;
1848 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001850 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851}
1852
1853/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1854/**
1855 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1856 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1857 *
1858 * (linux scsi_host_template.eh_bus_reset_handler routine)
1859 *
1860 * Returns SUCCESS or FAILED.
1861 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001862int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1864{
1865 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001866 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001867 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
1869 /* If we can't locate our host adapter structure, return FAILED status.
1870 */
1871 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001872 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 "Can't locate host! (sc=%p)\n",
1874 SCpnt ) );
1875 return FAILED;
1876 }
1877
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001878 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001880 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 if (hd->timeouts < -1)
1883 hd->timeouts++;
1884
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001885 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001886 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric914c2d82006-03-14 09:19:36 -07001887 vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001889 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1890 hd->ioc->name,
1891 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1892
1893 if (retval == 0)
1894 return SUCCESS;
1895
1896 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 hd->tmPending = 0;
1898 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001900 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901}
1902
1903/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1904/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001905 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1907 *
1908 * (linux scsi_host_template.eh_host_reset_handler routine)
1909 *
1910 * Returns SUCCESS or FAILED.
1911 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001912int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1914{
1915 MPT_SCSI_HOST * hd;
1916 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918 /* If we can't locate the host to reset, then we failed. */
1919 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001920 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 "Can't locate host! (sc=%p)\n",
1922 SCpnt ) );
1923 return FAILED;
1924 }
1925
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001926 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 hd->ioc->name, SCpnt);
1928
1929 /* If our attempts to reset the host failed, then return a failed
1930 * status. The host will be taken off line by the SCSI mid-layer.
1931 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1933 status = FAILED;
1934 } else {
1935 /* Make sure TM pending is cleared and TM state is set to
1936 * NONE.
1937 */
1938 hd->tmPending = 0;
1939 hd->tmState = TM_STATE_NONE;
1940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001942 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 "Status = %s\n",
1944 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1945
1946 return status;
1947}
1948
1949/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1950/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001951 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 * @hd: Pointer to MPT host structure.
1953 *
1954 * Returns {SUCCESS,FAILED}.
1955 */
1956static int
1957mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1958{
1959 unsigned long flags;
1960 int loop_count = 4 * 10; /* Wait 10 seconds */
1961 int status = FAILED;
1962
1963 do {
1964 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1965 if (hd->tmState == TM_STATE_NONE) {
1966 hd->tmState = TM_STATE_IN_PROGRESS;
1967 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001969 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 break;
1971 }
1972 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1973 msleep(250);
1974 } while (--loop_count);
1975
1976 return status;
1977}
1978
1979/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1980/**
1981 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1982 * @hd: Pointer to MPT host structure.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001983 * @timeout: timeout in seconds
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 *
1985 * Returns {SUCCESS,FAILED}.
1986 */
1987static int
1988mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1989{
1990 unsigned long flags;
1991 int loop_count = 4 * timeout;
1992 int status = FAILED;
1993
1994 do {
1995 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1996 if(hd->tmPending == 0) {
1997 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001998 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 break;
2000 }
2001 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002002 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 } while (--loop_count);
2004
2005 return status;
2006}
2007
2008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002009static void
2010mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2011{
2012 char *desc;
2013
2014 switch (response_code) {
2015 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2016 desc = "The task completed.";
2017 break;
2018 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2019 desc = "The IOC received an invalid frame status.";
2020 break;
2021 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2022 desc = "The task type is not supported.";
2023 break;
2024 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2025 desc = "The requested task failed.";
2026 break;
2027 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2028 desc = "The task completed successfully.";
2029 break;
2030 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2031 desc = "The LUN request is invalid.";
2032 break;
2033 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2034 desc = "The task is in the IOC queue and has not been sent to target.";
2035 break;
2036 default:
2037 desc = "unknown";
2038 break;
2039 }
2040 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2041 ioc->name, response_code, desc);
2042}
2043
2044/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045/**
2046 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2047 * @ioc: Pointer to MPT_ADAPTER structure
2048 * @mf: Pointer to SCSI task mgmt request frame
2049 * @mr: Pointer to SCSI task mgmt reply frame
2050 *
2051 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2052 * of any SCSI task management request.
2053 * This routine is registered with the MPT (base) driver at driver
2054 * load/init time via the mpt_register() API call.
2055 *
2056 * Returns 1 indicating alloc'd request frame ptr should be freed.
2057 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002058int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2060{
2061 SCSITaskMgmtReply_t *pScsiTmReply;
2062 SCSITaskMgmt_t *pScsiTmReq;
2063 MPT_SCSI_HOST *hd;
2064 unsigned long flags;
2065 u16 iocstatus;
2066 u8 tmType;
2067
2068 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2069 ioc->name, mf, mr));
2070 if (ioc->sh) {
2071 /* Depending on the thread, a timer is activated for
2072 * the TM request. Delete this timer on completion of TM.
2073 * Decrement count of outstanding TM requests.
2074 */
2075 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2076 } else {
2077 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2078 ioc->name));
2079 return 1;
2080 }
2081
2082 if (mr == NULL) {
2083 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2084 ioc->name, mf));
2085 return 1;
2086 } else {
2087 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2088 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2089
2090 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2091 tmType = pScsiTmReq->TaskType;
2092
Moore, Eric9f63bb72006-01-16 18:53:26 -07002093 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2094 pScsiTmReply->ResponseCode)
2095 mptscsih_taskmgmt_response_code(ioc,
2096 pScsiTmReply->ResponseCode);
2097
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2099 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2100 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2101
2102 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore3dc0b032006-07-11 17:32:33 -06002103 hd->tm_iocstatus = iocstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2105 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2106 /* Error? (anything non-zero?) */
2107 if (iocstatus) {
2108
2109 /* clear flags and continue.
2110 */
2111 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2112 hd->abortSCpnt = NULL;
2113
2114 /* If an internal command is present
2115 * or the TM failed - reload the FW.
2116 * FC FW may respond FAILED to an ABORT
2117 */
2118 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2119 if ((hd->cmdPtr) ||
2120 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2121 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2122 printk((KERN_WARNING
2123 " Firmware Reload FAILED!!\n"));
2124 }
2125 }
2126 }
2127 } else {
2128 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2129
2130 hd->abortSCpnt = NULL;
2131
2132 }
2133 }
2134
2135 spin_lock_irqsave(&ioc->FreeQlock, flags);
2136 hd->tmPending = 0;
2137 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2138 hd->tmState = TM_STATE_NONE;
2139
2140 return 1;
2141}
2142
2143/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2144/*
2145 * This is anyones guess quite frankly.
2146 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002147int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2149 sector_t capacity, int geom[])
2150{
2151 int heads;
2152 int sectors;
2153 sector_t cylinders;
2154 ulong dummy;
2155
2156 heads = 64;
2157 sectors = 32;
2158
2159 dummy = heads * sectors;
2160 cylinders = capacity;
2161 sector_div(cylinders,dummy);
2162
2163 /*
2164 * Handle extended translation size for logical drives
2165 * > 1Gb
2166 */
2167 if ((ulong)capacity >= 0x200000) {
2168 heads = 255;
2169 sectors = 63;
2170 dummy = heads * sectors;
2171 cylinders = capacity;
2172 sector_div(cylinders,dummy);
2173 }
2174
2175 /* return result */
2176 geom[0] = heads;
2177 geom[1] = sectors;
2178 geom[2] = cylinders;
2179
2180 dprintk((KERN_NOTICE
2181 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2182 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2183
2184 return 0;
2185}
2186
Moore, Ericf44e5462006-03-14 09:14:21 -07002187/* Search IOC page 3 to determine if this is hidden physical disk
2188 *
2189 */
2190int
2191mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2192{
2193 int i;
2194
2195 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2196 return 0;
2197 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2198 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2199 return 1;
2200 }
2201 return 0;
2202}
2203EXPORT_SYMBOL(mptscsih_is_phys_disk);
2204
James Bottomleyc92f2222006-03-01 09:02:49 -06002205int
2206mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2207{
2208 int i;
2209
2210 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2211 return -ENXIO;
2212
2213 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2214 if (physdiskid ==
2215 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2216 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2217 }
2218
2219 return -ENXIO;
2220}
2221EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2224/*
2225 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002226 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002229int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002230mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002232 VirtTarget *vtarget;
2233
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002234 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002235 if (!vtarget)
2236 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002237 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002238 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002239 return 0;
2240}
2241
2242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2243/*
2244 * OS entry point to allow host driver to alloc memory
2245 * for each scsi device. Called once per device the bus scan.
2246 * Return non-zero if allocation fails.
2247 */
2248int
2249mptscsih_slave_alloc(struct scsi_device *sdev)
2250{
2251 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002253 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002255 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002257 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 if (!vdev) {
2259 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2260 hd->ioc->name, sizeof(VirtDevice));
2261 return -ENOMEM;
2262 }
2263
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002264 vdev->lun = sdev->lun;
2265 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002267 starget = scsi_target(sdev);
2268 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002269
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002270 vdev->vtarget = vtarget;
2271
2272 if (vtarget->num_luns == 0) {
2273 hd->Targets[sdev->id] = vtarget;
2274 vtarget->ioc_id = hd->ioc->id;
2275 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2276 vtarget->target_id = sdev->id;
2277 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002278 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2279 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2280 vtarget->raidVolume = 1;
2281 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002282 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002283 }
2284 }
2285 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 return 0;
2287}
2288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289/*
2290 * OS entry point to allow for host driver to free allocated memory
2291 * Called if no device present or device being unloaded
2292 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002293void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002294mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002296 if (starget->hostdata)
2297 kfree(starget->hostdata);
2298 starget->hostdata = NULL;
2299}
2300
2301/*
2302 * OS entry point to allow for host driver to free allocated memory
2303 * Called if no device present or device being unloaded
2304 */
2305void
2306mptscsih_slave_destroy(struct scsi_device *sdev)
2307{
2308 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002310 VirtTarget *vtarget;
2311 VirtDevice *vdevice;
2312 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002314 starget = scsi_target(sdev);
2315 vtarget = starget->hostdata;
2316 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002318 mptscsih_search_running_cmds(hd, vdevice);
2319 vtarget->luns[0] &= ~(1 << vdevice->lun);
2320 vtarget->num_luns--;
2321 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 mptscsih_synchronize_cache(hd, vdevice);
2325 kfree(vdevice);
2326 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327}
2328
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002329/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2330/*
2331 * mptscsih_change_queue_depth - This function will set a devices queue depth
2332 * @sdev: per scsi_device pointer
2333 * @qdepth: requested queue depth
2334 *
2335 * Adding support for new 'change_queue_depth' api.
2336*/
2337int
2338mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002340 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2341 VirtTarget *vtarget;
2342 struct scsi_target *starget;
2343 int max_depth;
2344 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002346 starget = scsi_target(sdev);
2347 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002348
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002349 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002350 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002352 else if (sdev->type == TYPE_DISK &&
2353 vtarget->minSyncFactor <= MPT_ULTRA160)
2354 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2355 else
2356 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 } else
2358 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2359
2360 if (qdepth > max_depth)
2361 qdepth = max_depth;
2362 if (qdepth == 1)
2363 tagged = 0;
2364 else
2365 tagged = MSG_SIMPLE_TAG;
2366
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002367 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2368 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369}
2370
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371/*
2372 * OS entry point to adjust the queue_depths on a per-device basis.
2373 * Called once per device the bus scan. Use it to force the queue_depth
2374 * member to 1 if a device does not support Q tags.
2375 * Return non-zero if fails.
2376 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002377int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002378mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002380 struct Scsi_Host *sh = sdev->host;
2381 VirtTarget *vtarget;
2382 VirtDevice *vdevice;
2383 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002385 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002387 starget = scsi_target(sdev);
2388 vtarget = starget->hostdata;
2389 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
2391 dsprintk((MYIOC_s_INFO_FMT
2392 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002393 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2394 if (hd->ioc->bus_type == SPI)
2395 dsprintk((MYIOC_s_INFO_FMT
2396 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2397 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2398 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002400 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002402 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 goto slave_configure_exit;
2404 }
2405
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002406 vdevice->configured_lun=1;
2407 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2408 indexed_lun = (vdevice->lun % 32);
2409 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002410 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 dsprintk((MYIOC_s_INFO_FMT
2414 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002415 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002417 if (hd->ioc->bus_type == SPI)
2418 dsprintk((MYIOC_s_INFO_FMT
2419 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2420 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2421 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
2423slave_configure_exit:
2424
2425 dsprintk((MYIOC_s_INFO_FMT
2426 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002427 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2428 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
2430 return 0;
2431}
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2434/*
2435 * Private routines...
2436 */
2437
2438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2439/* Utility function to copy sense data from the scsi_cmnd buffer
2440 * to the FC and SCSI target structures.
2441 *
2442 */
2443static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002444mptscsih_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 -07002445{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002446 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 SCSIIORequest_t *pReq;
2448 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
2450 /* Get target structure
2451 */
2452 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002453 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
2455 if (sense_count) {
2456 u8 *sense_data;
2457 int req_index;
2458
2459 /* Copy the sense received into the scsi command block. */
2460 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2461 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2462 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2463
2464 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2465 */
2466 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002467 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 int idx;
2469 MPT_ADAPTER *ioc = hd->ioc;
2470
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002471 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2473 ioc->events[idx].eventContext = ioc->eventContext;
2474
2475 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2476 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002477 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2480
2481 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002482 if (hd->ioc->pcidev->vendor ==
2483 PCI_VENDOR_ID_IBM) {
2484 mptscsih_issue_sep_command(hd->ioc,
2485 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2486 vdev->vtarget->tflags |=
2487 MPT_TARGET_FLAGS_LED_ON;
2488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 }
2490 }
2491 } else {
2492 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2493 hd->ioc->name));
2494 }
2495}
2496
Eric Moore3dc0b032006-07-11 17:32:33 -06002497static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2499{
2500 MPT_SCSI_HOST *hd;
2501 int i;
2502
2503 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2504
2505 for (i = 0; i < hd->ioc->req_depth; i++) {
2506 if (hd->ScsiLookup[i] == sc) {
2507 return i;
2508 }
2509 }
2510
2511 return -1;
2512}
2513
2514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002515int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2517{
2518 MPT_SCSI_HOST *hd;
2519 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002520 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
2522 dtmprintk((KERN_WARNING MYNAM
2523 ": IOC %s_reset routed to SCSI host driver!\n",
2524 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2525 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2526
2527 /* If a FW reload request arrives after base installed but
2528 * before all scsi hosts have been attached, then an alt_ioc
2529 * may have a NULL sh pointer.
2530 */
2531 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2532 return 0;
2533 else
2534 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2535
2536 if (reset_phase == MPT_IOC_SETUP_RESET) {
2537 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2538
2539 /* Clean Up:
2540 * 1. Set Hard Reset Pending Flag
2541 * All new commands go to doneQ
2542 */
2543 hd->resetPending = 1;
2544
2545 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2546 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2547
2548 /* 2. Flush running commands
2549 * Clean ScsiLookup (and associated memory)
2550 * AND clean mytaskQ
2551 */
2552
2553 /* 2b. Reply to OS all known outstanding I/O commands.
2554 */
2555 mptscsih_flush_running_cmds(hd);
2556
2557 /* 2c. If there was an internal command that
2558 * has not completed, configuration or io request,
2559 * free these resources.
2560 */
2561 if (hd->cmdPtr) {
2562 del_timer(&hd->timer);
2563 mpt_free_msg_frame(ioc, hd->cmdPtr);
2564 }
2565
2566 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2567
2568 } else {
2569 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2570
2571 /* Once a FW reload begins, all new OS commands are
2572 * redirected to the doneQ w/ a reset status.
2573 * Init all control structures.
2574 */
2575
2576 /* ScsiLookup initialization
2577 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002578 for (ii=0; ii < hd->ioc->req_depth; ii++)
2579 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 /* 2. Chain Buffer initialization
2582 */
2583
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002584 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 /* 5. Enable new commands to be posted
2588 */
2589 spin_lock_irqsave(&ioc->FreeQlock, flags);
2590 hd->tmPending = 0;
2591 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2592 hd->resetPending = 0;
2593 hd->tmState = TM_STATE_NONE;
2594
2595 /* 6. If there was an internal command,
2596 * wake this process up.
2597 */
2598 if (hd->cmdPtr) {
2599 /*
2600 * Wake up the original calling thread
2601 */
2602 hd->pLocal = &hd->localReply;
2603 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002604 hd->scandv_wait_done = 1;
2605 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 hd->cmdPtr = NULL;
2607 }
2608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2610
2611 }
2612
2613 return 1; /* currently means nothing really */
2614}
2615
2616/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002617int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2619{
2620 MPT_SCSI_HOST *hd;
2621 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2622
Moore, Eric3a892be2006-03-14 09:14:03 -07002623 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 ioc->name, event));
2625
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002626 if (ioc->sh == NULL ||
2627 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2628 return 1;
2629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 switch (event) {
2631 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2632 /* FIXME! */
2633 break;
2634 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2635 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002636 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002637 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 break;
2639 case MPI_EVENT_LOGOUT: /* 09 */
2640 /* FIXME! */
2641 break;
2642
Michael Reed05e8ec12006-01-13 14:31:54 -06002643 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002644 break;
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 /*
2647 * CHECKME! Don't think we need to do
2648 * anything for these, but...
2649 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2651 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2652 /*
2653 * CHECKME! Falling thru...
2654 */
2655 break;
2656
2657 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002658 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 case MPI_EVENT_NONE: /* 00 */
2661 case MPI_EVENT_LOG_DATA: /* 01 */
2662 case MPI_EVENT_STATE_CHANGE: /* 02 */
2663 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2664 default:
2665 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2666 break;
2667 }
2668
2669 return 1; /* currently means nothing really */
2670}
2671
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2673/*
2674 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2675 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002676 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002677 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 *
2679 * NOTE: It's only SAFE to call this routine if data points to
2680 * sane & valid STANDARD INQUIRY data!
2681 *
2682 * Allocate and initialize memory for this target.
2683 * Save inquiry data.
2684 *
2685 */
2686static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002687mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2688 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002691 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 /* Is LUN supported? If so, upper 2 bits will be 0
2694 * in first byte of inquiry data.
2695 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002696 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 return;
2698
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002699 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
James Bottomleyc92f2222006-03-01 09:02:49 -06002702 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002704 if (hd->ioc->bus_type != SPI)
2705 return;
2706
James Bottomleyc92f2222006-03-01 09:02:49 -06002707 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002708 /* Treat all Processors as SAF-TE if
2709 * command line option is set */
2710 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2711 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002712 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002713 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002714 if (sdev->inquiry_len > 49 ) {
2715 if (sdev->inquiry[44] == 'S' &&
2716 sdev->inquiry[45] == 'A' &&
2717 sdev->inquiry[46] == 'F' &&
2718 sdev->inquiry[47] == '-' &&
2719 sdev->inquiry[48] == 'T' &&
2720 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002721 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2722 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
2724 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002725 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002726 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727}
2728
2729/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2730/*
2731 * Update the target negotiation parameters based on the
2732 * the Inquiry data, adapter capabilities, and NVRAM settings.
2733 *
2734 */
2735static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002736mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2737 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002739 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 int id = (int) target->target_id;
2741 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 u8 width = MPT_NARROW;
2743 u8 factor = MPT_ASYNC;
2744 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002745 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 u8 noQas = 1;
2747
2748 target->negoFlags = pspi_data->noQas;
2749
James Bottomleyc92f2222006-03-01 09:02:49 -06002750 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
James Bottomleyc92f2222006-03-01 09:02:49 -06002752 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 width = 0;
2754 factor = MPT_ULTRA2;
2755 offset = pspi_data->maxSyncOffset;
2756 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2757 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002758 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 width = 1;
2760 }
2761
James Bottomleyc92f2222006-03-01 09:02:49 -06002762 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002764 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002766 else {
2767 if (!scsi_device_ius(sdev) &&
2768 !scsi_device_qas(sdev))
2769 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002771 factor = MPT_ULTRA320;
2772 if (scsi_device_qas(sdev)) {
2773 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2774 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002776 if (sdev->type == TYPE_TAPE &&
2777 scsi_device_ius(sdev))
2778 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 offset = pspi_data->maxSyncOffset;
2782
2783 /* If RAID, never disable QAS
2784 * else if non RAID, do not disable
2785 * QAS if bit 1 is set
2786 * bit 1 QAS support, non-raid only
2787 * bit 0 IU support
2788 */
2789 if (target->raidVolume == 1) {
2790 noQas = 0;
2791 }
2792 } else {
2793 factor = MPT_ASYNC;
2794 offset = 0;
2795 }
2796 }
2797
James Bottomleyc92f2222006-03-01 09:02:49 -06002798 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2800 }
2801
2802 /* Update tflags based on NVRAM settings. (SCSI only)
2803 */
2804 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2805 nvram = pspi_data->nvram[id];
2806 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2807
2808 if (width)
2809 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2810
2811 if (offset > 0) {
2812 /* Ensure factor is set to the
2813 * maximum of: adapter, nvram, inquiry
2814 */
2815 if (nfactor) {
2816 if (nfactor < pspi_data->minSyncFactor )
2817 nfactor = pspi_data->minSyncFactor;
2818
2819 factor = max(factor, nfactor);
2820 if (factor == MPT_ASYNC)
2821 offset = 0;
2822 } else {
2823 offset = 0;
2824 factor = MPT_ASYNC;
2825 }
2826 } else {
2827 factor = MPT_ASYNC;
2828 }
2829 }
2830
2831 /* Make sure data is consistent
2832 */
2833 if ((!width) && (factor < MPT_ULTRA2)) {
2834 factor = MPT_ULTRA2;
2835 }
2836
2837 /* Save the data to the target structure.
2838 */
2839 target->minSyncFactor = factor;
2840 target->maxOffset = offset;
2841 target->maxWidth = width;
2842
2843 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2844
2845 /* Disable unused features.
2846 */
2847 if (!width)
2848 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2849
2850 if (!offset)
2851 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2852
2853 if ( factor > MPT_ULTRA320 )
2854 noQas = 0;
2855
James Bottomleyc92f2222006-03-01 09:02:49 -06002856 if (noQas && (pspi_data->noQas == 0)) {
2857 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2858 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
James Bottomleyc92f2222006-03-01 09:02:49 -06002860 /* Disable QAS in a mixed configuration case
2861 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
James Bottomleyc92f2222006-03-01 09:02:49 -06002863 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 }
2865}
2866
2867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2870/*
2871 * SCSI Config Page functionality ...
2872 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
2874/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875/* mptscsih_writeIOCPage4 - write IOC Page 4
2876 * @hd: Pointer to a SCSI Host Structure
2877 * @target_id: write IOC Page4 for this ID & Bus
2878 *
2879 * Return: -EAGAIN if unable to obtain a Message Frame
2880 * or 0 if success.
2881 *
2882 * Remark: We do not wait for a return, write pages sequentially.
2883 */
2884static int
2885mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2886{
2887 MPT_ADAPTER *ioc = hd->ioc;
2888 Config_t *pReq;
2889 IOCPage4_t *IOCPage4Ptr;
2890 MPT_FRAME_HDR *mf;
2891 dma_addr_t dataDma;
2892 u16 req_idx;
2893 u32 frameOffset;
2894 u32 flagsLength;
2895 int ii;
2896
2897 /* Get a MF for this command.
2898 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002899 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002900 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 ioc->name));
2902 return -EAGAIN;
2903 }
2904
2905 /* Set the request and the data pointers.
2906 * Place data at end of MF.
2907 */
2908 pReq = (Config_t *)mf;
2909
2910 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2911 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2912
2913 /* Complete the request frame (same for all requests).
2914 */
2915 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2916 pReq->Reserved = 0;
2917 pReq->ChainOffset = 0;
2918 pReq->Function = MPI_FUNCTION_CONFIG;
2919 pReq->ExtPageLength = 0;
2920 pReq->ExtPageType = 0;
2921 pReq->MsgFlags = 0;
2922 for (ii=0; ii < 8; ii++) {
2923 pReq->Reserved2[ii] = 0;
2924 }
2925
2926 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2927 dataDma = ioc->spi_data.IocPg4_dma;
2928 ii = IOCPage4Ptr->ActiveSEP++;
2929 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2930 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2931 pReq->Header = IOCPage4Ptr->Header;
2932 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2933
2934 /* Add a SGE to the config request.
2935 */
2936 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2937 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2938
2939 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2940
2941 dinitprintk((MYIOC_s_INFO_FMT
2942 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2943 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2944
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002945 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
2947 return 0;
2948}
2949
2950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2951/*
2952 * Bus Scan and Domain Validation functionality ...
2953 */
2954
2955/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2956/*
2957 * mptscsih_scandv_complete - Scan and DV callback routine registered
2958 * to Fustion MPT (base) driver.
2959 *
2960 * @ioc: Pointer to MPT_ADAPTER structure
2961 * @mf: Pointer to original MPT request frame
2962 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2963 *
2964 * This routine is called from mpt.c::mpt_interrupt() at the completion
2965 * of any SCSI IO request.
2966 * This routine is registered with the Fusion MPT (base) driver at driver
2967 * load/init time via the mpt_register() API call.
2968 *
2969 * Returns 1 indicating alloc'd request frame ptr should be freed.
2970 *
2971 * Remark: Sets a completion code and (possibly) saves sense data
2972 * in the IOC member localReply structure.
2973 * Used ONLY for DV and other internal commands.
2974 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002975int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2977{
2978 MPT_SCSI_HOST *hd;
2979 SCSIIORequest_t *pReq;
2980 int completionCode;
2981 u16 req_idx;
2982
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002983 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2984
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 if ((mf == NULL) ||
2986 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2987 printk(MYIOC_s_ERR_FMT
2988 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2989 ioc->name, mf?"BAD":"NULL", (void *) mf);
2990 goto wakeup;
2991 }
2992
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 del_timer(&hd->timer);
2994 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2995 hd->ScsiLookup[req_idx] = NULL;
2996 pReq = (SCSIIORequest_t *) mf;
2997
2998 if (mf != hd->cmdPtr) {
2999 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3000 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3001 }
3002 hd->cmdPtr = NULL;
3003
3004 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3005 hd->ioc->name, mf, mr, req_idx));
3006
3007 hd->pLocal = &hd->localReply;
3008 hd->pLocal->scsiStatus = 0;
3009
3010 /* If target struct exists, clear sense valid flag.
3011 */
3012 if (mr == NULL) {
3013 completionCode = MPT_SCANDV_GOOD;
3014 } else {
3015 SCSIIOReply_t *pReply;
3016 u16 status;
3017 u8 scsi_status;
3018
3019 pReply = (SCSIIOReply_t *) mr;
3020
3021 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3022 scsi_status = pReply->SCSIStatus;
3023
3024 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3025 status, pReply->SCSIState, scsi_status,
3026 le32_to_cpu(pReply->IOCLogInfo)));
3027
3028 switch(status) {
3029
3030 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3031 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3032 break;
3033
3034 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3035 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3036 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3037 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3038 completionCode = MPT_SCANDV_DID_RESET;
3039 break;
3040
3041 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3042 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3043 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3044 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3045 ConfigReply_t *pr = (ConfigReply_t *)mr;
3046 completionCode = MPT_SCANDV_GOOD;
3047 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3048 hd->pLocal->header.PageLength = pr->Header.PageLength;
3049 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3050 hd->pLocal->header.PageType = pr->Header.PageType;
3051
3052 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3053 /* If the RAID Volume request is successful,
3054 * return GOOD, else indicate that
3055 * some type of error occurred.
3056 */
3057 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003058 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 completionCode = MPT_SCANDV_GOOD;
3060 else
3061 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06003062 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
3064 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3065 u8 *sense_data;
3066 int sz;
3067
3068 /* save sense data in global structure
3069 */
3070 completionCode = MPT_SCANDV_SENSE;
3071 hd->pLocal->scsiStatus = scsi_status;
3072 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3073 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3074
3075 sz = min_t(int, pReq->SenseBufferLength,
3076 SCSI_STD_SENSE_BYTES);
3077 memcpy(hd->pLocal->sense, sense_data, sz);
3078
3079 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3080 sense_data));
3081 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3082 if (pReq->CDB[0] == INQUIRY)
3083 completionCode = MPT_SCANDV_ISSUE_SENSE;
3084 else
3085 completionCode = MPT_SCANDV_DID_RESET;
3086 }
3087 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3088 completionCode = MPT_SCANDV_DID_RESET;
3089 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3090 completionCode = MPT_SCANDV_DID_RESET;
3091 else {
3092 completionCode = MPT_SCANDV_GOOD;
3093 hd->pLocal->scsiStatus = scsi_status;
3094 }
3095 break;
3096
3097 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3098 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3099 completionCode = MPT_SCANDV_DID_RESET;
3100 else
3101 completionCode = MPT_SCANDV_SOME_ERROR;
3102 break;
3103
3104 default:
3105 completionCode = MPT_SCANDV_SOME_ERROR;
3106 break;
3107
3108 } /* switch(status) */
3109
3110 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3111 completionCode));
3112 } /* end of address reply case */
3113
3114 hd->pLocal->completion = completionCode;
3115
3116 /* MF and RF are freed in mpt_interrupt
3117 */
3118wakeup:
3119 /* Free Chain buffers (will never chain) in scan or dv */
3120 //mptscsih_freeChainBuffers(ioc, req_idx);
3121
3122 /*
3123 * Wake up the original calling thread
3124 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003125 hd->scandv_wait_done = 1;
3126 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127
3128 return 1;
3129}
3130
3131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3132/* mptscsih_timer_expired - Call back for timer process.
3133 * Used only for dv functionality.
3134 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3135 *
3136 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003137void
3138mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139{
3140 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3141
3142 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3143
3144 if (hd->cmdPtr) {
3145 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3146
3147 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3148 /* Desire to issue a task management request here.
3149 * TM requests MUST be single threaded.
3150 * If old eh code and no TM current, issue request.
3151 * If new eh code, do nothing. Wait for OS cmd timeout
3152 * for bus reset.
3153 */
3154 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3155 } else {
3156 /* Perform a FW reload */
3157 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3158 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3159 }
3160 }
3161 } else {
3162 /* This should NEVER happen */
3163 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3164 }
3165
3166 /* No more processing.
3167 * TM call will generate an interrupt for SCSI TM Management.
3168 * The FW will reply to all outstanding commands, callback will finish cleanup.
3169 * Hard reset clean-up will free all resources.
3170 */
3171 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3172
3173 return;
3174}
3175
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
3177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3178/**
3179 * mptscsih_do_cmd - Do internal command.
3180 * @hd: MPT_SCSI_HOST pointer
3181 * @io: INTERNAL_CMD pointer.
3182 *
3183 * Issue the specified internally generated command and do command
3184 * specific cleanup. For bus scan / DV only.
3185 * NOTES: If command is Inquiry and status is good,
3186 * initialize a target structure, save the data
3187 *
3188 * Remark: Single threaded access only.
3189 *
3190 * Return:
3191 * < 0 if an illegal command or no resources
3192 *
3193 * 0 if good
3194 *
3195 * > 0 if command complete but some type of completion error.
3196 */
3197static int
3198mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3199{
3200 MPT_FRAME_HDR *mf;
3201 SCSIIORequest_t *pScsiReq;
3202 SCSIIORequest_t ReqCopy;
3203 int my_idx, ii, dir;
3204 int rc, cmdTimeout;
3205 int in_isr;
3206 char cmdLen;
3207 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3208 char cmd = io->cmd;
3209
3210 in_isr = in_interrupt();
3211 if (in_isr) {
3212 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3213 hd->ioc->name));
3214 return -EPERM;
3215 }
3216
3217
3218 /* Set command specific information
3219 */
3220 switch (cmd) {
3221 case INQUIRY:
3222 cmdLen = 6;
3223 dir = MPI_SCSIIO_CONTROL_READ;
3224 CDB[0] = cmd;
3225 CDB[4] = io->size;
3226 cmdTimeout = 10;
3227 break;
3228
3229 case TEST_UNIT_READY:
3230 cmdLen = 6;
3231 dir = MPI_SCSIIO_CONTROL_READ;
3232 cmdTimeout = 10;
3233 break;
3234
3235 case START_STOP:
3236 cmdLen = 6;
3237 dir = MPI_SCSIIO_CONTROL_READ;
3238 CDB[0] = cmd;
3239 CDB[4] = 1; /*Spin up the disk */
3240 cmdTimeout = 15;
3241 break;
3242
3243 case REQUEST_SENSE:
3244 cmdLen = 6;
3245 CDB[0] = cmd;
3246 CDB[4] = io->size;
3247 dir = MPI_SCSIIO_CONTROL_READ;
3248 cmdTimeout = 10;
3249 break;
3250
3251 case READ_BUFFER:
3252 cmdLen = 10;
3253 dir = MPI_SCSIIO_CONTROL_READ;
3254 CDB[0] = cmd;
3255 if (io->flags & MPT_ICFLAG_ECHO) {
3256 CDB[1] = 0x0A;
3257 } else {
3258 CDB[1] = 0x02;
3259 }
3260
3261 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3262 CDB[1] |= 0x01;
3263 }
3264 CDB[6] = (io->size >> 16) & 0xFF;
3265 CDB[7] = (io->size >> 8) & 0xFF;
3266 CDB[8] = io->size & 0xFF;
3267 cmdTimeout = 10;
3268 break;
3269
3270 case WRITE_BUFFER:
3271 cmdLen = 10;
3272 dir = MPI_SCSIIO_CONTROL_WRITE;
3273 CDB[0] = cmd;
3274 if (io->flags & MPT_ICFLAG_ECHO) {
3275 CDB[1] = 0x0A;
3276 } else {
3277 CDB[1] = 0x02;
3278 }
3279 CDB[6] = (io->size >> 16) & 0xFF;
3280 CDB[7] = (io->size >> 8) & 0xFF;
3281 CDB[8] = io->size & 0xFF;
3282 cmdTimeout = 10;
3283 break;
3284
3285 case RESERVE:
3286 cmdLen = 6;
3287 dir = MPI_SCSIIO_CONTROL_READ;
3288 CDB[0] = cmd;
3289 cmdTimeout = 10;
3290 break;
3291
3292 case RELEASE:
3293 cmdLen = 6;
3294 dir = MPI_SCSIIO_CONTROL_READ;
3295 CDB[0] = cmd;
3296 cmdTimeout = 10;
3297 break;
3298
3299 case SYNCHRONIZE_CACHE:
3300 cmdLen = 10;
3301 dir = MPI_SCSIIO_CONTROL_READ;
3302 CDB[0] = cmd;
3303// CDB[1] = 0x02; /* set immediate bit */
3304 cmdTimeout = 10;
3305 break;
3306
3307 default:
3308 /* Error Case */
3309 return -EFAULT;
3310 }
3311
3312 /* Get and Populate a free Frame
3313 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003314 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3316 hd->ioc->name));
3317 return -EBUSY;
3318 }
3319
3320 pScsiReq = (SCSIIORequest_t *) mf;
3321
3322 /* Get the request index */
3323 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3324 ADD_INDEX_LOG(my_idx); /* for debug */
3325
3326 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3327 pScsiReq->TargetID = io->physDiskNum;
3328 pScsiReq->Bus = 0;
3329 pScsiReq->ChainOffset = 0;
3330 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3331 } else {
3332 pScsiReq->TargetID = io->id;
3333 pScsiReq->Bus = io->bus;
3334 pScsiReq->ChainOffset = 0;
3335 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3336 }
3337
3338 pScsiReq->CDBLength = cmdLen;
3339 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3340
3341 pScsiReq->Reserved = 0;
3342
3343 pScsiReq->MsgFlags = mpt_msg_flags();
3344 /* MsgContext set in mpt_get_msg_fram call */
3345
3346 for (ii=0; ii < 8; ii++)
3347 pScsiReq->LUN[ii] = 0;
3348 pScsiReq->LUN[1] = io->lun;
3349
3350 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3351 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3352 else
3353 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3354
3355 if (cmd == REQUEST_SENSE) {
3356 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3357 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3358 hd->ioc->name, cmd));
3359 }
3360
3361 for (ii=0; ii < 16; ii++)
3362 pScsiReq->CDB[ii] = CDB[ii];
3363
3364 pScsiReq->DataLength = cpu_to_le32(io->size);
3365 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3366 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3367
3368 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3369 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3370
3371 if (dir == MPI_SCSIIO_CONTROL_READ) {
3372 mpt_add_sge((char *) &pScsiReq->SGL,
3373 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3374 io->data_dma);
3375 } else {
3376 mpt_add_sge((char *) &pScsiReq->SGL,
3377 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3378 io->data_dma);
3379 }
3380
3381 /* The ISR will free the request frame, but we need
3382 * the information to initialize the target. Duplicate.
3383 */
3384 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3385
3386 /* Issue this command after:
3387 * finish init
3388 * add timer
3389 * Wait until the reply has been received
3390 * ScsiScanDvCtx callback function will
3391 * set hd->pLocal;
3392 * set scandv_wait_done and call wake_up
3393 */
3394 hd->pLocal = NULL;
3395 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003396 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
3398 /* Save cmd pointer, for resource free if timeout or
3399 * FW reload occurs
3400 */
3401 hd->cmdPtr = mf;
3402
3403 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003404 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3405 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
3407 if (hd->pLocal) {
3408 rc = hd->pLocal->completion;
3409 hd->pLocal->skip = 0;
3410
3411 /* Always set fatal error codes in some cases.
3412 */
3413 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3414 rc = -ENXIO;
3415 else if (rc == MPT_SCANDV_SOME_ERROR)
3416 rc = -rc;
3417 } else {
3418 rc = -EFAULT;
3419 /* This should never happen. */
3420 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3421 hd->ioc->name));
3422 }
3423
3424 return rc;
3425}
3426
3427/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3428/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003429 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3430 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003431 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003432 *
3433 * Uses the ISR, but with special processing.
3434 * MUST be single-threaded.
3435 *
3436 */
3437static void
3438mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3439{
3440 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441
3442 /* Following parameters will not change
3443 * in this routine.
3444 */
3445 iocmd.cmd = SYNCHRONIZE_CACHE;
3446 iocmd.flags = 0;
3447 iocmd.physDiskNum = -1;
3448 iocmd.data = NULL;
3449 iocmd.data_dma = -1;
3450 iocmd.size = 0;
3451 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003452 iocmd.bus = vdevice->vtarget->bus_id;
3453 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003454 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455
James Bottomleyc92f2222006-03-01 09:02:49 -06003456 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003457 (vdevice->configured_lun))
3458 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459}
3460
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003461EXPORT_SYMBOL(mptscsih_remove);
3462EXPORT_SYMBOL(mptscsih_shutdown);
3463#ifdef CONFIG_PM
3464EXPORT_SYMBOL(mptscsih_suspend);
3465EXPORT_SYMBOL(mptscsih_resume);
3466#endif
3467EXPORT_SYMBOL(mptscsih_proc_info);
3468EXPORT_SYMBOL(mptscsih_info);
3469EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003470EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003471EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003472EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003473EXPORT_SYMBOL(mptscsih_slave_destroy);
3474EXPORT_SYMBOL(mptscsih_slave_configure);
3475EXPORT_SYMBOL(mptscsih_abort);
3476EXPORT_SYMBOL(mptscsih_dev_reset);
3477EXPORT_SYMBOL(mptscsih_bus_reset);
3478EXPORT_SYMBOL(mptscsih_host_reset);
3479EXPORT_SYMBOL(mptscsih_bios_param);
3480EXPORT_SYMBOL(mptscsih_io_done);
3481EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3482EXPORT_SYMBOL(mptscsih_scandv_complete);
3483EXPORT_SYMBOL(mptscsih_event_process);
3484EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003485EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003486EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003487EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003489/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/