blob: 30524dc54b16b720dea158f45c5f477ff446cf19 [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
1233 *
1234 * (linux scsi_host_template.info routine)
1235 *
1236 * buffer: if write, user data; if read, buffer for user
1237 * length: if write, return length;
1238 * offset: if write, 0; if read, the current offset into the buffer from
1239 * the previous read.
1240 * hostno: scsi host number
1241 * func: if write = 1; if read = 0
1242 */
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/**
1905 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1906 * new_eh variant
1907 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1908 *
1909 * (linux scsi_host_template.eh_host_reset_handler routine)
1910 *
1911 * Returns SUCCESS or FAILED.
1912 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001913int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1915{
1916 MPT_SCSI_HOST * hd;
1917 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919 /* If we can't locate the host to reset, then we failed. */
1920 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001921 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 "Can't locate host! (sc=%p)\n",
1923 SCpnt ) );
1924 return FAILED;
1925 }
1926
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001927 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 hd->ioc->name, SCpnt);
1929
1930 /* If our attempts to reset the host failed, then return a failed
1931 * status. The host will be taken off line by the SCSI mid-layer.
1932 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1934 status = FAILED;
1935 } else {
1936 /* Make sure TM pending is cleared and TM state is set to
1937 * NONE.
1938 */
1939 hd->tmPending = 0;
1940 hd->tmState = TM_STATE_NONE;
1941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001943 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 "Status = %s\n",
1945 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1946
1947 return status;
1948}
1949
1950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1951/**
1952 * mptscsih_tm_pending_wait - wait for pending task management request to
1953 * complete.
1954 * @hd: Pointer to MPT host structure.
1955 *
1956 * Returns {SUCCESS,FAILED}.
1957 */
1958static int
1959mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1960{
1961 unsigned long flags;
1962 int loop_count = 4 * 10; /* Wait 10 seconds */
1963 int status = FAILED;
1964
1965 do {
1966 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1967 if (hd->tmState == TM_STATE_NONE) {
1968 hd->tmState = TM_STATE_IN_PROGRESS;
1969 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001971 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 break;
1973 }
1974 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1975 msleep(250);
1976 } while (--loop_count);
1977
1978 return status;
1979}
1980
1981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1982/**
1983 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1984 * @hd: Pointer to MPT host structure.
1985 *
1986 * Returns {SUCCESS,FAILED}.
1987 */
1988static int
1989mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1990{
1991 unsigned long flags;
1992 int loop_count = 4 * timeout;
1993 int status = FAILED;
1994
1995 do {
1996 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1997 if(hd->tmPending == 0) {
1998 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001999 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 break;
2001 }
2002 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002003 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 } while (--loop_count);
2005
2006 return status;
2007}
2008
2009/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002010static void
2011mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2012{
2013 char *desc;
2014
2015 switch (response_code) {
2016 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2017 desc = "The task completed.";
2018 break;
2019 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2020 desc = "The IOC received an invalid frame status.";
2021 break;
2022 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2023 desc = "The task type is not supported.";
2024 break;
2025 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2026 desc = "The requested task failed.";
2027 break;
2028 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2029 desc = "The task completed successfully.";
2030 break;
2031 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2032 desc = "The LUN request is invalid.";
2033 break;
2034 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2035 desc = "The task is in the IOC queue and has not been sent to target.";
2036 break;
2037 default:
2038 desc = "unknown";
2039 break;
2040 }
2041 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2042 ioc->name, response_code, desc);
2043}
2044
2045/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046/**
2047 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2048 * @ioc: Pointer to MPT_ADAPTER structure
2049 * @mf: Pointer to SCSI task mgmt request frame
2050 * @mr: Pointer to SCSI task mgmt reply frame
2051 *
2052 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2053 * of any SCSI task management request.
2054 * This routine is registered with the MPT (base) driver at driver
2055 * load/init time via the mpt_register() API call.
2056 *
2057 * Returns 1 indicating alloc'd request frame ptr should be freed.
2058 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002059int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2061{
2062 SCSITaskMgmtReply_t *pScsiTmReply;
2063 SCSITaskMgmt_t *pScsiTmReq;
2064 MPT_SCSI_HOST *hd;
2065 unsigned long flags;
2066 u16 iocstatus;
2067 u8 tmType;
2068
2069 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2070 ioc->name, mf, mr));
2071 if (ioc->sh) {
2072 /* Depending on the thread, a timer is activated for
2073 * the TM request. Delete this timer on completion of TM.
2074 * Decrement count of outstanding TM requests.
2075 */
2076 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2077 } else {
2078 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2079 ioc->name));
2080 return 1;
2081 }
2082
2083 if (mr == NULL) {
2084 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2085 ioc->name, mf));
2086 return 1;
2087 } else {
2088 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2089 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2090
2091 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2092 tmType = pScsiTmReq->TaskType;
2093
Moore, Eric9f63bb72006-01-16 18:53:26 -07002094 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2095 pScsiTmReply->ResponseCode)
2096 mptscsih_taskmgmt_response_code(ioc,
2097 pScsiTmReply->ResponseCode);
2098
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2100 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2101 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2102
2103 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore3dc0b032006-07-11 17:32:33 -06002104 hd->tm_iocstatus = iocstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2106 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2107 /* Error? (anything non-zero?) */
2108 if (iocstatus) {
2109
2110 /* clear flags and continue.
2111 */
2112 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2113 hd->abortSCpnt = NULL;
2114
2115 /* If an internal command is present
2116 * or the TM failed - reload the FW.
2117 * FC FW may respond FAILED to an ABORT
2118 */
2119 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2120 if ((hd->cmdPtr) ||
2121 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2122 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2123 printk((KERN_WARNING
2124 " Firmware Reload FAILED!!\n"));
2125 }
2126 }
2127 }
2128 } else {
2129 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2130
2131 hd->abortSCpnt = NULL;
2132
2133 }
2134 }
2135
2136 spin_lock_irqsave(&ioc->FreeQlock, flags);
2137 hd->tmPending = 0;
2138 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2139 hd->tmState = TM_STATE_NONE;
2140
2141 return 1;
2142}
2143
2144/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2145/*
2146 * This is anyones guess quite frankly.
2147 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002148int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2150 sector_t capacity, int geom[])
2151{
2152 int heads;
2153 int sectors;
2154 sector_t cylinders;
2155 ulong dummy;
2156
2157 heads = 64;
2158 sectors = 32;
2159
2160 dummy = heads * sectors;
2161 cylinders = capacity;
2162 sector_div(cylinders,dummy);
2163
2164 /*
2165 * Handle extended translation size for logical drives
2166 * > 1Gb
2167 */
2168 if ((ulong)capacity >= 0x200000) {
2169 heads = 255;
2170 sectors = 63;
2171 dummy = heads * sectors;
2172 cylinders = capacity;
2173 sector_div(cylinders,dummy);
2174 }
2175
2176 /* return result */
2177 geom[0] = heads;
2178 geom[1] = sectors;
2179 geom[2] = cylinders;
2180
2181 dprintk((KERN_NOTICE
2182 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2183 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2184
2185 return 0;
2186}
2187
Moore, Ericf44e5462006-03-14 09:14:21 -07002188/* Search IOC page 3 to determine if this is hidden physical disk
2189 *
2190 */
2191int
2192mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2193{
2194 int i;
2195
2196 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2197 return 0;
2198 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2199 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2200 return 1;
2201 }
2202 return 0;
2203}
2204EXPORT_SYMBOL(mptscsih_is_phys_disk);
2205
James Bottomleyc92f2222006-03-01 09:02:49 -06002206int
2207mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2208{
2209 int i;
2210
2211 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2212 return -ENXIO;
2213
2214 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2215 if (physdiskid ==
2216 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2217 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2218 }
2219
2220 return -ENXIO;
2221}
2222EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2223
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2225/*
2226 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002227 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002230int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002231mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002233 VirtTarget *vtarget;
2234
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002235 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002236 if (!vtarget)
2237 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002238 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002239 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002240 return 0;
2241}
2242
2243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2244/*
2245 * OS entry point to allow host driver to alloc memory
2246 * for each scsi device. Called once per device the bus scan.
2247 * Return non-zero if allocation fails.
2248 */
2249int
2250mptscsih_slave_alloc(struct scsi_device *sdev)
2251{
2252 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002254 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002256 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002258 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if (!vdev) {
2260 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2261 hd->ioc->name, sizeof(VirtDevice));
2262 return -ENOMEM;
2263 }
2264
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002265 vdev->lun = sdev->lun;
2266 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002268 starget = scsi_target(sdev);
2269 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002270
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002271 vdev->vtarget = vtarget;
2272
2273 if (vtarget->num_luns == 0) {
2274 hd->Targets[sdev->id] = vtarget;
2275 vtarget->ioc_id = hd->ioc->id;
2276 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2277 vtarget->target_id = sdev->id;
2278 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002279 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2280 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2281 vtarget->raidVolume = 1;
2282 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002283 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002284 }
2285 }
2286 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 return 0;
2288}
2289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290/*
2291 * OS entry point to allow for host driver to free allocated memory
2292 * Called if no device present or device being unloaded
2293 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002294void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002295mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002297 if (starget->hostdata)
2298 kfree(starget->hostdata);
2299 starget->hostdata = NULL;
2300}
2301
2302/*
2303 * OS entry point to allow for host driver to free allocated memory
2304 * Called if no device present or device being unloaded
2305 */
2306void
2307mptscsih_slave_destroy(struct scsi_device *sdev)
2308{
2309 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002311 VirtTarget *vtarget;
2312 VirtDevice *vdevice;
2313 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002315 starget = scsi_target(sdev);
2316 vtarget = starget->hostdata;
2317 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002319 mptscsih_search_running_cmds(hd, vdevice);
2320 vtarget->luns[0] &= ~(1 << vdevice->lun);
2321 vtarget->num_luns--;
2322 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002323 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002325 mptscsih_synchronize_cache(hd, vdevice);
2326 kfree(vdevice);
2327 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328}
2329
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002330/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2331/*
2332 * mptscsih_change_queue_depth - This function will set a devices queue depth
2333 * @sdev: per scsi_device pointer
2334 * @qdepth: requested queue depth
2335 *
2336 * Adding support for new 'change_queue_depth' api.
2337*/
2338int
2339mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002341 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2342 VirtTarget *vtarget;
2343 struct scsi_target *starget;
2344 int max_depth;
2345 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002347 starget = scsi_target(sdev);
2348 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002349
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002350 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002351 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002353 else if (sdev->type == TYPE_DISK &&
2354 vtarget->minSyncFactor <= MPT_ULTRA160)
2355 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2356 else
2357 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 } else
2359 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2360
2361 if (qdepth > max_depth)
2362 qdepth = max_depth;
2363 if (qdepth == 1)
2364 tagged = 0;
2365 else
2366 tagged = MSG_SIMPLE_TAG;
2367
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002368 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2369 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370}
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372/*
2373 * OS entry point to adjust the queue_depths on a per-device basis.
2374 * Called once per device the bus scan. Use it to force the queue_depth
2375 * member to 1 if a device does not support Q tags.
2376 * Return non-zero if fails.
2377 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002378int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002381 struct Scsi_Host *sh = sdev->host;
2382 VirtTarget *vtarget;
2383 VirtDevice *vdevice;
2384 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002386 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002388 starget = scsi_target(sdev);
2389 vtarget = starget->hostdata;
2390 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391
2392 dsprintk((MYIOC_s_INFO_FMT
2393 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002394 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2395 if (hd->ioc->bus_type == SPI)
2396 dsprintk((MYIOC_s_INFO_FMT
2397 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2398 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2399 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002401 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002403 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 goto slave_configure_exit;
2405 }
2406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 vdevice->configured_lun=1;
2408 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2409 indexed_lun = (vdevice->lun % 32);
2410 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002411 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002412 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 dsprintk((MYIOC_s_INFO_FMT
2415 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002416 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 if (hd->ioc->bus_type == SPI)
2419 dsprintk((MYIOC_s_INFO_FMT
2420 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2421 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2422 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424slave_configure_exit:
2425
2426 dsprintk((MYIOC_s_INFO_FMT
2427 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002428 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2429 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431 return 0;
2432}
2433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2435/*
2436 * Private routines...
2437 */
2438
2439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2440/* Utility function to copy sense data from the scsi_cmnd buffer
2441 * to the FC and SCSI target structures.
2442 *
2443 */
2444static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002445mptscsih_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 -07002446{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002447 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 SCSIIORequest_t *pReq;
2449 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 /* Get target structure
2452 */
2453 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002454 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 if (sense_count) {
2457 u8 *sense_data;
2458 int req_index;
2459
2460 /* Copy the sense received into the scsi command block. */
2461 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2462 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2463 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2464
2465 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2466 */
2467 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002468 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 int idx;
2470 MPT_ADAPTER *ioc = hd->ioc;
2471
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002472 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2474 ioc->events[idx].eventContext = ioc->eventContext;
2475
2476 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2477 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002478 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2481
2482 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002483 if (hd->ioc->pcidev->vendor ==
2484 PCI_VENDOR_ID_IBM) {
2485 mptscsih_issue_sep_command(hd->ioc,
2486 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2487 vdev->vtarget->tflags |=
2488 MPT_TARGET_FLAGS_LED_ON;
2489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 }
2491 }
2492 } else {
2493 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2494 hd->ioc->name));
2495 }
2496}
2497
Eric Moore3dc0b032006-07-11 17:32:33 -06002498static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2500{
2501 MPT_SCSI_HOST *hd;
2502 int i;
2503
2504 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2505
2506 for (i = 0; i < hd->ioc->req_depth; i++) {
2507 if (hd->ScsiLookup[i] == sc) {
2508 return i;
2509 }
2510 }
2511
2512 return -1;
2513}
2514
2515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002516int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2518{
2519 MPT_SCSI_HOST *hd;
2520 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002521 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 dtmprintk((KERN_WARNING MYNAM
2524 ": IOC %s_reset routed to SCSI host driver!\n",
2525 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2526 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2527
2528 /* If a FW reload request arrives after base installed but
2529 * before all scsi hosts have been attached, then an alt_ioc
2530 * may have a NULL sh pointer.
2531 */
2532 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2533 return 0;
2534 else
2535 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2536
2537 if (reset_phase == MPT_IOC_SETUP_RESET) {
2538 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2539
2540 /* Clean Up:
2541 * 1. Set Hard Reset Pending Flag
2542 * All new commands go to doneQ
2543 */
2544 hd->resetPending = 1;
2545
2546 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2547 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2548
2549 /* 2. Flush running commands
2550 * Clean ScsiLookup (and associated memory)
2551 * AND clean mytaskQ
2552 */
2553
2554 /* 2b. Reply to OS all known outstanding I/O commands.
2555 */
2556 mptscsih_flush_running_cmds(hd);
2557
2558 /* 2c. If there was an internal command that
2559 * has not completed, configuration or io request,
2560 * free these resources.
2561 */
2562 if (hd->cmdPtr) {
2563 del_timer(&hd->timer);
2564 mpt_free_msg_frame(ioc, hd->cmdPtr);
2565 }
2566
2567 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2568
2569 } else {
2570 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2571
2572 /* Once a FW reload begins, all new OS commands are
2573 * redirected to the doneQ w/ a reset status.
2574 * Init all control structures.
2575 */
2576
2577 /* ScsiLookup initialization
2578 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002579 for (ii=0; ii < hd->ioc->req_depth; ii++)
2580 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582 /* 2. Chain Buffer initialization
2583 */
2584
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002585 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588 /* 5. Enable new commands to be posted
2589 */
2590 spin_lock_irqsave(&ioc->FreeQlock, flags);
2591 hd->tmPending = 0;
2592 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2593 hd->resetPending = 0;
2594 hd->tmState = TM_STATE_NONE;
2595
2596 /* 6. If there was an internal command,
2597 * wake this process up.
2598 */
2599 if (hd->cmdPtr) {
2600 /*
2601 * Wake up the original calling thread
2602 */
2603 hd->pLocal = &hd->localReply;
2604 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002605 hd->scandv_wait_done = 1;
2606 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 hd->cmdPtr = NULL;
2608 }
2609
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2611
2612 }
2613
2614 return 1; /* currently means nothing really */
2615}
2616
2617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002618int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2620{
2621 MPT_SCSI_HOST *hd;
2622 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2623
Moore, Eric3a892be2006-03-14 09:14:03 -07002624 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 ioc->name, event));
2626
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002627 if (ioc->sh == NULL ||
2628 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2629 return 1;
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 switch (event) {
2632 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2633 /* FIXME! */
2634 break;
2635 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2636 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002637 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002638 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 break;
2640 case MPI_EVENT_LOGOUT: /* 09 */
2641 /* FIXME! */
2642 break;
2643
Michael Reed05e8ec12006-01-13 14:31:54 -06002644 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002645 break;
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 /*
2648 * CHECKME! Don't think we need to do
2649 * anything for these, but...
2650 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2652 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2653 /*
2654 * CHECKME! Falling thru...
2655 */
2656 break;
2657
2658 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002659 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 case MPI_EVENT_NONE: /* 00 */
2662 case MPI_EVENT_LOG_DATA: /* 01 */
2663 case MPI_EVENT_STATE_CHANGE: /* 02 */
2664 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2665 default:
2666 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2667 break;
2668 }
2669
2670 return 1; /* currently means nothing really */
2671}
2672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2674/*
2675 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2676 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002677 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002678 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 *
2680 * NOTE: It's only SAFE to call this routine if data points to
2681 * sane & valid STANDARD INQUIRY data!
2682 *
2683 * Allocate and initialize memory for this target.
2684 * Save inquiry data.
2685 *
2686 */
2687static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002688mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2689 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002692 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 /* Is LUN supported? If so, upper 2 bits will be 0
2695 * in first byte of inquiry data.
2696 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002697 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 return;
2699
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002700 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
James Bottomleyc92f2222006-03-01 09:02:49 -06002703 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002705 if (hd->ioc->bus_type != SPI)
2706 return;
2707
James Bottomleyc92f2222006-03-01 09:02:49 -06002708 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002709 /* Treat all Processors as SAF-TE if
2710 * command line option is set */
2711 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2712 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002713 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002714 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002715 if (sdev->inquiry_len > 49 ) {
2716 if (sdev->inquiry[44] == 'S' &&
2717 sdev->inquiry[45] == 'A' &&
2718 sdev->inquiry[46] == 'F' &&
2719 sdev->inquiry[47] == '-' &&
2720 sdev->inquiry[48] == 'T' &&
2721 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002722 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2723 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 }
2725 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002726 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002727 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728}
2729
2730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2731/*
2732 * Update the target negotiation parameters based on the
2733 * the Inquiry data, adapter capabilities, and NVRAM settings.
2734 *
2735 */
2736static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002737mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2738 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002740 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 int id = (int) target->target_id;
2742 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 u8 width = MPT_NARROW;
2744 u8 factor = MPT_ASYNC;
2745 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002746 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 u8 noQas = 1;
2748
2749 target->negoFlags = pspi_data->noQas;
2750
James Bottomleyc92f2222006-03-01 09:02:49 -06002751 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752
James Bottomleyc92f2222006-03-01 09:02:49 -06002753 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 width = 0;
2755 factor = MPT_ULTRA2;
2756 offset = pspi_data->maxSyncOffset;
2757 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2758 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002759 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 width = 1;
2761 }
2762
James Bottomleyc92f2222006-03-01 09:02:49 -06002763 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002765 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002767 else {
2768 if (!scsi_device_ius(sdev) &&
2769 !scsi_device_qas(sdev))
2770 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002772 factor = MPT_ULTRA320;
2773 if (scsi_device_qas(sdev)) {
2774 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2775 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002777 if (sdev->type == TYPE_TAPE &&
2778 scsi_device_ius(sdev))
2779 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 offset = pspi_data->maxSyncOffset;
2783
2784 /* If RAID, never disable QAS
2785 * else if non RAID, do not disable
2786 * QAS if bit 1 is set
2787 * bit 1 QAS support, non-raid only
2788 * bit 0 IU support
2789 */
2790 if (target->raidVolume == 1) {
2791 noQas = 0;
2792 }
2793 } else {
2794 factor = MPT_ASYNC;
2795 offset = 0;
2796 }
2797 }
2798
James Bottomleyc92f2222006-03-01 09:02:49 -06002799 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2801 }
2802
2803 /* Update tflags based on NVRAM settings. (SCSI only)
2804 */
2805 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2806 nvram = pspi_data->nvram[id];
2807 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2808
2809 if (width)
2810 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2811
2812 if (offset > 0) {
2813 /* Ensure factor is set to the
2814 * maximum of: adapter, nvram, inquiry
2815 */
2816 if (nfactor) {
2817 if (nfactor < pspi_data->minSyncFactor )
2818 nfactor = pspi_data->minSyncFactor;
2819
2820 factor = max(factor, nfactor);
2821 if (factor == MPT_ASYNC)
2822 offset = 0;
2823 } else {
2824 offset = 0;
2825 factor = MPT_ASYNC;
2826 }
2827 } else {
2828 factor = MPT_ASYNC;
2829 }
2830 }
2831
2832 /* Make sure data is consistent
2833 */
2834 if ((!width) && (factor < MPT_ULTRA2)) {
2835 factor = MPT_ULTRA2;
2836 }
2837
2838 /* Save the data to the target structure.
2839 */
2840 target->minSyncFactor = factor;
2841 target->maxOffset = offset;
2842 target->maxWidth = width;
2843
2844 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2845
2846 /* Disable unused features.
2847 */
2848 if (!width)
2849 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2850
2851 if (!offset)
2852 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2853
2854 if ( factor > MPT_ULTRA320 )
2855 noQas = 0;
2856
James Bottomleyc92f2222006-03-01 09:02:49 -06002857 if (noQas && (pspi_data->noQas == 0)) {
2858 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2859 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
James Bottomleyc92f2222006-03-01 09:02:49 -06002861 /* Disable QAS in a mixed configuration case
2862 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
James Bottomleyc92f2222006-03-01 09:02:49 -06002864 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 }
2866}
2867
2868/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
2870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2871/*
2872 * SCSI Config Page functionality ...
2873 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876/* mptscsih_writeIOCPage4 - write IOC Page 4
2877 * @hd: Pointer to a SCSI Host Structure
2878 * @target_id: write IOC Page4 for this ID & Bus
2879 *
2880 * Return: -EAGAIN if unable to obtain a Message Frame
2881 * or 0 if success.
2882 *
2883 * Remark: We do not wait for a return, write pages sequentially.
2884 */
2885static int
2886mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2887{
2888 MPT_ADAPTER *ioc = hd->ioc;
2889 Config_t *pReq;
2890 IOCPage4_t *IOCPage4Ptr;
2891 MPT_FRAME_HDR *mf;
2892 dma_addr_t dataDma;
2893 u16 req_idx;
2894 u32 frameOffset;
2895 u32 flagsLength;
2896 int ii;
2897
2898 /* Get a MF for this command.
2899 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002900 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002901 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 ioc->name));
2903 return -EAGAIN;
2904 }
2905
2906 /* Set the request and the data pointers.
2907 * Place data at end of MF.
2908 */
2909 pReq = (Config_t *)mf;
2910
2911 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2912 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2913
2914 /* Complete the request frame (same for all requests).
2915 */
2916 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2917 pReq->Reserved = 0;
2918 pReq->ChainOffset = 0;
2919 pReq->Function = MPI_FUNCTION_CONFIG;
2920 pReq->ExtPageLength = 0;
2921 pReq->ExtPageType = 0;
2922 pReq->MsgFlags = 0;
2923 for (ii=0; ii < 8; ii++) {
2924 pReq->Reserved2[ii] = 0;
2925 }
2926
2927 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2928 dataDma = ioc->spi_data.IocPg4_dma;
2929 ii = IOCPage4Ptr->ActiveSEP++;
2930 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2931 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2932 pReq->Header = IOCPage4Ptr->Header;
2933 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2934
2935 /* Add a SGE to the config request.
2936 */
2937 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2938 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2939
2940 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2941
2942 dinitprintk((MYIOC_s_INFO_FMT
2943 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2944 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2945
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002946 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
2948 return 0;
2949}
2950
2951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2952/*
2953 * Bus Scan and Domain Validation functionality ...
2954 */
2955
2956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2957/*
2958 * mptscsih_scandv_complete - Scan and DV callback routine registered
2959 * to Fustion MPT (base) driver.
2960 *
2961 * @ioc: Pointer to MPT_ADAPTER structure
2962 * @mf: Pointer to original MPT request frame
2963 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2964 *
2965 * This routine is called from mpt.c::mpt_interrupt() at the completion
2966 * of any SCSI IO request.
2967 * This routine is registered with the Fusion MPT (base) driver at driver
2968 * load/init time via the mpt_register() API call.
2969 *
2970 * Returns 1 indicating alloc'd request frame ptr should be freed.
2971 *
2972 * Remark: Sets a completion code and (possibly) saves sense data
2973 * in the IOC member localReply structure.
2974 * Used ONLY for DV and other internal commands.
2975 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002976int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2978{
2979 MPT_SCSI_HOST *hd;
2980 SCSIIORequest_t *pReq;
2981 int completionCode;
2982 u16 req_idx;
2983
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002984 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2985
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 if ((mf == NULL) ||
2987 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2988 printk(MYIOC_s_ERR_FMT
2989 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2990 ioc->name, mf?"BAD":"NULL", (void *) mf);
2991 goto wakeup;
2992 }
2993
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 del_timer(&hd->timer);
2995 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2996 hd->ScsiLookup[req_idx] = NULL;
2997 pReq = (SCSIIORequest_t *) mf;
2998
2999 if (mf != hd->cmdPtr) {
3000 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3001 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3002 }
3003 hd->cmdPtr = NULL;
3004
3005 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3006 hd->ioc->name, mf, mr, req_idx));
3007
3008 hd->pLocal = &hd->localReply;
3009 hd->pLocal->scsiStatus = 0;
3010
3011 /* If target struct exists, clear sense valid flag.
3012 */
3013 if (mr == NULL) {
3014 completionCode = MPT_SCANDV_GOOD;
3015 } else {
3016 SCSIIOReply_t *pReply;
3017 u16 status;
3018 u8 scsi_status;
3019
3020 pReply = (SCSIIOReply_t *) mr;
3021
3022 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3023 scsi_status = pReply->SCSIStatus;
3024
3025 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3026 status, pReply->SCSIState, scsi_status,
3027 le32_to_cpu(pReply->IOCLogInfo)));
3028
3029 switch(status) {
3030
3031 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3032 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3033 break;
3034
3035 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3036 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3037 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3038 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3039 completionCode = MPT_SCANDV_DID_RESET;
3040 break;
3041
3042 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3043 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3044 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3045 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3046 ConfigReply_t *pr = (ConfigReply_t *)mr;
3047 completionCode = MPT_SCANDV_GOOD;
3048 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3049 hd->pLocal->header.PageLength = pr->Header.PageLength;
3050 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3051 hd->pLocal->header.PageType = pr->Header.PageType;
3052
3053 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3054 /* If the RAID Volume request is successful,
3055 * return GOOD, else indicate that
3056 * some type of error occurred.
3057 */
3058 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003059 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 completionCode = MPT_SCANDV_GOOD;
3061 else
3062 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06003063 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
3065 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3066 u8 *sense_data;
3067 int sz;
3068
3069 /* save sense data in global structure
3070 */
3071 completionCode = MPT_SCANDV_SENSE;
3072 hd->pLocal->scsiStatus = scsi_status;
3073 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3074 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3075
3076 sz = min_t(int, pReq->SenseBufferLength,
3077 SCSI_STD_SENSE_BYTES);
3078 memcpy(hd->pLocal->sense, sense_data, sz);
3079
3080 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3081 sense_data));
3082 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3083 if (pReq->CDB[0] == INQUIRY)
3084 completionCode = MPT_SCANDV_ISSUE_SENSE;
3085 else
3086 completionCode = MPT_SCANDV_DID_RESET;
3087 }
3088 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3089 completionCode = MPT_SCANDV_DID_RESET;
3090 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3091 completionCode = MPT_SCANDV_DID_RESET;
3092 else {
3093 completionCode = MPT_SCANDV_GOOD;
3094 hd->pLocal->scsiStatus = scsi_status;
3095 }
3096 break;
3097
3098 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3099 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3100 completionCode = MPT_SCANDV_DID_RESET;
3101 else
3102 completionCode = MPT_SCANDV_SOME_ERROR;
3103 break;
3104
3105 default:
3106 completionCode = MPT_SCANDV_SOME_ERROR;
3107 break;
3108
3109 } /* switch(status) */
3110
3111 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3112 completionCode));
3113 } /* end of address reply case */
3114
3115 hd->pLocal->completion = completionCode;
3116
3117 /* MF and RF are freed in mpt_interrupt
3118 */
3119wakeup:
3120 /* Free Chain buffers (will never chain) in scan or dv */
3121 //mptscsih_freeChainBuffers(ioc, req_idx);
3122
3123 /*
3124 * Wake up the original calling thread
3125 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003126 hd->scandv_wait_done = 1;
3127 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
3129 return 1;
3130}
3131
3132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3133/* mptscsih_timer_expired - Call back for timer process.
3134 * Used only for dv functionality.
3135 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3136 *
3137 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003138void
3139mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140{
3141 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3142
3143 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3144
3145 if (hd->cmdPtr) {
3146 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3147
3148 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3149 /* Desire to issue a task management request here.
3150 * TM requests MUST be single threaded.
3151 * If old eh code and no TM current, issue request.
3152 * If new eh code, do nothing. Wait for OS cmd timeout
3153 * for bus reset.
3154 */
3155 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3156 } else {
3157 /* Perform a FW reload */
3158 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3159 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3160 }
3161 }
3162 } else {
3163 /* This should NEVER happen */
3164 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3165 }
3166
3167 /* No more processing.
3168 * TM call will generate an interrupt for SCSI TM Management.
3169 * The FW will reply to all outstanding commands, callback will finish cleanup.
3170 * Hard reset clean-up will free all resources.
3171 */
3172 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3173
3174 return;
3175}
3176
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
3178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3179/**
3180 * mptscsih_do_cmd - Do internal command.
3181 * @hd: MPT_SCSI_HOST pointer
3182 * @io: INTERNAL_CMD pointer.
3183 *
3184 * Issue the specified internally generated command and do command
3185 * specific cleanup. For bus scan / DV only.
3186 * NOTES: If command is Inquiry and status is good,
3187 * initialize a target structure, save the data
3188 *
3189 * Remark: Single threaded access only.
3190 *
3191 * Return:
3192 * < 0 if an illegal command or no resources
3193 *
3194 * 0 if good
3195 *
3196 * > 0 if command complete but some type of completion error.
3197 */
3198static int
3199mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3200{
3201 MPT_FRAME_HDR *mf;
3202 SCSIIORequest_t *pScsiReq;
3203 SCSIIORequest_t ReqCopy;
3204 int my_idx, ii, dir;
3205 int rc, cmdTimeout;
3206 int in_isr;
3207 char cmdLen;
3208 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3209 char cmd = io->cmd;
3210
3211 in_isr = in_interrupt();
3212 if (in_isr) {
3213 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3214 hd->ioc->name));
3215 return -EPERM;
3216 }
3217
3218
3219 /* Set command specific information
3220 */
3221 switch (cmd) {
3222 case INQUIRY:
3223 cmdLen = 6;
3224 dir = MPI_SCSIIO_CONTROL_READ;
3225 CDB[0] = cmd;
3226 CDB[4] = io->size;
3227 cmdTimeout = 10;
3228 break;
3229
3230 case TEST_UNIT_READY:
3231 cmdLen = 6;
3232 dir = MPI_SCSIIO_CONTROL_READ;
3233 cmdTimeout = 10;
3234 break;
3235
3236 case START_STOP:
3237 cmdLen = 6;
3238 dir = MPI_SCSIIO_CONTROL_READ;
3239 CDB[0] = cmd;
3240 CDB[4] = 1; /*Spin up the disk */
3241 cmdTimeout = 15;
3242 break;
3243
3244 case REQUEST_SENSE:
3245 cmdLen = 6;
3246 CDB[0] = cmd;
3247 CDB[4] = io->size;
3248 dir = MPI_SCSIIO_CONTROL_READ;
3249 cmdTimeout = 10;
3250 break;
3251
3252 case READ_BUFFER:
3253 cmdLen = 10;
3254 dir = MPI_SCSIIO_CONTROL_READ;
3255 CDB[0] = cmd;
3256 if (io->flags & MPT_ICFLAG_ECHO) {
3257 CDB[1] = 0x0A;
3258 } else {
3259 CDB[1] = 0x02;
3260 }
3261
3262 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3263 CDB[1] |= 0x01;
3264 }
3265 CDB[6] = (io->size >> 16) & 0xFF;
3266 CDB[7] = (io->size >> 8) & 0xFF;
3267 CDB[8] = io->size & 0xFF;
3268 cmdTimeout = 10;
3269 break;
3270
3271 case WRITE_BUFFER:
3272 cmdLen = 10;
3273 dir = MPI_SCSIIO_CONTROL_WRITE;
3274 CDB[0] = cmd;
3275 if (io->flags & MPT_ICFLAG_ECHO) {
3276 CDB[1] = 0x0A;
3277 } else {
3278 CDB[1] = 0x02;
3279 }
3280 CDB[6] = (io->size >> 16) & 0xFF;
3281 CDB[7] = (io->size >> 8) & 0xFF;
3282 CDB[8] = io->size & 0xFF;
3283 cmdTimeout = 10;
3284 break;
3285
3286 case RESERVE:
3287 cmdLen = 6;
3288 dir = MPI_SCSIIO_CONTROL_READ;
3289 CDB[0] = cmd;
3290 cmdTimeout = 10;
3291 break;
3292
3293 case RELEASE:
3294 cmdLen = 6;
3295 dir = MPI_SCSIIO_CONTROL_READ;
3296 CDB[0] = cmd;
3297 cmdTimeout = 10;
3298 break;
3299
3300 case SYNCHRONIZE_CACHE:
3301 cmdLen = 10;
3302 dir = MPI_SCSIIO_CONTROL_READ;
3303 CDB[0] = cmd;
3304// CDB[1] = 0x02; /* set immediate bit */
3305 cmdTimeout = 10;
3306 break;
3307
3308 default:
3309 /* Error Case */
3310 return -EFAULT;
3311 }
3312
3313 /* Get and Populate a free Frame
3314 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003315 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3317 hd->ioc->name));
3318 return -EBUSY;
3319 }
3320
3321 pScsiReq = (SCSIIORequest_t *) mf;
3322
3323 /* Get the request index */
3324 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3325 ADD_INDEX_LOG(my_idx); /* for debug */
3326
3327 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3328 pScsiReq->TargetID = io->physDiskNum;
3329 pScsiReq->Bus = 0;
3330 pScsiReq->ChainOffset = 0;
3331 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3332 } else {
3333 pScsiReq->TargetID = io->id;
3334 pScsiReq->Bus = io->bus;
3335 pScsiReq->ChainOffset = 0;
3336 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3337 }
3338
3339 pScsiReq->CDBLength = cmdLen;
3340 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3341
3342 pScsiReq->Reserved = 0;
3343
3344 pScsiReq->MsgFlags = mpt_msg_flags();
3345 /* MsgContext set in mpt_get_msg_fram call */
3346
3347 for (ii=0; ii < 8; ii++)
3348 pScsiReq->LUN[ii] = 0;
3349 pScsiReq->LUN[1] = io->lun;
3350
3351 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3352 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3353 else
3354 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3355
3356 if (cmd == REQUEST_SENSE) {
3357 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3358 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3359 hd->ioc->name, cmd));
3360 }
3361
3362 for (ii=0; ii < 16; ii++)
3363 pScsiReq->CDB[ii] = CDB[ii];
3364
3365 pScsiReq->DataLength = cpu_to_le32(io->size);
3366 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3367 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3368
3369 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3370 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3371
3372 if (dir == MPI_SCSIIO_CONTROL_READ) {
3373 mpt_add_sge((char *) &pScsiReq->SGL,
3374 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3375 io->data_dma);
3376 } else {
3377 mpt_add_sge((char *) &pScsiReq->SGL,
3378 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3379 io->data_dma);
3380 }
3381
3382 /* The ISR will free the request frame, but we need
3383 * the information to initialize the target. Duplicate.
3384 */
3385 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3386
3387 /* Issue this command after:
3388 * finish init
3389 * add timer
3390 * Wait until the reply has been received
3391 * ScsiScanDvCtx callback function will
3392 * set hd->pLocal;
3393 * set scandv_wait_done and call wake_up
3394 */
3395 hd->pLocal = NULL;
3396 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003397 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
3399 /* Save cmd pointer, for resource free if timeout or
3400 * FW reload occurs
3401 */
3402 hd->cmdPtr = mf;
3403
3404 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003405 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3406 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407
3408 if (hd->pLocal) {
3409 rc = hd->pLocal->completion;
3410 hd->pLocal->skip = 0;
3411
3412 /* Always set fatal error codes in some cases.
3413 */
3414 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3415 rc = -ENXIO;
3416 else if (rc == MPT_SCANDV_SOME_ERROR)
3417 rc = -rc;
3418 } else {
3419 rc = -EFAULT;
3420 /* This should never happen. */
3421 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3422 hd->ioc->name));
3423 }
3424
3425 return rc;
3426}
3427
3428/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3429/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003430 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3431 * @hd: Pointer to a SCSI HOST structure
3432 * @vtarget: per device private data
3433 * @lun: lun
3434 *
3435 * Uses the ISR, but with special processing.
3436 * MUST be single-threaded.
3437 *
3438 */
3439static void
3440mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3441{
3442 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
3444 /* Following parameters will not change
3445 * in this routine.
3446 */
3447 iocmd.cmd = SYNCHRONIZE_CACHE;
3448 iocmd.flags = 0;
3449 iocmd.physDiskNum = -1;
3450 iocmd.data = NULL;
3451 iocmd.data_dma = -1;
3452 iocmd.size = 0;
3453 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003454 iocmd.bus = vdevice->vtarget->bus_id;
3455 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003456 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457
James Bottomleyc92f2222006-03-01 09:02:49 -06003458 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003459 (vdevice->configured_lun))
3460 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461}
3462
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003463EXPORT_SYMBOL(mptscsih_remove);
3464EXPORT_SYMBOL(mptscsih_shutdown);
3465#ifdef CONFIG_PM
3466EXPORT_SYMBOL(mptscsih_suspend);
3467EXPORT_SYMBOL(mptscsih_resume);
3468#endif
3469EXPORT_SYMBOL(mptscsih_proc_info);
3470EXPORT_SYMBOL(mptscsih_info);
3471EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003472EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003473EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003474EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003475EXPORT_SYMBOL(mptscsih_slave_destroy);
3476EXPORT_SYMBOL(mptscsih_slave_configure);
3477EXPORT_SYMBOL(mptscsih_abort);
3478EXPORT_SYMBOL(mptscsih_dev_reset);
3479EXPORT_SYMBOL(mptscsih_bus_reset);
3480EXPORT_SYMBOL(mptscsih_host_reset);
3481EXPORT_SYMBOL(mptscsih_bios_param);
3482EXPORT_SYMBOL(mptscsih_io_done);
3483EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3484EXPORT_SYMBOL(mptscsih_scandv_complete);
3485EXPORT_SYMBOL(mptscsih_event_process);
3486EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003487EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003488EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003489EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/