blob: f0cca3ea93b20b8d4f72279480ac56e81e681b13 [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 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 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");
Eric Moore9f4203b2007-01-04 20:47:47 -070079MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
82
83typedef struct _BIG_SENSE_BUF {
84 u8 data[MPT_SENSE_BUFFER_ALLOC];
85} BIG_SENSE_BUF;
86
87#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
88#define MPT_SCANDV_DID_RESET (0x00000001)
89#define MPT_SCANDV_SENSE (0x00000002)
90#define MPT_SCANDV_SOME_ERROR (0x00000004)
91#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
92#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
93#define MPT_SCANDV_FALLBACK (0x00000020)
94
95#define MPT_SCANDV_MAX_RETRIES (10)
96
97#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
98#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
Moore, Eric Dean466544d2005-09-14 18:09:10 -060099#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
100#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
101#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
103#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
104
105typedef struct _internal_cmd {
106 char *data; /* data pointer */
107 dma_addr_t data_dma; /* data dma address */
108 int size; /* transfer size */
109 u8 cmd; /* SCSI Op Code */
110 u8 bus; /* bus number */
111 u8 id; /* SCSI ID (virtual) */
112 u8 lun;
113 u8 flags; /* Bit Field - See above */
114 u8 physDiskNum; /* Phys disk number, -1 else */
115 u8 rsvd2;
116 u8 rsvd;
117} INTERNAL_CMD;
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/*
120 * Other private/forward protos...
121 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400122int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400124int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
127 SCSIIORequest_t *pReq, int req_idx);
128static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400129static 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 -0700130static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
131static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -0600132static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
135
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400136int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
137int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
James Bottomleyc92f2222006-03-01 09:02:49 -0600139static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
140static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400142int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700144static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400146void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700147void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400149int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
150int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151#endif
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
156/**
157 * mptscsih_add_sge - Place a simple SGE at address pAddr.
158 * @pAddr: virtual address for SGE
159 * @flagslength: SGE flags and data transfer length
160 * @dma_addr: Physical address
161 *
162 * This routine places a MPT request frame back on the MPT adapter's
163 * FreeQ.
164 */
165static inline void
166mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
167{
168 if (sizeof(dma_addr_t) == sizeof(u64)) {
169 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
170 u32 tmp = dma_addr & 0xFFFFFFFF;
171
172 pSge->FlagsLength = cpu_to_le32(flagslength);
173 pSge->Address.Low = cpu_to_le32(tmp);
174 tmp = (u32) ((u64)dma_addr >> 32);
175 pSge->Address.High = cpu_to_le32(tmp);
176
177 } else {
178 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
179 pSge->FlagsLength = cpu_to_le32(flagslength);
180 pSge->Address = cpu_to_le32(dma_addr);
181 }
182} /* mptscsih_add_sge() */
183
184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
185/**
186 * mptscsih_add_chain - Place a chain SGE at address pAddr.
187 * @pAddr: virtual address for SGE
188 * @next: nextChainOffset value (u32's)
189 * @length: length of next SGL segment
190 * @dma_addr: Physical address
191 *
192 * This routine places a MPT request frame back on the MPT adapter's
193 * FreeQ.
194 */
195static inline void
196mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
197{
198 if (sizeof(dma_addr_t) == sizeof(u64)) {
199 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
200 u32 tmp = dma_addr & 0xFFFFFFFF;
201
202 pChain->Length = cpu_to_le16(length);
203 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
204
205 pChain->NextChainOffset = next;
206
207 pChain->Address.Low = cpu_to_le32(tmp);
208 tmp = (u32) ((u64)dma_addr >> 32);
209 pChain->Address.High = cpu_to_le32(tmp);
210 } else {
211 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
212 pChain->Length = cpu_to_le16(length);
213 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
214 pChain->NextChainOffset = next;
215 pChain->Address = cpu_to_le32(dma_addr);
216 }
217} /* mptscsih_add_chain() */
218
219/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
220/*
221 * mptscsih_getFreeChainBuffer - Function to get a free chain
222 * from the MPT_SCSI_HOST FreeChainQ.
223 * @ioc: Pointer to MPT_ADAPTER structure
224 * @req_idx: Index of the SCSI IO request frame. (output)
225 *
226 * return SUCCESS or FAILED
227 */
228static inline int
229mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
230{
231 MPT_FRAME_HDR *chainBuf;
232 unsigned long flags;
233 int rc;
234 int chain_idx;
235
236 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
237 ioc->name));
238 spin_lock_irqsave(&ioc->FreeQlock, flags);
239 if (!list_empty(&ioc->FreeChainQ)) {
240 int offset;
241
242 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
243 u.frame.linkage.list);
244 list_del(&chainBuf->u.frame.linkage.list);
245 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
246 chain_idx = offset / ioc->req_sz;
247 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200248 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
249 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 } else {
251 rc = FAILED;
252 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200253 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 ioc->name));
255 }
256 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
257
258 *retIndex = chain_idx;
259 return rc;
260} /* mptscsih_getFreeChainBuffer() */
261
262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
263/*
264 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
265 * SCSIIORequest_t Message Frame.
266 * @ioc: Pointer to MPT_ADAPTER structure
267 * @SCpnt: Pointer to scsi_cmnd structure
268 * @pReq: Pointer to SCSIIORequest_t structure
269 *
270 * Returns ...
271 */
272static int
273mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
274 SCSIIORequest_t *pReq, int req_idx)
275{
276 char *psge;
277 char *chainSge;
278 struct scatterlist *sg;
279 int frm_sz;
280 int sges_left, sg_done;
281 int chain_idx = MPT_HOST_NO_CHAIN;
282 int sgeOffset;
283 int numSgeSlots, numSgeThisFrame;
284 u32 sgflags, sgdir, thisxfer = 0;
285 int chain_dma_off = 0;
286 int newIndex;
287 int ii;
288 dma_addr_t v2;
289 u32 RequestNB;
290
291 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
292 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
293 sgdir = MPT_TRANSFER_HOST_TO_IOC;
294 } else {
295 sgdir = MPT_TRANSFER_IOC_TO_HOST;
296 }
297
298 psge = (char *) &pReq->SGL;
299 frm_sz = ioc->req_sz;
300
301 /* Map the data portion, if any.
302 * sges_left = 0 if no data transfer.
303 */
304 if ( (sges_left = SCpnt->use_sg) ) {
305 sges_left = pci_map_sg(ioc->pcidev,
306 (struct scatterlist *) SCpnt->request_buffer,
307 SCpnt->use_sg,
308 SCpnt->sc_data_direction);
309 if (sges_left == 0)
310 return FAILED;
311 } else if (SCpnt->request_bufflen) {
312 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
313 SCpnt->request_buffer,
314 SCpnt->request_bufflen,
315 SCpnt->sc_data_direction);
316 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
317 ioc->name, SCpnt, SCpnt->request_bufflen));
318 mptscsih_add_sge((char *) &pReq->SGL,
319 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
320 SCpnt->SCp.dma_handle);
321
322 return SUCCESS;
323 }
324
325 /* Handle the SG case.
326 */
327 sg = (struct scatterlist *) SCpnt->request_buffer;
328 sg_done = 0;
329 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
330 chainSge = NULL;
331
332 /* Prior to entering this loop - the following must be set
333 * current MF: sgeOffset (bytes)
334 * chainSge (Null if original MF is not a chain buffer)
335 * sg_done (num SGE done for this MF)
336 */
337
338nextSGEset:
339 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
340 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
341
342 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
343
344 /* Get first (num - 1) SG elements
345 * Skip any SG entries with a length of 0
346 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
347 */
348 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
349 thisxfer = sg_dma_len(sg);
350 if (thisxfer == 0) {
351 sg ++; /* Get next SG element from the OS */
352 sg_done++;
353 continue;
354 }
355
356 v2 = sg_dma_address(sg);
357 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
358
359 sg++; /* Get next SG element from the OS */
360 psge += (sizeof(u32) + sizeof(dma_addr_t));
361 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
362 sg_done++;
363 }
364
365 if (numSgeThisFrame == sges_left) {
366 /* Add last element, end of buffer and end of list flags.
367 */
368 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
369 MPT_SGE_FLAGS_END_OF_BUFFER |
370 MPT_SGE_FLAGS_END_OF_LIST;
371
372 /* Add last SGE and set termination flags.
373 * Note: Last SGE may have a length of 0 - which should be ok.
374 */
375 thisxfer = sg_dma_len(sg);
376
377 v2 = sg_dma_address(sg);
378 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
379 /*
380 sg++;
381 psge += (sizeof(u32) + sizeof(dma_addr_t));
382 */
383 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
384 sg_done++;
385
386 if (chainSge) {
387 /* The current buffer is a chain buffer,
388 * but there is not another one.
389 * Update the chain element
390 * Offset and Length fields.
391 */
392 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
393 } else {
394 /* The current buffer is the original MF
395 * and there is no Chain buffer.
396 */
397 pReq->ChainOffset = 0;
398 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200399 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
401 ioc->RequestNB[req_idx] = RequestNB;
402 }
403 } else {
404 /* At least one chain buffer is needed.
405 * Complete the first MF
406 * - last SGE element, set the LastElement bit
407 * - set ChainOffset (words) for orig MF
408 * (OR finish previous MF chain buffer)
409 * - update MFStructPtr ChainIndex
410 * - Populate chain element
411 * Also
412 * Loop until done.
413 */
414
415 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
416 ioc->name, sg_done));
417
418 /* Set LAST_ELEMENT flag for last non-chain element
419 * in the buffer. Since psge points at the NEXT
420 * SGE element, go back one SGE element, update the flags
421 * and reset the pointer. (Note: sgflags & thisxfer are already
422 * set properly).
423 */
424 if (sg_done) {
425 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
426 sgflags = le32_to_cpu(*ptmp);
427 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
428 *ptmp = cpu_to_le32(sgflags);
429 }
430
431 if (chainSge) {
432 /* The current buffer is a chain buffer.
433 * chainSge points to the previous Chain Element.
434 * Update its chain element Offset and Length (must
435 * include chain element size) fields.
436 * Old chain element is now complete.
437 */
438 u8 nextChain = (u8) (sgeOffset >> 2);
439 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
440 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
441 } else {
442 /* The original MF buffer requires a chain buffer -
443 * set the offset.
444 * Last element in this MF is a chain element.
445 */
446 pReq->ChainOffset = (u8) (sgeOffset >> 2);
447 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
448 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
449 ioc->RequestNB[req_idx] = RequestNB;
450 }
451
452 sges_left -= sg_done;
453
454
455 /* NOTE: psge points to the beginning of the chain element
456 * in current buffer. Get a chain buffer.
457 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200458 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
459 dfailprintk((MYIOC_s_INFO_FMT
460 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
461 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 /* Update the tracking arrays.
466 * If chainSge == NULL, update ReqToChain, else ChainToChain
467 */
468 if (chainSge) {
469 ioc->ChainToChain[chain_idx] = newIndex;
470 } else {
471 ioc->ReqToChain[req_idx] = newIndex;
472 }
473 chain_idx = newIndex;
474 chain_dma_off = ioc->req_sz * chain_idx;
475
476 /* Populate the chainSGE for the current buffer.
477 * - Set chain buffer pointer to psge and fill
478 * out the Address and Flags fields.
479 */
480 chainSge = (char *) psge;
481 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
482 psge, req_idx));
483
484 /* Start the SGE for the next buffer
485 */
486 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
487 sgeOffset = 0;
488 sg_done = 0;
489
490 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
491 psge, chain_idx));
492
493 /* Start the SGE for the next buffer
494 */
495
496 goto nextSGEset;
497 }
498
499 return SUCCESS;
500} /* mptscsih_AddSGE() */
501
Eric Moore786899b2006-07-11 17:22:22 -0600502static void
503mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
504 U32 SlotStatus)
505{
506 MPT_FRAME_HDR *mf;
507 SEPRequest_t *SEPMsg;
508
509 if (ioc->bus_type == FC)
510 return;
511
512 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
513 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
514 ioc->name,__FUNCTION__));
515 return;
516 }
517
518 SEPMsg = (SEPRequest_t *)mf;
519 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
520 SEPMsg->Bus = vtarget->bus_id;
521 SEPMsg->TargetID = vtarget->target_id;
522 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
523 SEPMsg->SlotStatus = SlotStatus;
524 devtverboseprintk((MYIOC_s_WARN_FMT
525 "Sending SEP cmd=%x id=%d bus=%d\n",
526 ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
527 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
528}
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
531/*
532 * mptscsih_io_done - Main SCSI IO callback routine registered to
533 * Fusion MPT (base) driver
534 * @ioc: Pointer to MPT_ADAPTER structure
535 * @mf: Pointer to original MPT request frame
536 * @r: Pointer to MPT reply frame (NULL if TurboReply)
537 *
538 * This routine is called from mpt.c::mpt_interrupt() at the completion
539 * of any SCSI IO request.
540 * This routine is registered with the Fusion MPT (base) driver at driver
541 * load/init time via the mpt_register() API call.
542 *
543 * Returns 1 indicating alloc'd request frame ptr should be freed.
544 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400545int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
547{
548 struct scsi_cmnd *sc;
549 MPT_SCSI_HOST *hd;
550 SCSIIORequest_t *pScsiReq;
551 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700552 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600553 VirtDevice *vdev;
554 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
557
558 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700559 req_idx_MR = (mr != NULL) ?
560 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
561 if ((req_idx != req_idx_MR) ||
562 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
563 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
564 ioc->name);
565 printk (MYIOC_s_ERR_FMT
566 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
567 ioc->name, req_idx, req_idx_MR, mf, mr,
568 hd->ScsiLookup[req_idx_MR]);
569 return 0;
570 }
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600573 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (sc == NULL) {
575 MPIHeader_t *hdr = (MPIHeader_t *)mf;
576
577 /* Remark: writeSDP1 will use the ScsiDoneCtx
578 * If a SCSI I/O cmd, device disabled by OS and
579 * completion done. Cannot touch sc struct. Just free mem.
580 */
581 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
582 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
583 ioc->name);
584
585 mptscsih_freeChainBuffers(ioc, req_idx);
586 return 1;
587 }
588
Eric Moore3dc0b032006-07-11 17:32:33 -0600589 if ((unsigned char *)mf != sc->host_scribble) {
590 mptscsih_freeChainBuffers(ioc, req_idx);
591 return 1;
592 }
593
594 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 sc->result = DID_OK << 16; /* Set default reply as OK */
596 pScsiReq = (SCSIIORequest_t *) mf;
597 pScsiReply = (SCSIIOReply_t *) mr;
598
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200599 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
600 dmfprintk((MYIOC_s_INFO_FMT
601 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
602 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
603 }else{
604 dmfprintk((MYIOC_s_INFO_FMT
605 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
606 ioc->name, mf, mr, sc, req_idx));
607 }
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 if (pScsiReply == NULL) {
610 /* special context reply handling */
611 ;
612 } else {
613 u32 xfer_cnt;
614 u16 status;
615 u8 scsi_state, scsi_status;
616
617 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
618 scsi_state = pScsiReply->SCSIState;
619 scsi_status = pScsiReply->SCSIStatus;
620 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
621 sc->resid = sc->request_bufflen - xfer_cnt;
622
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600623 /*
624 * if we get a data underrun indication, yet no data was
625 * transferred and the SCSI status indicates that the
626 * command was never started, change the data underrun
627 * to success
628 */
629 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
630 (scsi_status == MPI_SCSI_STATUS_BUSY ||
631 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
632 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
633 status = MPI_IOCSTATUS_SUCCESS;
634 }
635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
637 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
638 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700639 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600640 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 sc->request_bufflen, xfer_cnt));
642
643 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400644 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 /*
647 * Look for + dump FCP ResponseInfo[]!
648 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600649 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
650 pScsiReply->ResponseInfo) {
651 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
652 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700653 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 le32_to_cpu(pScsiReply->ResponseInfo));
655 }
656
657 switch(status) {
658 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
659 /* CHECKME!
660 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
661 * But not: DID_BUS_BUSY lest one risk
662 * killing interrupt handler:-(
663 */
664 sc->result = SAM_STAT_BUSY;
665 break;
666
667 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
668 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
669 sc->result = DID_BAD_TARGET << 16;
670 break;
671
672 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
673 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600674 if (ioc->bus_type != FC)
675 sc->result = DID_NO_CONNECT << 16;
676 /* else fibre, just stall until rescan event */
677 else
678 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
681 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600682
683 vdev = sc->device->hostdata;
684 if (!vdev)
685 break;
686 vtarget = vdev->vtarget;
687 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
688 mptscsih_issue_sep_command(ioc, vtarget,
689 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
690 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 break;
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600695 if ( ioc->bus_type == SAS ) {
696 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
697 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
698 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
699 log_info &=SAS_LOGINFO_MASK;
700 if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
701 sc->result = (DID_BUS_BUSY << 16);
702 break;
703 }
704 }
Eric Moore86dd4242007-01-04 20:44:01 -0700705 } else if (ioc->bus_type == FC) {
706 /*
707 * The FC IOC may kill a request for variety of
708 * reasons, some of which may be recovered by a
709 * retry, some which are unlikely to be
710 * recovered. Return DID_ERROR instead of
711 * DID_RESET to permit retry of the command,
712 * just not an infinite number of them
713 */
714 sc->result = DID_ERROR << 16;
715 break;
Eric Moorebf451522006-07-11 17:25:35 -0600716 }
717
718 /*
719 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
720 */
721
722 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
724 /* Linux handles an unsolicited DID_RESET better
725 * than an unsolicited DID_ABORT.
726 */
727 sc->result = DID_RESET << 16;
728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 break;
730
731 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600732 sc->resid = sc->request_bufflen - xfer_cnt;
733 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
734 sc->result=DID_SOFT_ERROR << 16;
735 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600737 dreplyprintk((KERN_NOTICE
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600738 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
742 /*
743 * Do upfront check for valid SenseData and give it
744 * precedence!
745 */
746 sc->result = (DID_OK << 16) | scsi_status;
747 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
748 /* Have already saved the status and sense data
749 */
750 ;
751 } else {
752 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600753 if (scsi_status == SAM_STAT_BUSY)
754 sc->result = SAM_STAT_BUSY;
755 else
756 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 }
758 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
759 /* What to do?
760 */
761 sc->result = DID_SOFT_ERROR << 16;
762 }
763 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
764 /* Not real sure here either... */
765 sc->result = DID_RESET << 16;
766 }
767 }
768
769 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
770 sc->underflow));
771 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
772 /* Report Queue Full
773 */
774 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
775 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 break;
778
Moore, Eric7e551472006-01-16 18:53:21 -0700779 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
780 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
782 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600783 if (scsi_status == MPI_SCSI_STATUS_BUSY)
784 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
785 else
786 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (scsi_state == 0) {
788 ;
789 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
790 /*
791 * If running against circa 200003dd 909 MPT f/w,
792 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
793 * (QUEUE_FULL) returned from device! --> get 0x0000?128
794 * and with SenseBytes set to 0.
795 */
796 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
797 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
798
799 }
800 else if (scsi_state &
801 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
802 ) {
803 /*
804 * What to do?
805 */
806 sc->result = DID_SOFT_ERROR << 16;
807 }
808 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
809 /* Not real sure here either... */
810 sc->result = DID_RESET << 16;
811 }
812 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
813 /* Device Inq. data indicates that it supports
814 * QTags, but rejects QTag messages.
815 * This command completed OK.
816 *
817 * Not real sure here either so do nothing... */
818 }
819
820 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
821 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
822
823 /* Add handling of:
824 * Reservation Conflict, Busy,
825 * Command Terminated, CHECK
826 */
827 break;
828
829 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
830 sc->result = DID_SOFT_ERROR << 16;
831 break;
832
833 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
834 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
835 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
836 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
837 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
838 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
839 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
841 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
842 default:
843 /*
844 * What to do?
845 */
846 sc->result = DID_SOFT_ERROR << 16;
847 break;
848
849 } /* switch(status) */
850
851 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
852 } /* end of address reply case */
853
854 /* Unmap the DMA buffers, if any. */
855 if (sc->use_sg) {
856 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
857 sc->use_sg, sc->sc_data_direction);
858 } else if (sc->request_bufflen) {
859 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
860 sc->request_bufflen, sc->sc_data_direction);
861 }
862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 sc->scsi_done(sc); /* Issue the command callback */
864
865 /* Free Chain buffers */
866 mptscsih_freeChainBuffers(ioc, req_idx);
867 return 1;
868}
869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870/*
871 * mptscsih_flush_running_cmds - For each command found, search
872 * Scsi_Host instance taskQ and reply to OS.
873 * Called only if recovering from a FW reload.
874 * @hd: Pointer to a SCSI HOST structure
875 *
876 * Returns: None.
877 *
878 * Must be called while new I/Os are being queued.
879 */
880static void
881mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
882{
883 MPT_ADAPTER *ioc = hd->ioc;
884 struct scsi_cmnd *SCpnt;
885 MPT_FRAME_HDR *mf;
886 int ii;
887 int max = ioc->req_depth;
888
889 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
890 for (ii= 0; ii < max; ii++) {
891 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
892
893 /* Command found.
894 */
895
896 /* Null ScsiLookup index
897 */
898 hd->ScsiLookup[ii] = NULL;
899
900 mf = MPT_INDEX_2_MFPTR(ioc, ii);
901 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
902 mf, SCpnt));
903
Eric Moore3dc0b032006-07-11 17:32:33 -0600904 /* Free Chain buffers */
905 mptscsih_freeChainBuffers(ioc, ii);
906
907 /* Free Message frames */
908 mpt_free_msg_frame(ioc, mf);
909
910 if ((unsigned char *)mf != SCpnt->host_scribble)
911 continue;
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 /* Set status, free OS resources (SG DMA buffers)
914 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400916 if (SCpnt->use_sg) {
917 pci_unmap_sg(ioc->pcidev,
918 (struct scatterlist *) SCpnt->request_buffer,
919 SCpnt->use_sg,
920 SCpnt->sc_data_direction);
921 } else if (SCpnt->request_bufflen) {
922 pci_unmap_single(ioc->pcidev,
923 SCpnt->SCp.dma_handle,
924 SCpnt->request_bufflen,
925 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 }
927 SCpnt->result = DID_RESET << 16;
928 SCpnt->host_scribble = NULL;
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
931 }
932 }
933
934 return;
935}
936
937/*
938 * mptscsih_search_running_cmds - Delete any commands associated
939 * with the specified target and lun. Function called only
940 * when a lun is disable by mid-layer.
941 * Do NOT access the referenced scsi_cmnd structure or
942 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600943 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700944 * @hd: Pointer to a SCSI HOST structure
945 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 *
947 * Returns: None.
948 *
949 * Called from slave_destroy.
950 */
951static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700952mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 SCSIIORequest_t *mf = NULL;
955 int ii;
956 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600957 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Ericbd23e942006-04-17 12:43:04 -0600960 vdevice->vtarget->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600963 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600966 if (mf == NULL)
967 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
969 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
Moore, Eric914c2d82006-03-14 09:19:36 -0700970 if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 continue;
972
973 /* Cleanup
974 */
975 hd->ScsiLookup[ii] = NULL;
976 mptscsih_freeChainBuffers(hd->ioc, ii);
977 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -0600978 if ((unsigned char *)mf != sc->host_scribble)
979 continue;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600980 if (sc->use_sg) {
981 pci_unmap_sg(hd->ioc->pcidev,
982 (struct scatterlist *) sc->request_buffer,
983 sc->use_sg,
984 sc->sc_data_direction);
985 } else if (sc->request_bufflen) {
986 pci_unmap_single(hd->ioc->pcidev,
987 sc->SCp.dma_handle,
988 sc->request_bufflen,
989 sc->sc_data_direction);
990 }
991 sc->host_scribble = NULL;
992 sc->result = DID_NO_CONNECT << 16;
993 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return;
997}
998
999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1002/*
1003 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1004 * from a SCSI target device.
1005 * @sc: Pointer to scsi_cmnd structure
1006 * @pScsiReply: Pointer to SCSIIOReply_t
1007 * @pScsiReq: Pointer to original SCSI request
1008 *
1009 * This routine periodically reports QUEUE_FULL status returned from a
1010 * SCSI target device. It reports this to the console via kernel
1011 * printk() API call, not more than once every 10 seconds.
1012 */
1013static void
1014mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1015{
1016 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001019 if (sc->device == NULL)
1020 return;
1021 if (sc->device->host == NULL)
1022 return;
1023 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1024 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001026 if (time - hd->last_queue_full > 10 * HZ) {
1027 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1028 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1029 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031}
1032
1033/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1034/*
1035 * mptscsih_remove - Removed scsi devices
1036 * @pdev: Pointer to pci_dev structure
1037 *
1038 *
1039 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001040void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041mptscsih_remove(struct pci_dev *pdev)
1042{
1043 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1044 struct Scsi_Host *host = ioc->sh;
1045 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001046 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001048 if(!host) {
1049 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 scsi_remove_host(host);
1054
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001055 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1056 return;
1057
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001058 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001060 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001062 if (hd->ScsiLookup != NULL) {
1063 sz1 = hd->ioc->req_depth * sizeof(void *);
1064 kfree(hd->ScsiLookup);
1065 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 }
1067
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001068 /*
1069 * Free pointer array.
1070 */
1071 kfree(hd->Targets);
1072 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001074 dprintk((MYIOC_s_INFO_FMT
1075 "Free'd ScsiLookup (%d) memory\n",
1076 hd->ioc->name, sz1));
1077
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001078 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001079
1080 /* NULL the Scsi_Host pointer
1081 */
1082 hd->ioc->sh = NULL;
1083
1084 scsi_host_put(host);
1085
1086 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088}
1089
1090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1091/*
1092 * mptscsih_shutdown - reboot notifier
1093 *
1094 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001095void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001096mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001098 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 struct Scsi_Host *host = ioc->sh;
1100 MPT_SCSI_HOST *hd;
1101
1102 if(!host)
1103 return;
1104
1105 hd = (MPT_SCSI_HOST *)host->hostdata;
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109#ifdef CONFIG_PM
1110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1111/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001112 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 *
1114 *
1115 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001116int
Pavel Machek8d189f72005-04-16 15:25:28 -07001117mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001119 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001120 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121}
1122
1123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1124/*
1125 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1126 *
1127 *
1128 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001129int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130mptscsih_resume(struct pci_dev *pdev)
1131{
1132 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1133 struct Scsi_Host *host = ioc->sh;
1134 MPT_SCSI_HOST *hd;
1135
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001136 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 if(!host)
1139 return 0;
1140
1141 hd = (MPT_SCSI_HOST *)host->hostdata;
1142 if(!hd)
1143 return 0;
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return 0;
1146}
1147
1148#endif
1149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1151/**
1152 * mptscsih_info - Return information about MPT adapter
1153 * @SChost: Pointer to Scsi_Host structure
1154 *
1155 * (linux scsi_host_template.info routine)
1156 *
1157 * Returns pointer to buffer where information was written.
1158 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160mptscsih_info(struct Scsi_Host *SChost)
1161{
1162 MPT_SCSI_HOST *h;
1163 int size = 0;
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001168 if (h->info_kbuf == NULL)
1169 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1170 return h->info_kbuf;
1171 h->info_kbuf[0] = '\0';
1172
1173 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1174 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001177 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180struct info_str {
1181 char *buffer;
1182 int length;
1183 int offset;
1184 int pos;
1185};
1186
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001187static void
1188mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189{
1190 if (info->pos + len > info->length)
1191 len = info->length - info->pos;
1192
1193 if (info->pos + len < info->offset) {
1194 info->pos += len;
1195 return;
1196 }
1197
1198 if (info->pos < info->offset) {
1199 data += (info->offset - info->pos);
1200 len -= (info->offset - info->pos);
1201 }
1202
1203 if (len > 0) {
1204 memcpy(info->buffer + info->pos, data, len);
1205 info->pos += len;
1206 }
1207}
1208
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001209static int
1210mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
1212 va_list args;
1213 char buf[81];
1214 int len;
1215
1216 va_start(args, fmt);
1217 len = vsprintf(buf, fmt, args);
1218 va_end(args);
1219
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001220 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 return len;
1222}
1223
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001224static int
1225mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
1227 struct info_str info;
1228
1229 info.buffer = pbuf;
1230 info.length = len;
1231 info.offset = offset;
1232 info.pos = 0;
1233
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1235 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1236 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1237 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1240}
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001245 * @host: scsi host struct
1246 * @buffer: if write, user data; if read, buffer for user
1247 * @start: returns the buffer address
1248 * @offset: if write, 0; if read, the current offset into the buffer from
1249 * the previous read.
1250 * @length: if write, return length;
1251 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 *
1253 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001255int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1257 int length, int func)
1258{
1259 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1260 MPT_ADAPTER *ioc = hd->ioc;
1261 int size = 0;
1262
1263 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001264 /*
1265 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 */
1267 } else {
1268 if (start)
1269 *start = buffer;
1270
1271 size = mptscsih_host_info(ioc, buffer, offset, length);
1272 }
1273
1274 return size;
1275}
1276
1277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1278#define ADD_INDEX_LOG(req_ent) do { } while(0)
1279
1280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1281/**
1282 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1283 * @SCpnt: Pointer to scsi_cmnd structure
1284 * @done: Pointer SCSI mid-layer IO completion function
1285 *
1286 * (linux scsi_host_template.queuecommand routine)
1287 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1288 * from a linux scsi_cmnd request and send it to the IOC.
1289 *
1290 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1291 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001292int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1294{
1295 MPT_SCSI_HOST *hd;
1296 MPT_FRAME_HDR *mf;
1297 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001298 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 int lun;
1300 u32 datalen;
1301 u32 scsictl;
1302 u32 scsidir;
1303 u32 cmd_len;
1304 int my_idx;
1305 int ii;
1306
1307 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 lun = SCpnt->device->lun;
1309 SCpnt->scsi_done = done;
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1312 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1313
1314 if (hd->resetPending) {
1315 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1316 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1317 return SCSI_MLQUEUE_HOST_BUSY;
1318 }
1319
Moore, Ericf44e5462006-03-14 09:14:21 -07001320 if ((hd->ioc->bus_type == SPI) &&
1321 vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001322 mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
1323 SCpnt->result = DID_NO_CONNECT << 16;
1324 done(SCpnt);
1325 return 0;
1326 }
1327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 /*
1329 * Put together a MPT SCSI request...
1330 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001331 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1333 hd->ioc->name));
1334 return SCSI_MLQUEUE_HOST_BUSY;
1335 }
1336
1337 pScsiReq = (SCSIIORequest_t *) mf;
1338
1339 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1340
1341 ADD_INDEX_LOG(my_idx);
1342
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001343 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 * Seems we may receive a buffer (datalen>0) even when there
1345 * will be no data transfer! GRRRRR...
1346 */
1347 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1348 datalen = SCpnt->request_bufflen;
1349 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1350 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1351 datalen = SCpnt->request_bufflen;
1352 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1353 } else {
1354 datalen = 0;
1355 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1356 }
1357
1358 /* Default to untagged. Once a target structure has been allocated,
1359 * use the Inquiry data to determine if device supports tagged.
1360 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001361 if (vdev
1362 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 && (SCpnt->device->tagged_supported)) {
1364 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1365 } else {
1366 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1367 }
1368
1369 /* Use the above information to set up the message frame
1370 */
Moore, Eric914c2d82006-03-14 09:19:36 -07001371 pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
1372 pScsiReq->Bus = vdev->vtarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001374 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1375 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1376 else
1377 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 pScsiReq->CDBLength = SCpnt->cmd_len;
1379 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1380 pScsiReq->Reserved = 0;
1381 pScsiReq->MsgFlags = mpt_msg_flags();
1382 pScsiReq->LUN[0] = 0;
1383 pScsiReq->LUN[1] = lun;
1384 pScsiReq->LUN[2] = 0;
1385 pScsiReq->LUN[3] = 0;
1386 pScsiReq->LUN[4] = 0;
1387 pScsiReq->LUN[5] = 0;
1388 pScsiReq->LUN[6] = 0;
1389 pScsiReq->LUN[7] = 0;
1390 pScsiReq->Control = cpu_to_le32(scsictl);
1391
1392 /*
1393 * Write SCSI CDB into the message
1394 */
1395 cmd_len = SCpnt->cmd_len;
1396 for (ii=0; ii < cmd_len; ii++)
1397 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1398
1399 for (ii=cmd_len; ii < 16; ii++)
1400 pScsiReq->CDB[ii] = 0;
1401
1402 /* DataLength */
1403 pScsiReq->DataLength = cpu_to_le32(datalen);
1404
1405 /* SenseBuffer low address */
1406 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1407 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1408
1409 /* Now add the SG list
1410 * Always have a SGE even if null length.
1411 */
1412 if (datalen == 0) {
1413 /* Add a NULL SGE */
1414 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1415 (dma_addr_t) -1);
1416 } else {
1417 /* Add a 32 or 64 bit SGE */
1418 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1419 goto fail;
1420 }
1421
Eric Moore3dc0b032006-07-11 17:32:33 -06001422 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001425 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1427 hd->ioc->name, SCpnt, mf, my_idx));
1428 DBG_DUMP_REQUEST_FRAME(mf)
1429 return 0;
1430
1431 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001432 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1434 mpt_free_msg_frame(hd->ioc, mf);
1435 return SCSI_MLQUEUE_HOST_BUSY;
1436}
1437
1438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1439/*
1440 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1441 * with a SCSI IO request
1442 * @hd: Pointer to the MPT_SCSI_HOST instance
1443 * @req_idx: Index of the SCSI IO request frame.
1444 *
1445 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1446 * No return.
1447 */
1448static void
1449mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1450{
1451 MPT_FRAME_HDR *chain;
1452 unsigned long flags;
1453 int chain_idx;
1454 int next;
1455
1456 /* Get the first chain index and reset
1457 * tracker state.
1458 */
1459 chain_idx = ioc->ReqToChain[req_idx];
1460 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1461
1462 while (chain_idx != MPT_HOST_NO_CHAIN) {
1463
1464 /* Save the next chain buffer index */
1465 next = ioc->ChainToChain[chain_idx];
1466
1467 /* Free this chain buffer and reset
1468 * tracker
1469 */
1470 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1471
1472 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1473 + (chain_idx * ioc->req_sz));
1474
1475 spin_lock_irqsave(&ioc->FreeQlock, flags);
1476 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1477 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1478
1479 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1480 ioc->name, chain_idx));
1481
1482 /* handle next */
1483 chain_idx = next;
1484 }
1485 return;
1486}
1487
1488/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1489/*
1490 * Reset Handling
1491 */
1492
1493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1494/*
1495 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1496 * Fall through to mpt_HardResetHandler if: not operational, too many
1497 * failed TM requests or handshake failure.
1498 *
1499 * @ioc: Pointer to MPT_ADAPTER structure
1500 * @type: Task Management type
1501 * @target: Logical Target ID for reset (if appropriate)
1502 * @lun: Logical Unit for reset (if appropriate)
1503 * @ctx2abort: Context for the task to be aborted (if appropriate)
1504 *
1505 * Remark: Currently invoked from a non-interrupt thread (_bh).
1506 *
1507 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1508 * will be active.
1509 *
1510 * Returns 0 for SUCCESS or -1 if FAILED.
1511 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001512int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1514{
1515 MPT_ADAPTER *ioc;
1516 int rc = -1;
1517 int doTask = 1;
1518 u32 ioc_raw_state;
1519 unsigned long flags;
1520
1521 /* If FW is being reloaded currently, return success to
1522 * the calling function.
1523 */
1524 if (hd == NULL)
1525 return 0;
1526
1527 ioc = hd->ioc;
1528 if (ioc == NULL) {
1529 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1530 return FAILED;
1531 }
1532 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1533
1534 // SJR - CHECKME - Can we avoid this here?
1535 // (mpt_HardResetHandler has this check...)
1536 spin_lock_irqsave(&ioc->diagLock, flags);
1537 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1538 spin_unlock_irqrestore(&ioc->diagLock, flags);
1539 return FAILED;
1540 }
1541 spin_unlock_irqrestore(&ioc->diagLock, flags);
1542
1543 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1544 * If we time out and not bus reset, then we return a FAILED status to the caller.
1545 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1546 * successful. Otherwise, reload the FW.
1547 */
1548 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1549 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001550 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 "Timed out waiting for last TM (%d) to complete! \n",
1552 hd->ioc->name, hd->tmPending));
1553 return FAILED;
1554 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001555 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 "Timed out waiting for last TM (%d) to complete! \n",
1557 hd->ioc->name, hd->tmPending));
1558 return FAILED;
1559 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001560 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 "Timed out waiting for last TM (%d) to complete! \n",
1562 hd->ioc->name, hd->tmPending));
1563 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1564 return FAILED;
1565
1566 doTask = 0;
1567 }
1568 } else {
1569 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1570 hd->tmPending |= (1 << type);
1571 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1572 }
1573
1574 /* Is operational?
1575 */
1576 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1577
1578#ifdef MPT_DEBUG_RESET
1579 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1580 printk(MYIOC_s_WARN_FMT
1581 "TM Handler: IOC Not operational(0x%x)!\n",
1582 hd->ioc->name, ioc_raw_state);
1583 }
1584#endif
1585
1586 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1587 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1588
1589 /* Isse the Task Mgmt request.
1590 */
1591 if (hd->hard_resets < -1)
1592 hd->hard_resets++;
1593 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1594 if (rc) {
1595 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1596 } else {
1597 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1598 }
1599 }
1600
1601 /* Only fall through to the HRH if this is a bus reset
1602 */
1603 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1604 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1605 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1606 hd->ioc->name));
1607 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1608 }
1609
Eric Moore3dc0b032006-07-11 17:32:33 -06001610 /*
1611 * Check IOCStatus from TM reply message
1612 */
1613 if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
1614 rc = FAILED;
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1617
1618 return rc;
1619}
1620
1621
1622/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1623/*
1624 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1625 * @hd: Pointer to MPT_SCSI_HOST structure
1626 * @type: Task Management type
1627 * @target: Logical Target ID for reset (if appropriate)
1628 * @lun: Logical Unit for reset (if appropriate)
1629 * @ctx2abort: Context for the task to be aborted (if appropriate)
1630 *
1631 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1632 * or a non-interrupt thread. In the former, must not call schedule().
1633 *
1634 * Not all fields are meaningfull for all task types.
1635 *
1636 * Returns 0 for SUCCESS, -999 for "no msg frames",
1637 * else other non-zero value returned.
1638 */
1639static int
1640mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1641{
1642 MPT_FRAME_HDR *mf;
1643 SCSITaskMgmt_t *pScsiTm;
1644 int ii;
1645 int retval;
1646
1647 /* Return Fail to calling function if no message frames available.
1648 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001649 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1651 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001652 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 }
1654 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1655 hd->ioc->name, mf));
1656
1657 /* Format the Request
1658 */
1659 pScsiTm = (SCSITaskMgmt_t *) mf;
1660 pScsiTm->TargetID = target;
1661 pScsiTm->Bus = channel;
1662 pScsiTm->ChainOffset = 0;
1663 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1664
1665 pScsiTm->Reserved = 0;
1666 pScsiTm->TaskType = type;
1667 pScsiTm->Reserved1 = 0;
1668 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1669 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1670
1671 for (ii= 0; ii < 8; ii++) {
1672 pScsiTm->LUN[ii] = 0;
1673 }
1674 pScsiTm->LUN[1] = lun;
1675
1676 for (ii=0; ii < 7; ii++)
1677 pScsiTm->Reserved2[ii] = 0;
1678
1679 pScsiTm->TaskMsgContext = ctx2abort;
1680
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001681 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1682 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
1684 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1685
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001686 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1688 CAN_SLEEP)) != 0) {
1689 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1690 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1691 hd->ioc, mf));
1692 mpt_free_msg_frame(hd->ioc, mf);
1693 return retval;
1694 }
1695
1696 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1697 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1698 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1699 hd->ioc, mf));
1700 mpt_free_msg_frame(hd->ioc, mf);
1701 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1702 hd->ioc->name));
1703 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1704 }
1705
1706 return retval;
1707}
1708
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001709static int
1710mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1711{
1712 switch (ioc->bus_type) {
1713 case FC:
1714 return 40;
1715 case SAS:
1716 return 10;
1717 case SPI:
1718 default:
1719 return 2;
1720 }
1721}
1722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1724/**
1725 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1726 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1727 *
1728 * (linux scsi_host_template.eh_abort_handler routine)
1729 *
1730 * Returns SUCCESS or FAILED.
1731 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001732int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733mptscsih_abort(struct scsi_cmnd * SCpnt)
1734{
1735 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 MPT_FRAME_HDR *mf;
1737 u32 ctx2abort;
1738 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001739 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001740 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001741 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
1743 /* If we can't locate our host adapter structure, return FAILED status.
1744 */
1745 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1746 SCpnt->result = DID_RESET << 16;
1747 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001748 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 "Can't locate host! (sc=%p)\n",
1750 SCpnt));
1751 return FAILED;
1752 }
1753
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 /* Find this command
1755 */
1756 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001757 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 * Do OS callback.
1759 */
1760 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001761 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 "Command not in the active list! (sc=%p)\n",
1763 hd->ioc->name, SCpnt));
1764 return SUCCESS;
1765 }
1766
Moore, Eric65207fe2006-04-21 16:14:35 -06001767 if (hd->resetPending) {
1768 return FAILED;
1769 }
1770
1771 if (hd->timeouts < -1)
1772 hd->timeouts++;
1773
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001774 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1775 hd->ioc->name, SCpnt);
1776 scsi_print_command(SCpnt);
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1779 * (the IO to be ABORT'd)
1780 *
1781 * NOTE: Since we do not byteswap MsgContext, we do not
1782 * swap it here either. It is an opaque cookie to
1783 * the controller, so it does not matter. -DaveM
1784 */
1785 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1786 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1787
1788 hd->abortSCpnt = SCpnt;
1789
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001790 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001791 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric914c2d82006-03-14 09:19:36 -07001792 vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001793 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
Eric Moore3dc0b032006-07-11 17:32:33 -06001795 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
1796 SCpnt->serial_number == sn) {
1797 retval = FAILED;
1798 }
1799
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1801 hd->ioc->name,
1802 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001804 if (retval == 0)
1805 return SUCCESS;
1806
1807 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 hd->tmPending = 0;
1809 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001811 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
1814/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1815/**
1816 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1817 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1818 *
1819 * (linux scsi_host_template.eh_dev_reset_handler routine)
1820 *
1821 * Returns SUCCESS or FAILED.
1822 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001823int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1825{
1826 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001827 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001828 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
1830 /* If we can't locate our host adapter structure, return FAILED status.
1831 */
1832 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001833 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 "Can't locate host! (sc=%p)\n",
1835 SCpnt));
1836 return FAILED;
1837 }
1838
1839 if (hd->resetPending)
1840 return FAILED;
1841
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001844 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001846 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001847 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -07001848 vdev->vtarget->bus_id, vdev->vtarget->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001849 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001850
1851 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1852 hd->ioc->name,
1853 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1854
1855 if (retval == 0)
1856 return SUCCESS;
1857
1858 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 hd->tmPending = 0;
1860 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001862 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863}
1864
1865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1866/**
1867 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1868 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1869 *
1870 * (linux scsi_host_template.eh_bus_reset_handler routine)
1871 *
1872 * Returns SUCCESS or FAILED.
1873 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001874int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1876{
1877 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001878 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001879 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
1881 /* If we can't locate our host adapter structure, return FAILED status.
1882 */
1883 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001884 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 "Can't locate host! (sc=%p)\n",
1886 SCpnt ) );
1887 return FAILED;
1888 }
1889
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001890 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001892 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894 if (hd->timeouts < -1)
1895 hd->timeouts++;
1896
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001897 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001898 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric914c2d82006-03-14 09:19:36 -07001899 vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001901 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1902 hd->ioc->name,
1903 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1904
1905 if (retval == 0)
1906 return SUCCESS;
1907
1908 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 hd->tmPending = 0;
1910 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001912 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913}
1914
1915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1916/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001917 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1919 *
1920 * (linux scsi_host_template.eh_host_reset_handler routine)
1921 *
1922 * Returns SUCCESS or FAILED.
1923 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001924int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1926{
1927 MPT_SCSI_HOST * hd;
1928 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
1930 /* If we can't locate the host to reset, then we failed. */
1931 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001932 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 "Can't locate host! (sc=%p)\n",
1934 SCpnt ) );
1935 return FAILED;
1936 }
1937
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001938 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 hd->ioc->name, SCpnt);
1940
1941 /* If our attempts to reset the host failed, then return a failed
1942 * status. The host will be taken off line by the SCSI mid-layer.
1943 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1945 status = FAILED;
1946 } else {
1947 /* Make sure TM pending is cleared and TM state is set to
1948 * NONE.
1949 */
1950 hd->tmPending = 0;
1951 hd->tmState = TM_STATE_NONE;
1952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001954 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 "Status = %s\n",
1956 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1957
1958 return status;
1959}
1960
1961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1962/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001963 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 * @hd: Pointer to MPT host structure.
1965 *
1966 * Returns {SUCCESS,FAILED}.
1967 */
1968static int
1969mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1970{
1971 unsigned long flags;
1972 int loop_count = 4 * 10; /* Wait 10 seconds */
1973 int status = FAILED;
1974
1975 do {
1976 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1977 if (hd->tmState == TM_STATE_NONE) {
1978 hd->tmState = TM_STATE_IN_PROGRESS;
1979 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001981 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 break;
1983 }
1984 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1985 msleep(250);
1986 } while (--loop_count);
1987
1988 return status;
1989}
1990
1991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1992/**
1993 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1994 * @hd: Pointer to MPT host structure.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001995 * @timeout: timeout in seconds
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 *
1997 * Returns {SUCCESS,FAILED}.
1998 */
1999static int
2000mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2001{
2002 unsigned long flags;
2003 int loop_count = 4 * timeout;
2004 int status = FAILED;
2005
2006 do {
2007 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2008 if(hd->tmPending == 0) {
2009 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002010 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 break;
2012 }
2013 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002014 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 } while (--loop_count);
2016
2017 return status;
2018}
2019
2020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002021static void
2022mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2023{
2024 char *desc;
2025
2026 switch (response_code) {
2027 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2028 desc = "The task completed.";
2029 break;
2030 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2031 desc = "The IOC received an invalid frame status.";
2032 break;
2033 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2034 desc = "The task type is not supported.";
2035 break;
2036 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2037 desc = "The requested task failed.";
2038 break;
2039 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2040 desc = "The task completed successfully.";
2041 break;
2042 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2043 desc = "The LUN request is invalid.";
2044 break;
2045 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2046 desc = "The task is in the IOC queue and has not been sent to target.";
2047 break;
2048 default:
2049 desc = "unknown";
2050 break;
2051 }
2052 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2053 ioc->name, response_code, desc);
2054}
2055
2056/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057/**
2058 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2059 * @ioc: Pointer to MPT_ADAPTER structure
2060 * @mf: Pointer to SCSI task mgmt request frame
2061 * @mr: Pointer to SCSI task mgmt reply frame
2062 *
2063 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2064 * of any SCSI task management request.
2065 * This routine is registered with the MPT (base) driver at driver
2066 * load/init time via the mpt_register() API call.
2067 *
2068 * Returns 1 indicating alloc'd request frame ptr should be freed.
2069 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002070int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2072{
2073 SCSITaskMgmtReply_t *pScsiTmReply;
2074 SCSITaskMgmt_t *pScsiTmReq;
2075 MPT_SCSI_HOST *hd;
2076 unsigned long flags;
2077 u16 iocstatus;
2078 u8 tmType;
2079
2080 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2081 ioc->name, mf, mr));
2082 if (ioc->sh) {
2083 /* Depending on the thread, a timer is activated for
2084 * the TM request. Delete this timer on completion of TM.
2085 * Decrement count of outstanding TM requests.
2086 */
2087 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2088 } else {
2089 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2090 ioc->name));
2091 return 1;
2092 }
2093
2094 if (mr == NULL) {
2095 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2096 ioc->name, mf));
2097 return 1;
2098 } else {
2099 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2100 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2101
2102 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2103 tmType = pScsiTmReq->TaskType;
2104
Moore, Eric9f63bb72006-01-16 18:53:26 -07002105 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2106 pScsiTmReply->ResponseCode)
2107 mptscsih_taskmgmt_response_code(ioc,
2108 pScsiTmReply->ResponseCode);
2109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2111 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2112 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2113
2114 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore3dc0b032006-07-11 17:32:33 -06002115 hd->tm_iocstatus = iocstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2117 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2118 /* Error? (anything non-zero?) */
2119 if (iocstatus) {
2120
2121 /* clear flags and continue.
2122 */
2123 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2124 hd->abortSCpnt = NULL;
2125
2126 /* If an internal command is present
2127 * or the TM failed - reload the FW.
2128 * FC FW may respond FAILED to an ABORT
2129 */
2130 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2131 if ((hd->cmdPtr) ||
2132 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2133 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2134 printk((KERN_WARNING
2135 " Firmware Reload FAILED!!\n"));
2136 }
2137 }
2138 }
2139 } else {
2140 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2141
2142 hd->abortSCpnt = NULL;
2143
2144 }
2145 }
2146
2147 spin_lock_irqsave(&ioc->FreeQlock, flags);
2148 hd->tmPending = 0;
2149 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2150 hd->tmState = TM_STATE_NONE;
2151
2152 return 1;
2153}
2154
2155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2156/*
2157 * This is anyones guess quite frankly.
2158 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002159int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2161 sector_t capacity, int geom[])
2162{
2163 int heads;
2164 int sectors;
2165 sector_t cylinders;
2166 ulong dummy;
2167
2168 heads = 64;
2169 sectors = 32;
2170
2171 dummy = heads * sectors;
2172 cylinders = capacity;
2173 sector_div(cylinders,dummy);
2174
2175 /*
2176 * Handle extended translation size for logical drives
2177 * > 1Gb
2178 */
2179 if ((ulong)capacity >= 0x200000) {
2180 heads = 255;
2181 sectors = 63;
2182 dummy = heads * sectors;
2183 cylinders = capacity;
2184 sector_div(cylinders,dummy);
2185 }
2186
2187 /* return result */
2188 geom[0] = heads;
2189 geom[1] = sectors;
2190 geom[2] = cylinders;
2191
2192 dprintk((KERN_NOTICE
2193 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2194 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2195
2196 return 0;
2197}
2198
Moore, Ericf44e5462006-03-14 09:14:21 -07002199/* Search IOC page 3 to determine if this is hidden physical disk
2200 *
2201 */
2202int
2203mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2204{
2205 int i;
2206
2207 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2208 return 0;
2209 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2210 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2211 return 1;
2212 }
2213 return 0;
2214}
2215EXPORT_SYMBOL(mptscsih_is_phys_disk);
2216
James Bottomleyc92f2222006-03-01 09:02:49 -06002217int
2218mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2219{
2220 int i;
2221
2222 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2223 return -ENXIO;
2224
2225 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2226 if (physdiskid ==
2227 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2228 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2229 }
2230
2231 return -ENXIO;
2232}
2233EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2234
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2236/*
2237 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002238 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002241int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002242mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002244 VirtTarget *vtarget;
2245
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002246 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002247 if (!vtarget)
2248 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002249 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002250 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002251 return 0;
2252}
2253
2254/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2255/*
2256 * OS entry point to allow host driver to alloc memory
2257 * for each scsi device. Called once per device the bus scan.
2258 * Return non-zero if allocation fails.
2259 */
2260int
2261mptscsih_slave_alloc(struct scsi_device *sdev)
2262{
2263 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002265 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002267 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002269 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if (!vdev) {
2271 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2272 hd->ioc->name, sizeof(VirtDevice));
2273 return -ENOMEM;
2274 }
2275
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002276 vdev->lun = sdev->lun;
2277 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002279 starget = scsi_target(sdev);
2280 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002281
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002282 vdev->vtarget = vtarget;
2283
2284 if (vtarget->num_luns == 0) {
2285 hd->Targets[sdev->id] = vtarget;
2286 vtarget->ioc_id = hd->ioc->id;
2287 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2288 vtarget->target_id = sdev->id;
2289 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002290 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2291 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2292 vtarget->raidVolume = 1;
2293 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002294 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002295 }
2296 }
2297 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 return 0;
2299}
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301/*
2302 * OS entry point to allow for host driver to free allocated memory
2303 * Called if no device present or device being unloaded
2304 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002305void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002306mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002308 if (starget->hostdata)
2309 kfree(starget->hostdata);
2310 starget->hostdata = NULL;
2311}
2312
2313/*
2314 * OS entry point to allow for host driver to free allocated memory
2315 * Called if no device present or device being unloaded
2316 */
2317void
2318mptscsih_slave_destroy(struct scsi_device *sdev)
2319{
2320 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322 VirtTarget *vtarget;
2323 VirtDevice *vdevice;
2324 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002326 starget = scsi_target(sdev);
2327 vtarget = starget->hostdata;
2328 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002330 mptscsih_search_running_cmds(hd, vdevice);
2331 vtarget->luns[0] &= ~(1 << vdevice->lun);
2332 vtarget->num_luns--;
2333 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002334 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002336 mptscsih_synchronize_cache(hd, vdevice);
2337 kfree(vdevice);
2338 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339}
2340
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002341/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2342/*
2343 * mptscsih_change_queue_depth - This function will set a devices queue depth
2344 * @sdev: per scsi_device pointer
2345 * @qdepth: requested queue depth
2346 *
2347 * Adding support for new 'change_queue_depth' api.
2348*/
2349int
2350mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002352 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2353 VirtTarget *vtarget;
2354 struct scsi_target *starget;
2355 int max_depth;
2356 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002358 starget = scsi_target(sdev);
2359 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002360
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002361 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002362 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002364 else if (sdev->type == TYPE_DISK &&
2365 vtarget->minSyncFactor <= MPT_ULTRA160)
2366 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2367 else
2368 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 } else
2370 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2371
2372 if (qdepth > max_depth)
2373 qdepth = max_depth;
2374 if (qdepth == 1)
2375 tagged = 0;
2376 else
2377 tagged = MSG_SIMPLE_TAG;
2378
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002379 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2380 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381}
2382
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383/*
2384 * OS entry point to adjust the queue_depths on a per-device basis.
2385 * Called once per device the bus scan. Use it to force the queue_depth
2386 * member to 1 if a device does not support Q tags.
2387 * Return non-zero if fails.
2388 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002389int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002390mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 struct Scsi_Host *sh = sdev->host;
2393 VirtTarget *vtarget;
2394 VirtDevice *vdevice;
2395 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002397 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002399 starget = scsi_target(sdev);
2400 vtarget = starget->hostdata;
2401 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 dsprintk((MYIOC_s_INFO_FMT
2404 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2406 if (hd->ioc->bus_type == SPI)
2407 dsprintk((MYIOC_s_INFO_FMT
2408 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2409 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2410 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002412 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002414 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 goto slave_configure_exit;
2416 }
2417
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 vdevice->configured_lun=1;
2419 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2420 indexed_lun = (vdevice->lun % 32);
2421 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002422 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002423 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 dsprintk((MYIOC_s_INFO_FMT
2426 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002427 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002429 if (hd->ioc->bus_type == SPI)
2430 dsprintk((MYIOC_s_INFO_FMT
2431 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2432 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2433 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435slave_configure_exit:
2436
2437 dsprintk((MYIOC_s_INFO_FMT
2438 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002439 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2440 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442 return 0;
2443}
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2446/*
2447 * Private routines...
2448 */
2449
2450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2451/* Utility function to copy sense data from the scsi_cmnd buffer
2452 * to the FC and SCSI target structures.
2453 *
2454 */
2455static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002456mptscsih_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 -07002457{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002458 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 SCSIIORequest_t *pReq;
2460 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462 /* Get target structure
2463 */
2464 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002465 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
2467 if (sense_count) {
2468 u8 *sense_data;
2469 int req_index;
2470
2471 /* Copy the sense received into the scsi command block. */
2472 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2473 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2474 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2475
2476 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2477 */
2478 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002479 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 int idx;
2481 MPT_ADAPTER *ioc = hd->ioc;
2482
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002483 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2485 ioc->events[idx].eventContext = ioc->eventContext;
2486
2487 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2488 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002489 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
2491 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2492
2493 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002494 if (hd->ioc->pcidev->vendor ==
2495 PCI_VENDOR_ID_IBM) {
2496 mptscsih_issue_sep_command(hd->ioc,
2497 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2498 vdev->vtarget->tflags |=
2499 MPT_TARGET_FLAGS_LED_ON;
2500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
2502 }
2503 } else {
2504 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2505 hd->ioc->name));
2506 }
2507}
2508
Eric Moore3dc0b032006-07-11 17:32:33 -06002509static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2511{
2512 MPT_SCSI_HOST *hd;
2513 int i;
2514
2515 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2516
2517 for (i = 0; i < hd->ioc->req_depth; i++) {
2518 if (hd->ScsiLookup[i] == sc) {
2519 return i;
2520 }
2521 }
2522
2523 return -1;
2524}
2525
2526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002527int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2529{
2530 MPT_SCSI_HOST *hd;
2531 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002532 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
2534 dtmprintk((KERN_WARNING MYNAM
2535 ": IOC %s_reset routed to SCSI host driver!\n",
2536 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2537 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2538
2539 /* If a FW reload request arrives after base installed but
2540 * before all scsi hosts have been attached, then an alt_ioc
2541 * may have a NULL sh pointer.
2542 */
2543 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2544 return 0;
2545 else
2546 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2547
2548 if (reset_phase == MPT_IOC_SETUP_RESET) {
2549 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2550
2551 /* Clean Up:
2552 * 1. Set Hard Reset Pending Flag
2553 * All new commands go to doneQ
2554 */
2555 hd->resetPending = 1;
2556
2557 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2558 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2559
2560 /* 2. Flush running commands
2561 * Clean ScsiLookup (and associated memory)
2562 * AND clean mytaskQ
2563 */
2564
2565 /* 2b. Reply to OS all known outstanding I/O commands.
2566 */
2567 mptscsih_flush_running_cmds(hd);
2568
2569 /* 2c. If there was an internal command that
2570 * has not completed, configuration or io request,
2571 * free these resources.
2572 */
2573 if (hd->cmdPtr) {
2574 del_timer(&hd->timer);
2575 mpt_free_msg_frame(ioc, hd->cmdPtr);
2576 }
2577
2578 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2579
2580 } else {
2581 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2582
2583 /* Once a FW reload begins, all new OS commands are
2584 * redirected to the doneQ w/ a reset status.
2585 * Init all control structures.
2586 */
2587
2588 /* ScsiLookup initialization
2589 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002590 for (ii=0; ii < hd->ioc->req_depth; ii++)
2591 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
2593 /* 2. Chain Buffer initialization
2594 */
2595
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002596 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
2599 /* 5. Enable new commands to be posted
2600 */
2601 spin_lock_irqsave(&ioc->FreeQlock, flags);
2602 hd->tmPending = 0;
2603 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2604 hd->resetPending = 0;
2605 hd->tmState = TM_STATE_NONE;
2606
2607 /* 6. If there was an internal command,
2608 * wake this process up.
2609 */
2610 if (hd->cmdPtr) {
2611 /*
2612 * Wake up the original calling thread
2613 */
2614 hd->pLocal = &hd->localReply;
2615 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002616 hd->scandv_wait_done = 1;
2617 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 hd->cmdPtr = NULL;
2619 }
2620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2622
2623 }
2624
2625 return 1; /* currently means nothing really */
2626}
2627
2628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002629int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2631{
2632 MPT_SCSI_HOST *hd;
2633 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2634
Moore, Eric3a892be2006-03-14 09:14:03 -07002635 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 ioc->name, event));
2637
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002638 if (ioc->sh == NULL ||
2639 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2640 return 1;
2641
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 switch (event) {
2643 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2644 /* FIXME! */
2645 break;
2646 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2647 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002648 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002649 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 break;
2651 case MPI_EVENT_LOGOUT: /* 09 */
2652 /* FIXME! */
2653 break;
2654
Michael Reed05e8ec12006-01-13 14:31:54 -06002655 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002656 break;
2657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 /*
2659 * CHECKME! Don't think we need to do
2660 * anything for these, but...
2661 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2663 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2664 /*
2665 * CHECKME! Falling thru...
2666 */
2667 break;
2668
2669 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002670 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 case MPI_EVENT_NONE: /* 00 */
2673 case MPI_EVENT_LOG_DATA: /* 01 */
2674 case MPI_EVENT_STATE_CHANGE: /* 02 */
2675 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2676 default:
2677 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2678 break;
2679 }
2680
2681 return 1; /* currently means nothing really */
2682}
2683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2685/*
2686 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2687 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002688 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002689 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 *
2691 * NOTE: It's only SAFE to call this routine if data points to
2692 * sane & valid STANDARD INQUIRY data!
2693 *
2694 * Allocate and initialize memory for this target.
2695 * Save inquiry data.
2696 *
2697 */
2698static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002699mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2700 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Eric Mooref99be432007-01-04 20:46:54 -07002703 hd->ioc->name, vtarget->bus_id, vtarget->target_id,
2704 sdev->lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /* Is LUN supported? If so, upper 2 bits will be 0
2707 * in first byte of inquiry data.
2708 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002709 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 return;
2711
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002712 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
James Bottomleyc92f2222006-03-01 09:02:49 -06002715 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002717 if (hd->ioc->bus_type != SPI)
2718 return;
2719
James Bottomleyc92f2222006-03-01 09:02:49 -06002720 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002721 /* Treat all Processors as SAF-TE if
2722 * command line option is set */
2723 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2724 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002725 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002726 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002727 if (sdev->inquiry_len > 49 ) {
2728 if (sdev->inquiry[44] == 'S' &&
2729 sdev->inquiry[45] == 'A' &&
2730 sdev->inquiry[46] == 'F' &&
2731 sdev->inquiry[47] == '-' &&
2732 sdev->inquiry[48] == 'T' &&
2733 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002734 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2735 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 }
2737 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002738 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002739 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740}
2741
2742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2743/*
2744 * Update the target negotiation parameters based on the
2745 * the Inquiry data, adapter capabilities, and NVRAM settings.
2746 *
2747 */
2748static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002749mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2750 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002752 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 int id = (int) target->target_id;
2754 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 u8 width = MPT_NARROW;
2756 u8 factor = MPT_ASYNC;
2757 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002758 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 u8 noQas = 1;
2760
2761 target->negoFlags = pspi_data->noQas;
2762
James Bottomleyc92f2222006-03-01 09:02:49 -06002763 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764
James Bottomleyc92f2222006-03-01 09:02:49 -06002765 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 width = 0;
2767 factor = MPT_ULTRA2;
2768 offset = pspi_data->maxSyncOffset;
2769 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2770 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002771 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 width = 1;
2773 }
2774
James Bottomleyc92f2222006-03-01 09:02:49 -06002775 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002777 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002779 else {
2780 if (!scsi_device_ius(sdev) &&
2781 !scsi_device_qas(sdev))
2782 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002784 factor = MPT_ULTRA320;
2785 if (scsi_device_qas(sdev)) {
Eric Mooref99be432007-01-04 20:46:54 -07002786 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
James Bottomleyc92f2222006-03-01 09:02:49 -06002787 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002789 if (sdev->type == TYPE_TAPE &&
2790 scsi_device_ius(sdev))
2791 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 offset = pspi_data->maxSyncOffset;
2795
2796 /* If RAID, never disable QAS
2797 * else if non RAID, do not disable
2798 * QAS if bit 1 is set
2799 * bit 1 QAS support, non-raid only
2800 * bit 0 IU support
2801 */
2802 if (target->raidVolume == 1) {
2803 noQas = 0;
2804 }
2805 } else {
2806 factor = MPT_ASYNC;
2807 offset = 0;
2808 }
2809 }
2810
James Bottomleyc92f2222006-03-01 09:02:49 -06002811 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2813 }
2814
2815 /* Update tflags based on NVRAM settings. (SCSI only)
2816 */
2817 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2818 nvram = pspi_data->nvram[id];
2819 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2820
2821 if (width)
2822 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2823
2824 if (offset > 0) {
2825 /* Ensure factor is set to the
2826 * maximum of: adapter, nvram, inquiry
2827 */
2828 if (nfactor) {
2829 if (nfactor < pspi_data->minSyncFactor )
2830 nfactor = pspi_data->minSyncFactor;
2831
2832 factor = max(factor, nfactor);
2833 if (factor == MPT_ASYNC)
2834 offset = 0;
2835 } else {
2836 offset = 0;
2837 factor = MPT_ASYNC;
2838 }
2839 } else {
2840 factor = MPT_ASYNC;
2841 }
2842 }
2843
2844 /* Make sure data is consistent
2845 */
2846 if ((!width) && (factor < MPT_ULTRA2)) {
2847 factor = MPT_ULTRA2;
2848 }
2849
2850 /* Save the data to the target structure.
2851 */
2852 target->minSyncFactor = factor;
2853 target->maxOffset = offset;
2854 target->maxWidth = width;
2855
2856 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2857
2858 /* Disable unused features.
2859 */
2860 if (!width)
2861 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2862
2863 if (!offset)
2864 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2865
2866 if ( factor > MPT_ULTRA320 )
2867 noQas = 0;
2868
James Bottomleyc92f2222006-03-01 09:02:49 -06002869 if (noQas && (pspi_data->noQas == 0)) {
2870 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2871 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872
James Bottomleyc92f2222006-03-01 09:02:49 -06002873 /* Disable QAS in a mixed configuration case
2874 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
James Bottomleyc92f2222006-03-01 09:02:49 -06002876 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 }
2878}
2879
2880/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881
2882/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2883/*
2884 * SCSI Config Page functionality ...
2885 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888/* mptscsih_writeIOCPage4 - write IOC Page 4
2889 * @hd: Pointer to a SCSI Host Structure
2890 * @target_id: write IOC Page4 for this ID & Bus
2891 *
2892 * Return: -EAGAIN if unable to obtain a Message Frame
2893 * or 0 if success.
2894 *
2895 * Remark: We do not wait for a return, write pages sequentially.
2896 */
2897static int
2898mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2899{
2900 MPT_ADAPTER *ioc = hd->ioc;
2901 Config_t *pReq;
2902 IOCPage4_t *IOCPage4Ptr;
2903 MPT_FRAME_HDR *mf;
2904 dma_addr_t dataDma;
2905 u16 req_idx;
2906 u32 frameOffset;
2907 u32 flagsLength;
2908 int ii;
2909
2910 /* Get a MF for this command.
2911 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002912 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002913 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 ioc->name));
2915 return -EAGAIN;
2916 }
2917
2918 /* Set the request and the data pointers.
2919 * Place data at end of MF.
2920 */
2921 pReq = (Config_t *)mf;
2922
2923 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2924 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2925
2926 /* Complete the request frame (same for all requests).
2927 */
2928 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2929 pReq->Reserved = 0;
2930 pReq->ChainOffset = 0;
2931 pReq->Function = MPI_FUNCTION_CONFIG;
2932 pReq->ExtPageLength = 0;
2933 pReq->ExtPageType = 0;
2934 pReq->MsgFlags = 0;
2935 for (ii=0; ii < 8; ii++) {
2936 pReq->Reserved2[ii] = 0;
2937 }
2938
2939 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2940 dataDma = ioc->spi_data.IocPg4_dma;
2941 ii = IOCPage4Ptr->ActiveSEP++;
2942 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2943 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2944 pReq->Header = IOCPage4Ptr->Header;
2945 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2946
2947 /* Add a SGE to the config request.
2948 */
2949 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2950 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2951
2952 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2953
2954 dinitprintk((MYIOC_s_INFO_FMT
2955 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2956 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2957
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002958 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 return 0;
2961}
2962
2963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2964/*
2965 * Bus Scan and Domain Validation functionality ...
2966 */
2967
2968/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2969/*
2970 * mptscsih_scandv_complete - Scan and DV callback routine registered
2971 * to Fustion MPT (base) driver.
2972 *
2973 * @ioc: Pointer to MPT_ADAPTER structure
2974 * @mf: Pointer to original MPT request frame
2975 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2976 *
2977 * This routine is called from mpt.c::mpt_interrupt() at the completion
2978 * of any SCSI IO request.
2979 * This routine is registered with the Fusion MPT (base) driver at driver
2980 * load/init time via the mpt_register() API call.
2981 *
2982 * Returns 1 indicating alloc'd request frame ptr should be freed.
2983 *
2984 * Remark: Sets a completion code and (possibly) saves sense data
2985 * in the IOC member localReply structure.
2986 * Used ONLY for DV and other internal commands.
2987 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002988int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2990{
2991 MPT_SCSI_HOST *hd;
2992 SCSIIORequest_t *pReq;
2993 int completionCode;
2994 u16 req_idx;
2995
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002996 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2997
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 if ((mf == NULL) ||
2999 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3000 printk(MYIOC_s_ERR_FMT
3001 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3002 ioc->name, mf?"BAD":"NULL", (void *) mf);
3003 goto wakeup;
3004 }
3005
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 del_timer(&hd->timer);
3007 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3008 hd->ScsiLookup[req_idx] = NULL;
3009 pReq = (SCSIIORequest_t *) mf;
3010
3011 if (mf != hd->cmdPtr) {
3012 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3013 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3014 }
3015 hd->cmdPtr = NULL;
3016
3017 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3018 hd->ioc->name, mf, mr, req_idx));
3019
3020 hd->pLocal = &hd->localReply;
3021 hd->pLocal->scsiStatus = 0;
3022
3023 /* If target struct exists, clear sense valid flag.
3024 */
3025 if (mr == NULL) {
3026 completionCode = MPT_SCANDV_GOOD;
3027 } else {
3028 SCSIIOReply_t *pReply;
3029 u16 status;
3030 u8 scsi_status;
3031
3032 pReply = (SCSIIOReply_t *) mr;
3033
3034 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3035 scsi_status = pReply->SCSIStatus;
3036
3037 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3038 status, pReply->SCSIState, scsi_status,
3039 le32_to_cpu(pReply->IOCLogInfo)));
3040
3041 switch(status) {
3042
3043 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3044 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3045 break;
3046
3047 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3048 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3049 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3050 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3051 completionCode = MPT_SCANDV_DID_RESET;
3052 break;
3053
3054 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3055 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3056 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3057 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3058 ConfigReply_t *pr = (ConfigReply_t *)mr;
3059 completionCode = MPT_SCANDV_GOOD;
3060 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3061 hd->pLocal->header.PageLength = pr->Header.PageLength;
3062 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3063 hd->pLocal->header.PageType = pr->Header.PageType;
3064
3065 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3066 /* If the RAID Volume request is successful,
3067 * return GOOD, else indicate that
3068 * some type of error occurred.
3069 */
3070 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003071 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 completionCode = MPT_SCANDV_GOOD;
3073 else
3074 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06003075 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076
3077 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3078 u8 *sense_data;
3079 int sz;
3080
3081 /* save sense data in global structure
3082 */
3083 completionCode = MPT_SCANDV_SENSE;
3084 hd->pLocal->scsiStatus = scsi_status;
3085 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3086 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3087
3088 sz = min_t(int, pReq->SenseBufferLength,
3089 SCSI_STD_SENSE_BYTES);
3090 memcpy(hd->pLocal->sense, sense_data, sz);
3091
3092 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3093 sense_data));
3094 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3095 if (pReq->CDB[0] == INQUIRY)
3096 completionCode = MPT_SCANDV_ISSUE_SENSE;
3097 else
3098 completionCode = MPT_SCANDV_DID_RESET;
3099 }
3100 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3101 completionCode = MPT_SCANDV_DID_RESET;
3102 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3103 completionCode = MPT_SCANDV_DID_RESET;
3104 else {
3105 completionCode = MPT_SCANDV_GOOD;
3106 hd->pLocal->scsiStatus = scsi_status;
3107 }
3108 break;
3109
3110 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3111 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3112 completionCode = MPT_SCANDV_DID_RESET;
3113 else
3114 completionCode = MPT_SCANDV_SOME_ERROR;
3115 break;
3116
3117 default:
3118 completionCode = MPT_SCANDV_SOME_ERROR;
3119 break;
3120
3121 } /* switch(status) */
3122
3123 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3124 completionCode));
3125 } /* end of address reply case */
3126
3127 hd->pLocal->completion = completionCode;
3128
3129 /* MF and RF are freed in mpt_interrupt
3130 */
3131wakeup:
3132 /* Free Chain buffers (will never chain) in scan or dv */
3133 //mptscsih_freeChainBuffers(ioc, req_idx);
3134
3135 /*
3136 * Wake up the original calling thread
3137 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003138 hd->scandv_wait_done = 1;
3139 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140
3141 return 1;
3142}
3143
3144/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3145/* mptscsih_timer_expired - Call back for timer process.
3146 * Used only for dv functionality.
3147 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3148 *
3149 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003150void
3151mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152{
3153 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3154
3155 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3156
3157 if (hd->cmdPtr) {
3158 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3159
3160 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3161 /* Desire to issue a task management request here.
3162 * TM requests MUST be single threaded.
3163 * If old eh code and no TM current, issue request.
3164 * If new eh code, do nothing. Wait for OS cmd timeout
3165 * for bus reset.
3166 */
3167 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3168 } else {
3169 /* Perform a FW reload */
3170 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3171 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3172 }
3173 }
3174 } else {
3175 /* This should NEVER happen */
3176 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3177 }
3178
3179 /* No more processing.
3180 * TM call will generate an interrupt for SCSI TM Management.
3181 * The FW will reply to all outstanding commands, callback will finish cleanup.
3182 * Hard reset clean-up will free all resources.
3183 */
3184 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3185
3186 return;
3187}
3188
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3191/**
3192 * mptscsih_do_cmd - Do internal command.
3193 * @hd: MPT_SCSI_HOST pointer
3194 * @io: INTERNAL_CMD pointer.
3195 *
3196 * Issue the specified internally generated command and do command
3197 * specific cleanup. For bus scan / DV only.
3198 * NOTES: If command is Inquiry and status is good,
3199 * initialize a target structure, save the data
3200 *
3201 * Remark: Single threaded access only.
3202 *
3203 * Return:
3204 * < 0 if an illegal command or no resources
3205 *
3206 * 0 if good
3207 *
3208 * > 0 if command complete but some type of completion error.
3209 */
3210static int
3211mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3212{
3213 MPT_FRAME_HDR *mf;
3214 SCSIIORequest_t *pScsiReq;
3215 SCSIIORequest_t ReqCopy;
3216 int my_idx, ii, dir;
3217 int rc, cmdTimeout;
3218 int in_isr;
3219 char cmdLen;
3220 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3221 char cmd = io->cmd;
3222
3223 in_isr = in_interrupt();
3224 if (in_isr) {
3225 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3226 hd->ioc->name));
3227 return -EPERM;
3228 }
3229
3230
3231 /* Set command specific information
3232 */
3233 switch (cmd) {
3234 case INQUIRY:
3235 cmdLen = 6;
3236 dir = MPI_SCSIIO_CONTROL_READ;
3237 CDB[0] = cmd;
3238 CDB[4] = io->size;
3239 cmdTimeout = 10;
3240 break;
3241
3242 case TEST_UNIT_READY:
3243 cmdLen = 6;
3244 dir = MPI_SCSIIO_CONTROL_READ;
3245 cmdTimeout = 10;
3246 break;
3247
3248 case START_STOP:
3249 cmdLen = 6;
3250 dir = MPI_SCSIIO_CONTROL_READ;
3251 CDB[0] = cmd;
3252 CDB[4] = 1; /*Spin up the disk */
3253 cmdTimeout = 15;
3254 break;
3255
3256 case REQUEST_SENSE:
3257 cmdLen = 6;
3258 CDB[0] = cmd;
3259 CDB[4] = io->size;
3260 dir = MPI_SCSIIO_CONTROL_READ;
3261 cmdTimeout = 10;
3262 break;
3263
3264 case READ_BUFFER:
3265 cmdLen = 10;
3266 dir = MPI_SCSIIO_CONTROL_READ;
3267 CDB[0] = cmd;
3268 if (io->flags & MPT_ICFLAG_ECHO) {
3269 CDB[1] = 0x0A;
3270 } else {
3271 CDB[1] = 0x02;
3272 }
3273
3274 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3275 CDB[1] |= 0x01;
3276 }
3277 CDB[6] = (io->size >> 16) & 0xFF;
3278 CDB[7] = (io->size >> 8) & 0xFF;
3279 CDB[8] = io->size & 0xFF;
3280 cmdTimeout = 10;
3281 break;
3282
3283 case WRITE_BUFFER:
3284 cmdLen = 10;
3285 dir = MPI_SCSIIO_CONTROL_WRITE;
3286 CDB[0] = cmd;
3287 if (io->flags & MPT_ICFLAG_ECHO) {
3288 CDB[1] = 0x0A;
3289 } else {
3290 CDB[1] = 0x02;
3291 }
3292 CDB[6] = (io->size >> 16) & 0xFF;
3293 CDB[7] = (io->size >> 8) & 0xFF;
3294 CDB[8] = io->size & 0xFF;
3295 cmdTimeout = 10;
3296 break;
3297
3298 case RESERVE:
3299 cmdLen = 6;
3300 dir = MPI_SCSIIO_CONTROL_READ;
3301 CDB[0] = cmd;
3302 cmdTimeout = 10;
3303 break;
3304
3305 case RELEASE:
3306 cmdLen = 6;
3307 dir = MPI_SCSIIO_CONTROL_READ;
3308 CDB[0] = cmd;
3309 cmdTimeout = 10;
3310 break;
3311
3312 case SYNCHRONIZE_CACHE:
3313 cmdLen = 10;
3314 dir = MPI_SCSIIO_CONTROL_READ;
3315 CDB[0] = cmd;
3316// CDB[1] = 0x02; /* set immediate bit */
3317 cmdTimeout = 10;
3318 break;
3319
3320 default:
3321 /* Error Case */
3322 return -EFAULT;
3323 }
3324
3325 /* Get and Populate a free Frame
3326 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003327 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3329 hd->ioc->name));
3330 return -EBUSY;
3331 }
3332
3333 pScsiReq = (SCSIIORequest_t *) mf;
3334
3335 /* Get the request index */
3336 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3337 ADD_INDEX_LOG(my_idx); /* for debug */
3338
3339 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3340 pScsiReq->TargetID = io->physDiskNum;
3341 pScsiReq->Bus = 0;
3342 pScsiReq->ChainOffset = 0;
3343 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3344 } else {
3345 pScsiReq->TargetID = io->id;
3346 pScsiReq->Bus = io->bus;
3347 pScsiReq->ChainOffset = 0;
3348 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3349 }
3350
3351 pScsiReq->CDBLength = cmdLen;
3352 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3353
3354 pScsiReq->Reserved = 0;
3355
3356 pScsiReq->MsgFlags = mpt_msg_flags();
3357 /* MsgContext set in mpt_get_msg_fram call */
3358
3359 for (ii=0; ii < 8; ii++)
3360 pScsiReq->LUN[ii] = 0;
3361 pScsiReq->LUN[1] = io->lun;
3362
3363 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3364 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3365 else
3366 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3367
3368 if (cmd == REQUEST_SENSE) {
3369 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3370 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3371 hd->ioc->name, cmd));
3372 }
3373
3374 for (ii=0; ii < 16; ii++)
3375 pScsiReq->CDB[ii] = CDB[ii];
3376
3377 pScsiReq->DataLength = cpu_to_le32(io->size);
3378 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3379 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3380
3381 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3382 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3383
3384 if (dir == MPI_SCSIIO_CONTROL_READ) {
3385 mpt_add_sge((char *) &pScsiReq->SGL,
3386 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3387 io->data_dma);
3388 } else {
3389 mpt_add_sge((char *) &pScsiReq->SGL,
3390 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3391 io->data_dma);
3392 }
3393
3394 /* The ISR will free the request frame, but we need
3395 * the information to initialize the target. Duplicate.
3396 */
3397 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3398
3399 /* Issue this command after:
3400 * finish init
3401 * add timer
3402 * Wait until the reply has been received
3403 * ScsiScanDvCtx callback function will
3404 * set hd->pLocal;
3405 * set scandv_wait_done and call wake_up
3406 */
3407 hd->pLocal = NULL;
3408 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003409 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410
3411 /* Save cmd pointer, for resource free if timeout or
3412 * FW reload occurs
3413 */
3414 hd->cmdPtr = mf;
3415
3416 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003417 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3418 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419
3420 if (hd->pLocal) {
3421 rc = hd->pLocal->completion;
3422 hd->pLocal->skip = 0;
3423
3424 /* Always set fatal error codes in some cases.
3425 */
3426 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3427 rc = -ENXIO;
3428 else if (rc == MPT_SCANDV_SOME_ERROR)
3429 rc = -rc;
3430 } else {
3431 rc = -EFAULT;
3432 /* This should never happen. */
3433 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3434 hd->ioc->name));
3435 }
3436
3437 return rc;
3438}
3439
3440/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3441/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003442 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3443 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003444 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003445 *
3446 * Uses the ISR, but with special processing.
3447 * MUST be single-threaded.
3448 *
3449 */
3450static void
3451mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3452{
3453 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
3455 /* Following parameters will not change
3456 * in this routine.
3457 */
3458 iocmd.cmd = SYNCHRONIZE_CACHE;
3459 iocmd.flags = 0;
3460 iocmd.physDiskNum = -1;
3461 iocmd.data = NULL;
3462 iocmd.data_dma = -1;
3463 iocmd.size = 0;
3464 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003465 iocmd.bus = vdevice->vtarget->bus_id;
3466 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003467 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468
James Bottomleyc92f2222006-03-01 09:02:49 -06003469 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003470 (vdevice->configured_lun))
3471 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472}
3473
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003474EXPORT_SYMBOL(mptscsih_remove);
3475EXPORT_SYMBOL(mptscsih_shutdown);
3476#ifdef CONFIG_PM
3477EXPORT_SYMBOL(mptscsih_suspend);
3478EXPORT_SYMBOL(mptscsih_resume);
3479#endif
3480EXPORT_SYMBOL(mptscsih_proc_info);
3481EXPORT_SYMBOL(mptscsih_info);
3482EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003483EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003484EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003485EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003486EXPORT_SYMBOL(mptscsih_slave_destroy);
3487EXPORT_SYMBOL(mptscsih_slave_configure);
3488EXPORT_SYMBOL(mptscsih_abort);
3489EXPORT_SYMBOL(mptscsih_dev_reset);
3490EXPORT_SYMBOL(mptscsih_bus_reset);
3491EXPORT_SYMBOL(mptscsih_host_reset);
3492EXPORT_SYMBOL(mptscsih_bios_param);
3493EXPORT_SYMBOL(mptscsih_io_done);
3494EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3495EXPORT_SYMBOL(mptscsih_scandv_complete);
3496EXPORT_SYMBOL(mptscsih_event_process);
3497EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003498EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003499EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003500EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/