blob: c8a9d8e8c5de627d370e3b311f20f8538747b398 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04006 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * (mailto:mpt_linux_developer@lsil.com)
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include "linux_compat.h" /* linux-2.6 tweaks */
48#include <linux/module.h>
49#include <linux/kernel.h>
50#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
57#include <linux/sched.h>
58#include <linux/workqueue.h>
59
60#include <scsi/scsi.h>
61#include <scsi/scsi_cmnd.h>
62#include <scsi/scsi_device.h>
63#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060065#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68#include "mptscsih.h"
69
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT SCSI Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptscsih"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
80
81typedef struct _BIG_SENSE_BUF {
82 u8 data[MPT_SENSE_BUFFER_ALLOC];
83} BIG_SENSE_BUF;
84
85#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
86#define MPT_SCANDV_DID_RESET (0x00000001)
87#define MPT_SCANDV_SENSE (0x00000002)
88#define MPT_SCANDV_SOME_ERROR (0x00000004)
89#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
90#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
91#define MPT_SCANDV_FALLBACK (0x00000020)
92
93#define MPT_SCANDV_MAX_RETRIES (10)
94
95#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
96#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
Moore, Eric Dean466544d2005-09-14 18:09:10 -060097#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
98#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
99#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
101#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
102
103typedef struct _internal_cmd {
104 char *data; /* data pointer */
105 dma_addr_t data_dma; /* data dma address */
106 int size; /* transfer size */
107 u8 cmd; /* SCSI Op Code */
108 u8 bus; /* bus number */
109 u8 id; /* SCSI ID (virtual) */
110 u8 lun;
111 u8 flags; /* Bit Field - See above */
112 u8 physDiskNum; /* Phys disk number, -1 else */
113 u8 rsvd2;
114 u8 rsvd;
115} INTERNAL_CMD;
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * Other private/forward protos...
119 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400120int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400122int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
125 SCSIIORequest_t *pReq, int req_idx);
126static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400127static 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 -0700128static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
129static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
130static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
133
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400134int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
135int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
James Bottomleyc92f2222006-03-01 09:02:49 -0600137static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
138static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400140int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700142static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400144void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700145void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400147int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
148int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149#endif
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
154/**
155 * mptscsih_add_sge - Place a simple SGE at address pAddr.
156 * @pAddr: virtual address for SGE
157 * @flagslength: SGE flags and data transfer length
158 * @dma_addr: Physical address
159 *
160 * This routine places a MPT request frame back on the MPT adapter's
161 * FreeQ.
162 */
163static inline void
164mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
165{
166 if (sizeof(dma_addr_t) == sizeof(u64)) {
167 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
168 u32 tmp = dma_addr & 0xFFFFFFFF;
169
170 pSge->FlagsLength = cpu_to_le32(flagslength);
171 pSge->Address.Low = cpu_to_le32(tmp);
172 tmp = (u32) ((u64)dma_addr >> 32);
173 pSge->Address.High = cpu_to_le32(tmp);
174
175 } else {
176 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
177 pSge->FlagsLength = cpu_to_le32(flagslength);
178 pSge->Address = cpu_to_le32(dma_addr);
179 }
180} /* mptscsih_add_sge() */
181
182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
183/**
184 * mptscsih_add_chain - Place a chain SGE at address pAddr.
185 * @pAddr: virtual address for SGE
186 * @next: nextChainOffset value (u32's)
187 * @length: length of next SGL segment
188 * @dma_addr: Physical address
189 *
190 * This routine places a MPT request frame back on the MPT adapter's
191 * FreeQ.
192 */
193static inline void
194mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
195{
196 if (sizeof(dma_addr_t) == sizeof(u64)) {
197 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
198 u32 tmp = dma_addr & 0xFFFFFFFF;
199
200 pChain->Length = cpu_to_le16(length);
201 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
202
203 pChain->NextChainOffset = next;
204
205 pChain->Address.Low = cpu_to_le32(tmp);
206 tmp = (u32) ((u64)dma_addr >> 32);
207 pChain->Address.High = cpu_to_le32(tmp);
208 } else {
209 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
210 pChain->Length = cpu_to_le16(length);
211 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
212 pChain->NextChainOffset = next;
213 pChain->Address = cpu_to_le32(dma_addr);
214 }
215} /* mptscsih_add_chain() */
216
217/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
218/*
219 * mptscsih_getFreeChainBuffer - Function to get a free chain
220 * from the MPT_SCSI_HOST FreeChainQ.
221 * @ioc: Pointer to MPT_ADAPTER structure
222 * @req_idx: Index of the SCSI IO request frame. (output)
223 *
224 * return SUCCESS or FAILED
225 */
226static inline int
227mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
228{
229 MPT_FRAME_HDR *chainBuf;
230 unsigned long flags;
231 int rc;
232 int chain_idx;
233
234 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
235 ioc->name));
236 spin_lock_irqsave(&ioc->FreeQlock, flags);
237 if (!list_empty(&ioc->FreeChainQ)) {
238 int offset;
239
240 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
241 u.frame.linkage.list);
242 list_del(&chainBuf->u.frame.linkage.list);
243 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
244 chain_idx = offset / ioc->req_sz;
245 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200246 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
247 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 } else {
249 rc = FAILED;
250 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200251 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 ioc->name));
253 }
254 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
255
256 *retIndex = chain_idx;
257 return rc;
258} /* mptscsih_getFreeChainBuffer() */
259
260/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
261/*
262 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
263 * SCSIIORequest_t Message Frame.
264 * @ioc: Pointer to MPT_ADAPTER structure
265 * @SCpnt: Pointer to scsi_cmnd structure
266 * @pReq: Pointer to SCSIIORequest_t structure
267 *
268 * Returns ...
269 */
270static int
271mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
272 SCSIIORequest_t *pReq, int req_idx)
273{
274 char *psge;
275 char *chainSge;
276 struct scatterlist *sg;
277 int frm_sz;
278 int sges_left, sg_done;
279 int chain_idx = MPT_HOST_NO_CHAIN;
280 int sgeOffset;
281 int numSgeSlots, numSgeThisFrame;
282 u32 sgflags, sgdir, thisxfer = 0;
283 int chain_dma_off = 0;
284 int newIndex;
285 int ii;
286 dma_addr_t v2;
287 u32 RequestNB;
288
289 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
290 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
291 sgdir = MPT_TRANSFER_HOST_TO_IOC;
292 } else {
293 sgdir = MPT_TRANSFER_IOC_TO_HOST;
294 }
295
296 psge = (char *) &pReq->SGL;
297 frm_sz = ioc->req_sz;
298
299 /* Map the data portion, if any.
300 * sges_left = 0 if no data transfer.
301 */
302 if ( (sges_left = SCpnt->use_sg) ) {
303 sges_left = pci_map_sg(ioc->pcidev,
304 (struct scatterlist *) SCpnt->request_buffer,
305 SCpnt->use_sg,
306 SCpnt->sc_data_direction);
307 if (sges_left == 0)
308 return FAILED;
309 } else if (SCpnt->request_bufflen) {
310 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
311 SCpnt->request_buffer,
312 SCpnt->request_bufflen,
313 SCpnt->sc_data_direction);
314 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
315 ioc->name, SCpnt, SCpnt->request_bufflen));
316 mptscsih_add_sge((char *) &pReq->SGL,
317 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
318 SCpnt->SCp.dma_handle);
319
320 return SUCCESS;
321 }
322
323 /* Handle the SG case.
324 */
325 sg = (struct scatterlist *) SCpnt->request_buffer;
326 sg_done = 0;
327 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
328 chainSge = NULL;
329
330 /* Prior to entering this loop - the following must be set
331 * current MF: sgeOffset (bytes)
332 * chainSge (Null if original MF is not a chain buffer)
333 * sg_done (num SGE done for this MF)
334 */
335
336nextSGEset:
337 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
338 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
339
340 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
341
342 /* Get first (num - 1) SG elements
343 * Skip any SG entries with a length of 0
344 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
345 */
346 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
347 thisxfer = sg_dma_len(sg);
348 if (thisxfer == 0) {
349 sg ++; /* Get next SG element from the OS */
350 sg_done++;
351 continue;
352 }
353
354 v2 = sg_dma_address(sg);
355 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
356
357 sg++; /* Get next SG element from the OS */
358 psge += (sizeof(u32) + sizeof(dma_addr_t));
359 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
360 sg_done++;
361 }
362
363 if (numSgeThisFrame == sges_left) {
364 /* Add last element, end of buffer and end of list flags.
365 */
366 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
367 MPT_SGE_FLAGS_END_OF_BUFFER |
368 MPT_SGE_FLAGS_END_OF_LIST;
369
370 /* Add last SGE and set termination flags.
371 * Note: Last SGE may have a length of 0 - which should be ok.
372 */
373 thisxfer = sg_dma_len(sg);
374
375 v2 = sg_dma_address(sg);
376 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
377 /*
378 sg++;
379 psge += (sizeof(u32) + sizeof(dma_addr_t));
380 */
381 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
382 sg_done++;
383
384 if (chainSge) {
385 /* The current buffer is a chain buffer,
386 * but there is not another one.
387 * Update the chain element
388 * Offset and Length fields.
389 */
390 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
391 } else {
392 /* The current buffer is the original MF
393 * and there is no Chain buffer.
394 */
395 pReq->ChainOffset = 0;
396 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200397 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
399 ioc->RequestNB[req_idx] = RequestNB;
400 }
401 } else {
402 /* At least one chain buffer is needed.
403 * Complete the first MF
404 * - last SGE element, set the LastElement bit
405 * - set ChainOffset (words) for orig MF
406 * (OR finish previous MF chain buffer)
407 * - update MFStructPtr ChainIndex
408 * - Populate chain element
409 * Also
410 * Loop until done.
411 */
412
413 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
414 ioc->name, sg_done));
415
416 /* Set LAST_ELEMENT flag for last non-chain element
417 * in the buffer. Since psge points at the NEXT
418 * SGE element, go back one SGE element, update the flags
419 * and reset the pointer. (Note: sgflags & thisxfer are already
420 * set properly).
421 */
422 if (sg_done) {
423 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
424 sgflags = le32_to_cpu(*ptmp);
425 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
426 *ptmp = cpu_to_le32(sgflags);
427 }
428
429 if (chainSge) {
430 /* The current buffer is a chain buffer.
431 * chainSge points to the previous Chain Element.
432 * Update its chain element Offset and Length (must
433 * include chain element size) fields.
434 * Old chain element is now complete.
435 */
436 u8 nextChain = (u8) (sgeOffset >> 2);
437 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
438 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
439 } else {
440 /* The original MF buffer requires a chain buffer -
441 * set the offset.
442 * Last element in this MF is a chain element.
443 */
444 pReq->ChainOffset = (u8) (sgeOffset >> 2);
445 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
446 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
447 ioc->RequestNB[req_idx] = RequestNB;
448 }
449
450 sges_left -= sg_done;
451
452
453 /* NOTE: psge points to the beginning of the chain element
454 * in current buffer. Get a chain buffer.
455 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200456 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
457 dfailprintk((MYIOC_s_INFO_FMT
458 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
459 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 /* Update the tracking arrays.
464 * If chainSge == NULL, update ReqToChain, else ChainToChain
465 */
466 if (chainSge) {
467 ioc->ChainToChain[chain_idx] = newIndex;
468 } else {
469 ioc->ReqToChain[req_idx] = newIndex;
470 }
471 chain_idx = newIndex;
472 chain_dma_off = ioc->req_sz * chain_idx;
473
474 /* Populate the chainSGE for the current buffer.
475 * - Set chain buffer pointer to psge and fill
476 * out the Address and Flags fields.
477 */
478 chainSge = (char *) psge;
479 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
480 psge, req_idx));
481
482 /* Start the SGE for the next buffer
483 */
484 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
485 sgeOffset = 0;
486 sg_done = 0;
487
488 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
489 psge, chain_idx));
490
491 /* Start the SGE for the next buffer
492 */
493
494 goto nextSGEset;
495 }
496
497 return SUCCESS;
498} /* mptscsih_AddSGE() */
499
Eric Moore786899b2006-07-11 17:22:22 -0600500static void
501mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
502 U32 SlotStatus)
503{
504 MPT_FRAME_HDR *mf;
505 SEPRequest_t *SEPMsg;
506
507 if (ioc->bus_type == FC)
508 return;
509
510 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
511 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
512 ioc->name,__FUNCTION__));
513 return;
514 }
515
516 SEPMsg = (SEPRequest_t *)mf;
517 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
518 SEPMsg->Bus = vtarget->bus_id;
519 SEPMsg->TargetID = vtarget->target_id;
520 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
521 SEPMsg->SlotStatus = SlotStatus;
522 devtverboseprintk((MYIOC_s_WARN_FMT
523 "Sending SEP cmd=%x id=%d bus=%d\n",
524 ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
525 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
526}
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
529/*
530 * mptscsih_io_done - Main SCSI IO callback routine registered to
531 * Fusion MPT (base) driver
532 * @ioc: Pointer to MPT_ADAPTER structure
533 * @mf: Pointer to original MPT request frame
534 * @r: Pointer to MPT reply frame (NULL if TurboReply)
535 *
536 * This routine is called from mpt.c::mpt_interrupt() at the completion
537 * of any SCSI IO request.
538 * This routine is registered with the Fusion MPT (base) driver at driver
539 * load/init time via the mpt_register() API call.
540 *
541 * Returns 1 indicating alloc'd request frame ptr should be freed.
542 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400543int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
545{
546 struct scsi_cmnd *sc;
547 MPT_SCSI_HOST *hd;
548 SCSIIORequest_t *pScsiReq;
549 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700550 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600551 VirtDevice *vdev;
552 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
555
556 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700557 req_idx_MR = (mr != NULL) ?
558 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
559 if ((req_idx != req_idx_MR) ||
560 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
561 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
562 ioc->name);
563 printk (MYIOC_s_ERR_FMT
564 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
565 ioc->name, req_idx, req_idx_MR, mf, mr,
566 hd->ScsiLookup[req_idx_MR]);
567 return 0;
568 }
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 sc = hd->ScsiLookup[req_idx];
571 if (sc == NULL) {
572 MPIHeader_t *hdr = (MPIHeader_t *)mf;
573
574 /* Remark: writeSDP1 will use the ScsiDoneCtx
575 * If a SCSI I/O cmd, device disabled by OS and
576 * completion done. Cannot touch sc struct. Just free mem.
577 */
578 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
579 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
580 ioc->name);
581
582 mptscsih_freeChainBuffers(ioc, req_idx);
583 return 1;
584 }
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 sc->result = DID_OK << 16; /* Set default reply as OK */
587 pScsiReq = (SCSIIORequest_t *) mf;
588 pScsiReply = (SCSIIOReply_t *) mr;
589
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200590 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
591 dmfprintk((MYIOC_s_INFO_FMT
592 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
593 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
594 }else{
595 dmfprintk((MYIOC_s_INFO_FMT
596 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
597 ioc->name, mf, mr, sc, req_idx));
598 }
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (pScsiReply == NULL) {
601 /* special context reply handling */
602 ;
603 } else {
604 u32 xfer_cnt;
605 u16 status;
606 u8 scsi_state, scsi_status;
607
608 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
609 scsi_state = pScsiReply->SCSIState;
610 scsi_status = pScsiReply->SCSIStatus;
611 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
612 sc->resid = sc->request_bufflen - xfer_cnt;
613
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600614 /*
615 * if we get a data underrun indication, yet no data was
616 * transferred and the SCSI status indicates that the
617 * command was never started, change the data underrun
618 * to success
619 */
620 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
621 (scsi_status == MPI_SCSI_STATUS_BUSY ||
622 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
623 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
624 status = MPI_IOCSTATUS_SUCCESS;
625 }
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
628 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
629 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700630 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600631 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 sc->request_bufflen, xfer_cnt));
633
634 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400635 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /*
638 * Look for + dump FCP ResponseInfo[]!
639 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600640 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
641 pScsiReply->ResponseInfo) {
642 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
643 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700644 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 le32_to_cpu(pScsiReply->ResponseInfo));
646 }
647
648 switch(status) {
649 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
650 /* CHECKME!
651 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
652 * But not: DID_BUS_BUSY lest one risk
653 * killing interrupt handler:-(
654 */
655 sc->result = SAM_STAT_BUSY;
656 break;
657
658 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
659 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
660 sc->result = DID_BAD_TARGET << 16;
661 break;
662
663 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
664 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600665 if (ioc->bus_type != FC)
666 sc->result = DID_NO_CONNECT << 16;
667 /* else fibre, just stall until rescan event */
668 else
669 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
672 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600673
674 vdev = sc->device->hostdata;
675 if (!vdev)
676 break;
677 vtarget = vdev->vtarget;
678 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
679 mptscsih_issue_sep_command(ioc, vtarget,
680 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
681 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 break;
684
685 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
686 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
687 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
688 /* Linux handles an unsolicited DID_RESET better
689 * than an unsolicited DID_ABORT.
690 */
691 sc->result = DID_RESET << 16;
692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 break;
694
695 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600696 sc->resid = sc->request_bufflen - xfer_cnt;
697 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
698 sc->result=DID_SOFT_ERROR << 16;
699 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600701 dreplyprintk((KERN_NOTICE
702 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
706 /*
707 * Do upfront check for valid SenseData and give it
708 * precedence!
709 */
710 sc->result = (DID_OK << 16) | scsi_status;
711 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
712 /* Have already saved the status and sense data
713 */
714 ;
715 } else {
716 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600717 if (scsi_status == SAM_STAT_BUSY)
718 sc->result = SAM_STAT_BUSY;
719 else
720 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
723 /* What to do?
724 */
725 sc->result = DID_SOFT_ERROR << 16;
726 }
727 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
728 /* Not real sure here either... */
729 sc->result = DID_RESET << 16;
730 }
731 }
732
733 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
734 sc->underflow));
735 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
736 /* Report Queue Full
737 */
738 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
739 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 break;
742
Moore, Eric7e551472006-01-16 18:53:21 -0700743 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
744 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
746 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600747 if (scsi_status == MPI_SCSI_STATUS_BUSY)
748 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
749 else
750 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (scsi_state == 0) {
752 ;
753 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
754 /*
755 * If running against circa 200003dd 909 MPT f/w,
756 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
757 * (QUEUE_FULL) returned from device! --> get 0x0000?128
758 * and with SenseBytes set to 0.
759 */
760 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
761 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
762
763 }
764 else if (scsi_state &
765 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
766 ) {
767 /*
768 * What to do?
769 */
770 sc->result = DID_SOFT_ERROR << 16;
771 }
772 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
773 /* Not real sure here either... */
774 sc->result = DID_RESET << 16;
775 }
776 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
777 /* Device Inq. data indicates that it supports
778 * QTags, but rejects QTag messages.
779 * This command completed OK.
780 *
781 * Not real sure here either so do nothing... */
782 }
783
784 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
785 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
786
787 /* Add handling of:
788 * Reservation Conflict, Busy,
789 * Command Terminated, CHECK
790 */
791 break;
792
793 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
794 sc->result = DID_SOFT_ERROR << 16;
795 break;
796
797 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
798 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
799 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
800 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
801 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
802 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
803 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
805 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
806 default:
807 /*
808 * What to do?
809 */
810 sc->result = DID_SOFT_ERROR << 16;
811 break;
812
813 } /* switch(status) */
814
815 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
816 } /* end of address reply case */
817
818 /* Unmap the DMA buffers, if any. */
819 if (sc->use_sg) {
820 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
821 sc->use_sg, sc->sc_data_direction);
822 } else if (sc->request_bufflen) {
823 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
824 sc->request_bufflen, sc->sc_data_direction);
825 }
826
827 hd->ScsiLookup[req_idx] = NULL;
828
829 sc->scsi_done(sc); /* Issue the command callback */
830
831 /* Free Chain buffers */
832 mptscsih_freeChainBuffers(ioc, req_idx);
833 return 1;
834}
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836/*
837 * mptscsih_flush_running_cmds - For each command found, search
838 * Scsi_Host instance taskQ and reply to OS.
839 * Called only if recovering from a FW reload.
840 * @hd: Pointer to a SCSI HOST structure
841 *
842 * Returns: None.
843 *
844 * Must be called while new I/Os are being queued.
845 */
846static void
847mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
848{
849 MPT_ADAPTER *ioc = hd->ioc;
850 struct scsi_cmnd *SCpnt;
851 MPT_FRAME_HDR *mf;
852 int ii;
853 int max = ioc->req_depth;
854
855 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
856 for (ii= 0; ii < max; ii++) {
857 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
858
859 /* Command found.
860 */
861
862 /* Null ScsiLookup index
863 */
864 hd->ScsiLookup[ii] = NULL;
865
866 mf = MPT_INDEX_2_MFPTR(ioc, ii);
867 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
868 mf, SCpnt));
869
870 /* Set status, free OS resources (SG DMA buffers)
871 * Do OS callback
872 * Free driver resources (chain, msg buffers)
873 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400874 if (SCpnt->use_sg) {
875 pci_unmap_sg(ioc->pcidev,
876 (struct scatterlist *) SCpnt->request_buffer,
877 SCpnt->use_sg,
878 SCpnt->sc_data_direction);
879 } else if (SCpnt->request_bufflen) {
880 pci_unmap_single(ioc->pcidev,
881 SCpnt->SCp.dma_handle,
882 SCpnt->request_bufflen,
883 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885 SCpnt->result = DID_RESET << 16;
886 SCpnt->host_scribble = NULL;
887
888 /* Free Chain buffers */
889 mptscsih_freeChainBuffers(ioc, ii);
890
891 /* Free Message frames */
892 mpt_free_msg_frame(ioc, mf);
893
894 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
895 }
896 }
897
898 return;
899}
900
901/*
902 * mptscsih_search_running_cmds - Delete any commands associated
903 * with the specified target and lun. Function called only
904 * when a lun is disable by mid-layer.
905 * Do NOT access the referenced scsi_cmnd structure or
906 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600907 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700908 * @hd: Pointer to a SCSI HOST structure
909 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 *
911 * Returns: None.
912 *
913 * Called from slave_destroy.
914 */
915static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700916mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917{
918 SCSIIORequest_t *mf = NULL;
919 int ii;
920 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600921 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Ericbd23e942006-04-17 12:43:04 -0600924 vdevice->vtarget->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600927 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
930
931 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
932 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
933
Moore, Eric914c2d82006-03-14 09:19:36 -0700934 if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 continue;
936
937 /* Cleanup
938 */
939 hd->ScsiLookup[ii] = NULL;
940 mptscsih_freeChainBuffers(hd->ioc, ii);
941 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600942 if (sc->use_sg) {
943 pci_unmap_sg(hd->ioc->pcidev,
944 (struct scatterlist *) sc->request_buffer,
945 sc->use_sg,
946 sc->sc_data_direction);
947 } else if (sc->request_bufflen) {
948 pci_unmap_single(hd->ioc->pcidev,
949 sc->SCp.dma_handle,
950 sc->request_bufflen,
951 sc->sc_data_direction);
952 }
953 sc->host_scribble = NULL;
954 sc->result = DID_NO_CONNECT << 16;
955 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 return;
959}
960
961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
964/*
965 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
966 * from a SCSI target device.
967 * @sc: Pointer to scsi_cmnd structure
968 * @pScsiReply: Pointer to SCSIIOReply_t
969 * @pScsiReq: Pointer to original SCSI request
970 *
971 * This routine periodically reports QUEUE_FULL status returned from a
972 * SCSI target device. It reports this to the console via kernel
973 * printk() API call, not more than once every 10 seconds.
974 */
975static void
976mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
977{
978 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400981 if (sc->device == NULL)
982 return;
983 if (sc->device->host == NULL)
984 return;
985 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
986 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400988 if (time - hd->last_queue_full > 10 * HZ) {
989 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
990 hd->ioc->name, 0, sc->device->id, sc->device->lun));
991 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
996/*
997 * mptscsih_remove - Removed scsi devices
998 * @pdev: Pointer to pci_dev structure
999 *
1000 *
1001 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001002void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003mptscsih_remove(struct pci_dev *pdev)
1004{
1005 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1006 struct Scsi_Host *host = ioc->sh;
1007 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001008 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001010 if(!host) {
1011 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 scsi_remove_host(host);
1016
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001017 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1018 return;
1019
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001020 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001022 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001024 if (hd->ScsiLookup != NULL) {
1025 sz1 = hd->ioc->req_depth * sizeof(void *);
1026 kfree(hd->ScsiLookup);
1027 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 }
1029
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001030 /*
1031 * Free pointer array.
1032 */
1033 kfree(hd->Targets);
1034 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001036 dprintk((MYIOC_s_INFO_FMT
1037 "Free'd ScsiLookup (%d) memory\n",
1038 hd->ioc->name, sz1));
1039
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001040 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001041
1042 /* NULL the Scsi_Host pointer
1043 */
1044 hd->ioc->sh = NULL;
1045
1046 scsi_host_put(host);
1047
1048 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050}
1051
1052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1053/*
1054 * mptscsih_shutdown - reboot notifier
1055 *
1056 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001057void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001058mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001060 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 struct Scsi_Host *host = ioc->sh;
1062 MPT_SCSI_HOST *hd;
1063
1064 if(!host)
1065 return;
1066
1067 hd = (MPT_SCSI_HOST *)host->hostdata;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
1071#ifdef CONFIG_PM
1072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1073/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001074 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 *
1076 *
1077 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001078int
Pavel Machek8d189f72005-04-16 15:25:28 -07001079mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001081 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001082 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083}
1084
1085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1086/*
1087 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1088 *
1089 *
1090 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001091int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092mptscsih_resume(struct pci_dev *pdev)
1093{
1094 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1095 struct Scsi_Host *host = ioc->sh;
1096 MPT_SCSI_HOST *hd;
1097
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001098 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 if(!host)
1101 return 0;
1102
1103 hd = (MPT_SCSI_HOST *)host->hostdata;
1104 if(!hd)
1105 return 0;
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return 0;
1108}
1109
1110#endif
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1113/**
1114 * mptscsih_info - Return information about MPT adapter
1115 * @SChost: Pointer to Scsi_Host structure
1116 *
1117 * (linux scsi_host_template.info routine)
1118 *
1119 * Returns pointer to buffer where information was written.
1120 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001121const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122mptscsih_info(struct Scsi_Host *SChost)
1123{
1124 MPT_SCSI_HOST *h;
1125 int size = 0;
1126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001130 if (h->info_kbuf == NULL)
1131 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1132 return h->info_kbuf;
1133 h->info_kbuf[0] = '\0';
1134
1135 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1136 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001139 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140}
1141
1142struct info_str {
1143 char *buffer;
1144 int length;
1145 int offset;
1146 int pos;
1147};
1148
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001149static void
1150mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
1152 if (info->pos + len > info->length)
1153 len = info->length - info->pos;
1154
1155 if (info->pos + len < info->offset) {
1156 info->pos += len;
1157 return;
1158 }
1159
1160 if (info->pos < info->offset) {
1161 data += (info->offset - info->pos);
1162 len -= (info->offset - info->pos);
1163 }
1164
1165 if (len > 0) {
1166 memcpy(info->buffer + info->pos, data, len);
1167 info->pos += len;
1168 }
1169}
1170
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001171static int
1172mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
1174 va_list args;
1175 char buf[81];
1176 int len;
1177
1178 va_start(args, fmt);
1179 len = vsprintf(buf, fmt, args);
1180 va_end(args);
1181
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001182 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return len;
1184}
1185
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001186static int
1187mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
1189 struct info_str info;
1190
1191 info.buffer = pbuf;
1192 info.length = len;
1193 info.offset = offset;
1194 info.pos = 0;
1195
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1197 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1198 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1199 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1202}
1203
1204/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1205/**
1206 * mptscsih_proc_info - Return information about MPT adapter
1207 *
1208 * (linux scsi_host_template.info routine)
1209 *
1210 * buffer: if write, user data; if read, buffer for user
1211 * length: if write, return length;
1212 * offset: if write, 0; if read, the current offset into the buffer from
1213 * the previous read.
1214 * hostno: scsi host number
1215 * func: if write = 1; if read = 0
1216 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001217int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1219 int length, int func)
1220{
1221 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1222 MPT_ADAPTER *ioc = hd->ioc;
1223 int size = 0;
1224
1225 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001226 /*
1227 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 */
1229 } else {
1230 if (start)
1231 *start = buffer;
1232
1233 size = mptscsih_host_info(ioc, buffer, offset, length);
1234 }
1235
1236 return size;
1237}
1238
1239/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1240#define ADD_INDEX_LOG(req_ent) do { } while(0)
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1245 * @SCpnt: Pointer to scsi_cmnd structure
1246 * @done: Pointer SCSI mid-layer IO completion function
1247 *
1248 * (linux scsi_host_template.queuecommand routine)
1249 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1250 * from a linux scsi_cmnd request and send it to the IOC.
1251 *
1252 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1253 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001254int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1256{
1257 MPT_SCSI_HOST *hd;
1258 MPT_FRAME_HDR *mf;
1259 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001260 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 int lun;
1262 u32 datalen;
1263 u32 scsictl;
1264 u32 scsidir;
1265 u32 cmd_len;
1266 int my_idx;
1267 int ii;
1268
1269 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 lun = SCpnt->device->lun;
1271 SCpnt->scsi_done = done;
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1274 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1275
1276 if (hd->resetPending) {
1277 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1278 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1279 return SCSI_MLQUEUE_HOST_BUSY;
1280 }
1281
Moore, Ericf44e5462006-03-14 09:14:21 -07001282 if ((hd->ioc->bus_type == SPI) &&
1283 vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001284 mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
1285 SCpnt->result = DID_NO_CONNECT << 16;
1286 done(SCpnt);
1287 return 0;
1288 }
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 /*
1291 * Put together a MPT SCSI request...
1292 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001293 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1295 hd->ioc->name));
1296 return SCSI_MLQUEUE_HOST_BUSY;
1297 }
1298
1299 pScsiReq = (SCSIIORequest_t *) mf;
1300
1301 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1302
1303 ADD_INDEX_LOG(my_idx);
1304
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001305 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 * Seems we may receive a buffer (datalen>0) even when there
1307 * will be no data transfer! GRRRRR...
1308 */
1309 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1310 datalen = SCpnt->request_bufflen;
1311 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1312 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1313 datalen = SCpnt->request_bufflen;
1314 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1315 } else {
1316 datalen = 0;
1317 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1318 }
1319
1320 /* Default to untagged. Once a target structure has been allocated,
1321 * use the Inquiry data to determine if device supports tagged.
1322 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001323 if (vdev
1324 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 && (SCpnt->device->tagged_supported)) {
1326 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1327 } else {
1328 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1329 }
1330
1331 /* Use the above information to set up the message frame
1332 */
Moore, Eric914c2d82006-03-14 09:19:36 -07001333 pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
1334 pScsiReq->Bus = vdev->vtarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001336 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1337 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1338 else
1339 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pScsiReq->CDBLength = SCpnt->cmd_len;
1341 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1342 pScsiReq->Reserved = 0;
1343 pScsiReq->MsgFlags = mpt_msg_flags();
1344 pScsiReq->LUN[0] = 0;
1345 pScsiReq->LUN[1] = lun;
1346 pScsiReq->LUN[2] = 0;
1347 pScsiReq->LUN[3] = 0;
1348 pScsiReq->LUN[4] = 0;
1349 pScsiReq->LUN[5] = 0;
1350 pScsiReq->LUN[6] = 0;
1351 pScsiReq->LUN[7] = 0;
1352 pScsiReq->Control = cpu_to_le32(scsictl);
1353
1354 /*
1355 * Write SCSI CDB into the message
1356 */
1357 cmd_len = SCpnt->cmd_len;
1358 for (ii=0; ii < cmd_len; ii++)
1359 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1360
1361 for (ii=cmd_len; ii < 16; ii++)
1362 pScsiReq->CDB[ii] = 0;
1363
1364 /* DataLength */
1365 pScsiReq->DataLength = cpu_to_le32(datalen);
1366
1367 /* SenseBuffer low address */
1368 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1369 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1370
1371 /* Now add the SG list
1372 * Always have a SGE even if null length.
1373 */
1374 if (datalen == 0) {
1375 /* Add a NULL SGE */
1376 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1377 (dma_addr_t) -1);
1378 } else {
1379 /* Add a 32 or 64 bit SGE */
1380 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1381 goto fail;
1382 }
1383
1384 hd->ScsiLookup[my_idx] = SCpnt;
1385 SCpnt->host_scribble = NULL;
1386
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001387 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1389 hd->ioc->name, SCpnt, mf, my_idx));
1390 DBG_DUMP_REQUEST_FRAME(mf)
1391 return 0;
1392
1393 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001394 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1396 mpt_free_msg_frame(hd->ioc, mf);
1397 return SCSI_MLQUEUE_HOST_BUSY;
1398}
1399
1400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1401/*
1402 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1403 * with a SCSI IO request
1404 * @hd: Pointer to the MPT_SCSI_HOST instance
1405 * @req_idx: Index of the SCSI IO request frame.
1406 *
1407 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1408 * No return.
1409 */
1410static void
1411mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1412{
1413 MPT_FRAME_HDR *chain;
1414 unsigned long flags;
1415 int chain_idx;
1416 int next;
1417
1418 /* Get the first chain index and reset
1419 * tracker state.
1420 */
1421 chain_idx = ioc->ReqToChain[req_idx];
1422 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1423
1424 while (chain_idx != MPT_HOST_NO_CHAIN) {
1425
1426 /* Save the next chain buffer index */
1427 next = ioc->ChainToChain[chain_idx];
1428
1429 /* Free this chain buffer and reset
1430 * tracker
1431 */
1432 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1433
1434 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1435 + (chain_idx * ioc->req_sz));
1436
1437 spin_lock_irqsave(&ioc->FreeQlock, flags);
1438 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1439 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1440
1441 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1442 ioc->name, chain_idx));
1443
1444 /* handle next */
1445 chain_idx = next;
1446 }
1447 return;
1448}
1449
1450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1451/*
1452 * Reset Handling
1453 */
1454
1455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1456/*
1457 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1458 * Fall through to mpt_HardResetHandler if: not operational, too many
1459 * failed TM requests or handshake failure.
1460 *
1461 * @ioc: Pointer to MPT_ADAPTER structure
1462 * @type: Task Management type
1463 * @target: Logical Target ID for reset (if appropriate)
1464 * @lun: Logical Unit for reset (if appropriate)
1465 * @ctx2abort: Context for the task to be aborted (if appropriate)
1466 *
1467 * Remark: Currently invoked from a non-interrupt thread (_bh).
1468 *
1469 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1470 * will be active.
1471 *
1472 * Returns 0 for SUCCESS or -1 if FAILED.
1473 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001474int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1476{
1477 MPT_ADAPTER *ioc;
1478 int rc = -1;
1479 int doTask = 1;
1480 u32 ioc_raw_state;
1481 unsigned long flags;
1482
1483 /* If FW is being reloaded currently, return success to
1484 * the calling function.
1485 */
1486 if (hd == NULL)
1487 return 0;
1488
1489 ioc = hd->ioc;
1490 if (ioc == NULL) {
1491 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1492 return FAILED;
1493 }
1494 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1495
1496 // SJR - CHECKME - Can we avoid this here?
1497 // (mpt_HardResetHandler has this check...)
1498 spin_lock_irqsave(&ioc->diagLock, flags);
1499 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1500 spin_unlock_irqrestore(&ioc->diagLock, flags);
1501 return FAILED;
1502 }
1503 spin_unlock_irqrestore(&ioc->diagLock, flags);
1504
1505 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1506 * If we time out and not bus reset, then we return a FAILED status to the caller.
1507 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1508 * successful. Otherwise, reload the FW.
1509 */
1510 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1511 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001512 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 "Timed out waiting for last TM (%d) to complete! \n",
1514 hd->ioc->name, hd->tmPending));
1515 return FAILED;
1516 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001517 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 "Timed out waiting for last TM (%d) to complete! \n",
1519 hd->ioc->name, hd->tmPending));
1520 return FAILED;
1521 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001522 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 "Timed out waiting for last TM (%d) to complete! \n",
1524 hd->ioc->name, hd->tmPending));
1525 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1526 return FAILED;
1527
1528 doTask = 0;
1529 }
1530 } else {
1531 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1532 hd->tmPending |= (1 << type);
1533 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1534 }
1535
1536 /* Is operational?
1537 */
1538 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1539
1540#ifdef MPT_DEBUG_RESET
1541 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1542 printk(MYIOC_s_WARN_FMT
1543 "TM Handler: IOC Not operational(0x%x)!\n",
1544 hd->ioc->name, ioc_raw_state);
1545 }
1546#endif
1547
1548 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1549 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1550
1551 /* Isse the Task Mgmt request.
1552 */
1553 if (hd->hard_resets < -1)
1554 hd->hard_resets++;
1555 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1556 if (rc) {
1557 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1558 } else {
1559 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1560 }
1561 }
1562
1563 /* Only fall through to the HRH if this is a bus reset
1564 */
1565 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1566 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1567 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1568 hd->ioc->name));
1569 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1570 }
1571
1572 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1573
1574 return rc;
1575}
1576
1577
1578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1579/*
1580 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1581 * @hd: Pointer to MPT_SCSI_HOST structure
1582 * @type: Task Management type
1583 * @target: Logical Target ID for reset (if appropriate)
1584 * @lun: Logical Unit for reset (if appropriate)
1585 * @ctx2abort: Context for the task to be aborted (if appropriate)
1586 *
1587 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1588 * or a non-interrupt thread. In the former, must not call schedule().
1589 *
1590 * Not all fields are meaningfull for all task types.
1591 *
1592 * Returns 0 for SUCCESS, -999 for "no msg frames",
1593 * else other non-zero value returned.
1594 */
1595static int
1596mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1597{
1598 MPT_FRAME_HDR *mf;
1599 SCSITaskMgmt_t *pScsiTm;
1600 int ii;
1601 int retval;
1602
1603 /* Return Fail to calling function if no message frames available.
1604 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001605 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1607 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001608 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 }
1610 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1611 hd->ioc->name, mf));
1612
1613 /* Format the Request
1614 */
1615 pScsiTm = (SCSITaskMgmt_t *) mf;
1616 pScsiTm->TargetID = target;
1617 pScsiTm->Bus = channel;
1618 pScsiTm->ChainOffset = 0;
1619 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1620
1621 pScsiTm->Reserved = 0;
1622 pScsiTm->TaskType = type;
1623 pScsiTm->Reserved1 = 0;
1624 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1625 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1626
1627 for (ii= 0; ii < 8; ii++) {
1628 pScsiTm->LUN[ii] = 0;
1629 }
1630 pScsiTm->LUN[1] = lun;
1631
1632 for (ii=0; ii < 7; ii++)
1633 pScsiTm->Reserved2[ii] = 0;
1634
1635 pScsiTm->TaskMsgContext = ctx2abort;
1636
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001637 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1638 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1641
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001642 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1644 CAN_SLEEP)) != 0) {
1645 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1646 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1647 hd->ioc, mf));
1648 mpt_free_msg_frame(hd->ioc, mf);
1649 return retval;
1650 }
1651
1652 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1653 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1654 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1655 hd->ioc, mf));
1656 mpt_free_msg_frame(hd->ioc, mf);
1657 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1658 hd->ioc->name));
1659 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1660 }
1661
1662 return retval;
1663}
1664
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001665static int
1666mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1667{
1668 switch (ioc->bus_type) {
1669 case FC:
1670 return 40;
1671 case SAS:
1672 return 10;
1673 case SPI:
1674 default:
1675 return 2;
1676 }
1677}
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1680/**
1681 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1682 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1683 *
1684 * (linux scsi_host_template.eh_abort_handler routine)
1685 *
1686 * Returns SUCCESS or FAILED.
1687 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001688int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689mptscsih_abort(struct scsi_cmnd * SCpnt)
1690{
1691 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 MPT_FRAME_HDR *mf;
1693 u32 ctx2abort;
1694 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001695 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001696 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
1698 /* If we can't locate our host adapter structure, return FAILED status.
1699 */
1700 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1701 SCpnt->result = DID_RESET << 16;
1702 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001703 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 "Can't locate host! (sc=%p)\n",
1705 SCpnt));
1706 return FAILED;
1707 }
1708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 /* Find this command
1710 */
1711 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001712 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 * Do OS callback.
1714 */
1715 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001716 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 "Command not in the active list! (sc=%p)\n",
1718 hd->ioc->name, SCpnt));
1719 return SUCCESS;
1720 }
1721
Moore, Eric65207fe2006-04-21 16:14:35 -06001722 if (hd->resetPending) {
1723 return FAILED;
1724 }
1725
1726 if (hd->timeouts < -1)
1727 hd->timeouts++;
1728
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001729 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1730 hd->ioc->name, SCpnt);
1731 scsi_print_command(SCpnt);
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1734 * (the IO to be ABORT'd)
1735 *
1736 * NOTE: Since we do not byteswap MsgContext, we do not
1737 * swap it here either. It is an opaque cookie to
1738 * the controller, so it does not matter. -DaveM
1739 */
1740 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1741 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1742
1743 hd->abortSCpnt = SCpnt;
1744
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001745 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001746 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric914c2d82006-03-14 09:19:36 -07001747 vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001748 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001750 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1751 hd->ioc->name,
1752 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001754 if (retval == 0)
1755 return SUCCESS;
1756
1757 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 hd->tmPending = 0;
1759 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001761 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762}
1763
1764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1765/**
1766 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1767 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1768 *
1769 * (linux scsi_host_template.eh_dev_reset_handler routine)
1770 *
1771 * Returns SUCCESS or FAILED.
1772 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001773int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1775{
1776 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001777 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001778 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
1780 /* If we can't locate our host adapter structure, return FAILED status.
1781 */
1782 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 "Can't locate host! (sc=%p)\n",
1785 SCpnt));
1786 return FAILED;
1787 }
1788
1789 if (hd->resetPending)
1790 return FAILED;
1791
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001792 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001794 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001796 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001797 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -07001798 vdev->vtarget->bus_id, vdev->vtarget->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001799 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800
1801 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1802 hd->ioc->name,
1803 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1804
1805 if (retval == 0)
1806 return SUCCESS;
1807
1808 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 hd->tmPending = 0;
1810 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001812 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813}
1814
1815/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1816/**
1817 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1818 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1819 *
1820 * (linux scsi_host_template.eh_bus_reset_handler routine)
1821 *
1822 * Returns SUCCESS or FAILED.
1823 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001824int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1826{
1827 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001828 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001829 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 /* If we can't locate our host adapter structure, return FAILED status.
1832 */
1833 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001834 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 "Can't locate host! (sc=%p)\n",
1836 SCpnt ) );
1837 return FAILED;
1838 }
1839
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001840 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 if (hd->timeouts < -1)
1845 hd->timeouts++;
1846
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001847 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001848 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric914c2d82006-03-14 09:19:36 -07001849 vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001851 printk (KERN_WARNING MYNAM ": %s: bus 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_host_reset - Perform a SCSI host adapter RESET!
1868 * new_eh variant
1869 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1870 *
1871 * (linux scsi_host_template.eh_host_reset_handler routine)
1872 *
1873 * Returns SUCCESS or FAILED.
1874 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001875int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1877{
1878 MPT_SCSI_HOST * hd;
1879 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
1881 /* If we can't locate the host to reset, then we failed. */
1882 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001883 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 "Can't locate host! (sc=%p)\n",
1885 SCpnt ) );
1886 return FAILED;
1887 }
1888
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001889 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 hd->ioc->name, SCpnt);
1891
1892 /* If our attempts to reset the host failed, then return a failed
1893 * status. The host will be taken off line by the SCSI mid-layer.
1894 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1896 status = FAILED;
1897 } else {
1898 /* Make sure TM pending is cleared and TM state is set to
1899 * NONE.
1900 */
1901 hd->tmPending = 0;
1902 hd->tmState = TM_STATE_NONE;
1903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001905 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 "Status = %s\n",
1907 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1908
1909 return status;
1910}
1911
1912/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1913/**
1914 * mptscsih_tm_pending_wait - wait for pending task management request to
1915 * complete.
1916 * @hd: Pointer to MPT host structure.
1917 *
1918 * Returns {SUCCESS,FAILED}.
1919 */
1920static int
1921mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1922{
1923 unsigned long flags;
1924 int loop_count = 4 * 10; /* Wait 10 seconds */
1925 int status = FAILED;
1926
1927 do {
1928 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1929 if (hd->tmState == TM_STATE_NONE) {
1930 hd->tmState = TM_STATE_IN_PROGRESS;
1931 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001933 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 break;
1935 }
1936 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1937 msleep(250);
1938 } while (--loop_count);
1939
1940 return status;
1941}
1942
1943/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1944/**
1945 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1946 * @hd: Pointer to MPT host structure.
1947 *
1948 * Returns {SUCCESS,FAILED}.
1949 */
1950static int
1951mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1952{
1953 unsigned long flags;
1954 int loop_count = 4 * timeout;
1955 int status = FAILED;
1956
1957 do {
1958 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1959 if(hd->tmPending == 0) {
1960 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001961 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 break;
1963 }
1964 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05001965 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 } while (--loop_count);
1967
1968 return status;
1969}
1970
1971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07001972static void
1973mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1974{
1975 char *desc;
1976
1977 switch (response_code) {
1978 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1979 desc = "The task completed.";
1980 break;
1981 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1982 desc = "The IOC received an invalid frame status.";
1983 break;
1984 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1985 desc = "The task type is not supported.";
1986 break;
1987 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1988 desc = "The requested task failed.";
1989 break;
1990 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1991 desc = "The task completed successfully.";
1992 break;
1993 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1994 desc = "The LUN request is invalid.";
1995 break;
1996 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1997 desc = "The task is in the IOC queue and has not been sent to target.";
1998 break;
1999 default:
2000 desc = "unknown";
2001 break;
2002 }
2003 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2004 ioc->name, response_code, desc);
2005}
2006
2007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008/**
2009 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2010 * @ioc: Pointer to MPT_ADAPTER structure
2011 * @mf: Pointer to SCSI task mgmt request frame
2012 * @mr: Pointer to SCSI task mgmt reply frame
2013 *
2014 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2015 * of any SCSI task management request.
2016 * This routine is registered with the MPT (base) driver at driver
2017 * load/init time via the mpt_register() API call.
2018 *
2019 * Returns 1 indicating alloc'd request frame ptr should be freed.
2020 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002021int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2023{
2024 SCSITaskMgmtReply_t *pScsiTmReply;
2025 SCSITaskMgmt_t *pScsiTmReq;
2026 MPT_SCSI_HOST *hd;
2027 unsigned long flags;
2028 u16 iocstatus;
2029 u8 tmType;
2030
2031 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2032 ioc->name, mf, mr));
2033 if (ioc->sh) {
2034 /* Depending on the thread, a timer is activated for
2035 * the TM request. Delete this timer on completion of TM.
2036 * Decrement count of outstanding TM requests.
2037 */
2038 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2039 } else {
2040 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2041 ioc->name));
2042 return 1;
2043 }
2044
2045 if (mr == NULL) {
2046 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2047 ioc->name, mf));
2048 return 1;
2049 } else {
2050 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2051 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2052
2053 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2054 tmType = pScsiTmReq->TaskType;
2055
Moore, Eric9f63bb72006-01-16 18:53:26 -07002056 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2057 pScsiTmReply->ResponseCode)
2058 mptscsih_taskmgmt_response_code(ioc,
2059 pScsiTmReply->ResponseCode);
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2062 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2063 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2064
2065 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2066 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2067 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2068 /* Error? (anything non-zero?) */
2069 if (iocstatus) {
2070
2071 /* clear flags and continue.
2072 */
2073 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2074 hd->abortSCpnt = NULL;
2075
2076 /* If an internal command is present
2077 * or the TM failed - reload the FW.
2078 * FC FW may respond FAILED to an ABORT
2079 */
2080 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2081 if ((hd->cmdPtr) ||
2082 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2083 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2084 printk((KERN_WARNING
2085 " Firmware Reload FAILED!!\n"));
2086 }
2087 }
2088 }
2089 } else {
2090 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2091
2092 hd->abortSCpnt = NULL;
2093
2094 }
2095 }
2096
2097 spin_lock_irqsave(&ioc->FreeQlock, flags);
2098 hd->tmPending = 0;
2099 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2100 hd->tmState = TM_STATE_NONE;
2101
2102 return 1;
2103}
2104
2105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2106/*
2107 * This is anyones guess quite frankly.
2108 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002109int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2111 sector_t capacity, int geom[])
2112{
2113 int heads;
2114 int sectors;
2115 sector_t cylinders;
2116 ulong dummy;
2117
2118 heads = 64;
2119 sectors = 32;
2120
2121 dummy = heads * sectors;
2122 cylinders = capacity;
2123 sector_div(cylinders,dummy);
2124
2125 /*
2126 * Handle extended translation size for logical drives
2127 * > 1Gb
2128 */
2129 if ((ulong)capacity >= 0x200000) {
2130 heads = 255;
2131 sectors = 63;
2132 dummy = heads * sectors;
2133 cylinders = capacity;
2134 sector_div(cylinders,dummy);
2135 }
2136
2137 /* return result */
2138 geom[0] = heads;
2139 geom[1] = sectors;
2140 geom[2] = cylinders;
2141
2142 dprintk((KERN_NOTICE
2143 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2144 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2145
2146 return 0;
2147}
2148
Moore, Ericf44e5462006-03-14 09:14:21 -07002149/* Search IOC page 3 to determine if this is hidden physical disk
2150 *
2151 */
2152int
2153mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2154{
2155 int i;
2156
2157 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2158 return 0;
2159 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2160 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2161 return 1;
2162 }
2163 return 0;
2164}
2165EXPORT_SYMBOL(mptscsih_is_phys_disk);
2166
James Bottomleyc92f2222006-03-01 09:02:49 -06002167int
2168mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2169{
2170 int i;
2171
2172 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2173 return -ENXIO;
2174
2175 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2176 if (physdiskid ==
2177 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2178 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2179 }
2180
2181 return -ENXIO;
2182}
2183EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2186/*
2187 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002188 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002191int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002192mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002194 VirtTarget *vtarget;
2195
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002196 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002197 if (!vtarget)
2198 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002199 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002200 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002201 return 0;
2202}
2203
2204/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2205/*
2206 * OS entry point to allow host driver to alloc memory
2207 * for each scsi device. Called once per device the bus scan.
2208 * Return non-zero if allocation fails.
2209 */
2210int
2211mptscsih_slave_alloc(struct scsi_device *sdev)
2212{
2213 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002215 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002217 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002219 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (!vdev) {
2221 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2222 hd->ioc->name, sizeof(VirtDevice));
2223 return -ENOMEM;
2224 }
2225
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002226 vdev->lun = sdev->lun;
2227 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002229 starget = scsi_target(sdev);
2230 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002231
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002232 vdev->vtarget = vtarget;
2233
2234 if (vtarget->num_luns == 0) {
2235 hd->Targets[sdev->id] = vtarget;
2236 vtarget->ioc_id = hd->ioc->id;
2237 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2238 vtarget->target_id = sdev->id;
2239 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002240 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2241 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2242 vtarget->raidVolume = 1;
2243 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002244 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002245 }
2246 }
2247 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 return 0;
2249}
2250
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251/*
2252 * OS entry point to allow for host driver to free allocated memory
2253 * Called if no device present or device being unloaded
2254 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002255void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002256mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002258 if (starget->hostdata)
2259 kfree(starget->hostdata);
2260 starget->hostdata = NULL;
2261}
2262
2263/*
2264 * OS entry point to allow for host driver to free allocated memory
2265 * Called if no device present or device being unloaded
2266 */
2267void
2268mptscsih_slave_destroy(struct scsi_device *sdev)
2269{
2270 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002272 VirtTarget *vtarget;
2273 VirtDevice *vdevice;
2274 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002276 starget = scsi_target(sdev);
2277 vtarget = starget->hostdata;
2278 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002280 mptscsih_search_running_cmds(hd, vdevice);
2281 vtarget->luns[0] &= ~(1 << vdevice->lun);
2282 vtarget->num_luns--;
2283 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002284 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002286 mptscsih_synchronize_cache(hd, vdevice);
2287 kfree(vdevice);
2288 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289}
2290
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002291/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2292/*
2293 * mptscsih_change_queue_depth - This function will set a devices queue depth
2294 * @sdev: per scsi_device pointer
2295 * @qdepth: requested queue depth
2296 *
2297 * Adding support for new 'change_queue_depth' api.
2298*/
2299int
2300mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002302 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2303 VirtTarget *vtarget;
2304 struct scsi_target *starget;
2305 int max_depth;
2306 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002308 starget = scsi_target(sdev);
2309 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002310
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002311 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002312 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002314 else if (sdev->type == TYPE_DISK &&
2315 vtarget->minSyncFactor <= MPT_ULTRA160)
2316 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2317 else
2318 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 } else
2320 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2321
2322 if (qdepth > max_depth)
2323 qdepth = max_depth;
2324 if (qdepth == 1)
2325 tagged = 0;
2326 else
2327 tagged = MSG_SIMPLE_TAG;
2328
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002329 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2330 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331}
2332
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333/*
2334 * OS entry point to adjust the queue_depths on a per-device basis.
2335 * Called once per device the bus scan. Use it to force the queue_depth
2336 * member to 1 if a device does not support Q tags.
2337 * Return non-zero if fails.
2338 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002339int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002340mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002342 struct Scsi_Host *sh = sdev->host;
2343 VirtTarget *vtarget;
2344 VirtDevice *vdevice;
2345 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002347 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002349 starget = scsi_target(sdev);
2350 vtarget = starget->hostdata;
2351 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352
2353 dsprintk((MYIOC_s_INFO_FMT
2354 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002355 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2356 if (hd->ioc->bus_type == SPI)
2357 dsprintk((MYIOC_s_INFO_FMT
2358 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2359 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2360 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002362 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002364 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 goto slave_configure_exit;
2366 }
2367
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368 vdevice->configured_lun=1;
2369 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2370 indexed_lun = (vdevice->lun % 32);
2371 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002372 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002373 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375 dsprintk((MYIOC_s_INFO_FMT
2376 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002377 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379 if (hd->ioc->bus_type == SPI)
2380 dsprintk((MYIOC_s_INFO_FMT
2381 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2382 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2383 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
2385slave_configure_exit:
2386
2387 dsprintk((MYIOC_s_INFO_FMT
2388 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002389 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2390 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391
2392 return 0;
2393}
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2396/*
2397 * Private routines...
2398 */
2399
2400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2401/* Utility function to copy sense data from the scsi_cmnd buffer
2402 * to the FC and SCSI target structures.
2403 *
2404 */
2405static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002406mptscsih_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 -07002407{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002408 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 SCSIIORequest_t *pReq;
2410 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412 /* Get target structure
2413 */
2414 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002415 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
2417 if (sense_count) {
2418 u8 *sense_data;
2419 int req_index;
2420
2421 /* Copy the sense received into the scsi command block. */
2422 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2423 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2424 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2425
2426 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2427 */
2428 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002429 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 int idx;
2431 MPT_ADAPTER *ioc = hd->ioc;
2432
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002433 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2435 ioc->events[idx].eventContext = ioc->eventContext;
2436
2437 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2438 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002439 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2442
2443 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002444 if (hd->ioc->pcidev->vendor ==
2445 PCI_VENDOR_ID_IBM) {
2446 mptscsih_issue_sep_command(hd->ioc,
2447 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2448 vdev->vtarget->tflags |=
2449 MPT_TARGET_FLAGS_LED_ON;
2450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 }
2452 }
2453 } else {
2454 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2455 hd->ioc->name));
2456 }
2457}
2458
2459static u32
2460SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2461{
2462 MPT_SCSI_HOST *hd;
2463 int i;
2464
2465 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2466
2467 for (i = 0; i < hd->ioc->req_depth; i++) {
2468 if (hd->ScsiLookup[i] == sc) {
2469 return i;
2470 }
2471 }
2472
2473 return -1;
2474}
2475
2476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002477int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2479{
2480 MPT_SCSI_HOST *hd;
2481 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002482 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
2484 dtmprintk((KERN_WARNING MYNAM
2485 ": IOC %s_reset routed to SCSI host driver!\n",
2486 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2487 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2488
2489 /* If a FW reload request arrives after base installed but
2490 * before all scsi hosts have been attached, then an alt_ioc
2491 * may have a NULL sh pointer.
2492 */
2493 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2494 return 0;
2495 else
2496 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2497
2498 if (reset_phase == MPT_IOC_SETUP_RESET) {
2499 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2500
2501 /* Clean Up:
2502 * 1. Set Hard Reset Pending Flag
2503 * All new commands go to doneQ
2504 */
2505 hd->resetPending = 1;
2506
2507 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2508 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2509
2510 /* 2. Flush running commands
2511 * Clean ScsiLookup (and associated memory)
2512 * AND clean mytaskQ
2513 */
2514
2515 /* 2b. Reply to OS all known outstanding I/O commands.
2516 */
2517 mptscsih_flush_running_cmds(hd);
2518
2519 /* 2c. If there was an internal command that
2520 * has not completed, configuration or io request,
2521 * free these resources.
2522 */
2523 if (hd->cmdPtr) {
2524 del_timer(&hd->timer);
2525 mpt_free_msg_frame(ioc, hd->cmdPtr);
2526 }
2527
2528 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2529
2530 } else {
2531 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2532
2533 /* Once a FW reload begins, all new OS commands are
2534 * redirected to the doneQ w/ a reset status.
2535 * Init all control structures.
2536 */
2537
2538 /* ScsiLookup initialization
2539 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002540 for (ii=0; ii < hd->ioc->req_depth; ii++)
2541 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
2543 /* 2. Chain Buffer initialization
2544 */
2545
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002546 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549 /* 5. Enable new commands to be posted
2550 */
2551 spin_lock_irqsave(&ioc->FreeQlock, flags);
2552 hd->tmPending = 0;
2553 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2554 hd->resetPending = 0;
2555 hd->tmState = TM_STATE_NONE;
2556
2557 /* 6. If there was an internal command,
2558 * wake this process up.
2559 */
2560 if (hd->cmdPtr) {
2561 /*
2562 * Wake up the original calling thread
2563 */
2564 hd->pLocal = &hd->localReply;
2565 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002566 hd->scandv_wait_done = 1;
2567 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 hd->cmdPtr = NULL;
2569 }
2570
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2572
2573 }
2574
2575 return 1; /* currently means nothing really */
2576}
2577
2578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002579int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2581{
2582 MPT_SCSI_HOST *hd;
2583 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2584
Moore, Eric3a892be2006-03-14 09:14:03 -07002585 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 ioc->name, event));
2587
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002588 if (ioc->sh == NULL ||
2589 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2590 return 1;
2591
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 switch (event) {
2593 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2594 /* FIXME! */
2595 break;
2596 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2597 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002598 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002599 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 break;
2601 case MPI_EVENT_LOGOUT: /* 09 */
2602 /* FIXME! */
2603 break;
2604
Michael Reed05e8ec12006-01-13 14:31:54 -06002605 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002606 break;
2607
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 /*
2609 * CHECKME! Don't think we need to do
2610 * anything for these, but...
2611 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2613 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2614 /*
2615 * CHECKME! Falling thru...
2616 */
2617 break;
2618
2619 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002620 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 case MPI_EVENT_NONE: /* 00 */
2623 case MPI_EVENT_LOG_DATA: /* 01 */
2624 case MPI_EVENT_STATE_CHANGE: /* 02 */
2625 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2626 default:
2627 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2628 break;
2629 }
2630
2631 return 1; /* currently means nothing really */
2632}
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2635/*
2636 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2637 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002638 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002639 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 *
2641 * NOTE: It's only SAFE to call this routine if data points to
2642 * sane & valid STANDARD INQUIRY data!
2643 *
2644 * Allocate and initialize memory for this target.
2645 * Save inquiry data.
2646 *
2647 */
2648static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002649mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2650 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002653 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 /* Is LUN supported? If so, upper 2 bits will be 0
2656 * in first byte of inquiry data.
2657 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002658 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 return;
2660
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002661 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
James Bottomleyc92f2222006-03-01 09:02:49 -06002664 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002666 if (hd->ioc->bus_type != SPI)
2667 return;
2668
James Bottomleyc92f2222006-03-01 09:02:49 -06002669 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002670 /* Treat all Processors as SAF-TE if
2671 * command line option is set */
2672 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2673 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002674 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002675 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002676 if (sdev->inquiry_len > 49 ) {
2677 if (sdev->inquiry[44] == 'S' &&
2678 sdev->inquiry[45] == 'A' &&
2679 sdev->inquiry[46] == 'F' &&
2680 sdev->inquiry[47] == '-' &&
2681 sdev->inquiry[48] == 'T' &&
2682 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002683 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2684 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 }
2686 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002687 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002688 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689}
2690
2691/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2692/*
2693 * Update the target negotiation parameters based on the
2694 * the Inquiry data, adapter capabilities, and NVRAM settings.
2695 *
2696 */
2697static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002698mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2699 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002701 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 int id = (int) target->target_id;
2703 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 u8 width = MPT_NARROW;
2705 u8 factor = MPT_ASYNC;
2706 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002707 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 u8 noQas = 1;
2709
2710 target->negoFlags = pspi_data->noQas;
2711
James Bottomleyc92f2222006-03-01 09:02:49 -06002712 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
James Bottomleyc92f2222006-03-01 09:02:49 -06002714 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 width = 0;
2716 factor = MPT_ULTRA2;
2717 offset = pspi_data->maxSyncOffset;
2718 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2719 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002720 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 width = 1;
2722 }
2723
James Bottomleyc92f2222006-03-01 09:02:49 -06002724 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002726 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002728 else {
2729 if (!scsi_device_ius(sdev) &&
2730 !scsi_device_qas(sdev))
2731 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002733 factor = MPT_ULTRA320;
2734 if (scsi_device_qas(sdev)) {
2735 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2736 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002738 if (sdev->type == TYPE_TAPE &&
2739 scsi_device_ius(sdev))
2740 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 offset = pspi_data->maxSyncOffset;
2744
2745 /* If RAID, never disable QAS
2746 * else if non RAID, do not disable
2747 * QAS if bit 1 is set
2748 * bit 1 QAS support, non-raid only
2749 * bit 0 IU support
2750 */
2751 if (target->raidVolume == 1) {
2752 noQas = 0;
2753 }
2754 } else {
2755 factor = MPT_ASYNC;
2756 offset = 0;
2757 }
2758 }
2759
James Bottomleyc92f2222006-03-01 09:02:49 -06002760 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2762 }
2763
2764 /* Update tflags based on NVRAM settings. (SCSI only)
2765 */
2766 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2767 nvram = pspi_data->nvram[id];
2768 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2769
2770 if (width)
2771 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2772
2773 if (offset > 0) {
2774 /* Ensure factor is set to the
2775 * maximum of: adapter, nvram, inquiry
2776 */
2777 if (nfactor) {
2778 if (nfactor < pspi_data->minSyncFactor )
2779 nfactor = pspi_data->minSyncFactor;
2780
2781 factor = max(factor, nfactor);
2782 if (factor == MPT_ASYNC)
2783 offset = 0;
2784 } else {
2785 offset = 0;
2786 factor = MPT_ASYNC;
2787 }
2788 } else {
2789 factor = MPT_ASYNC;
2790 }
2791 }
2792
2793 /* Make sure data is consistent
2794 */
2795 if ((!width) && (factor < MPT_ULTRA2)) {
2796 factor = MPT_ULTRA2;
2797 }
2798
2799 /* Save the data to the target structure.
2800 */
2801 target->minSyncFactor = factor;
2802 target->maxOffset = offset;
2803 target->maxWidth = width;
2804
2805 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2806
2807 /* Disable unused features.
2808 */
2809 if (!width)
2810 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2811
2812 if (!offset)
2813 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2814
2815 if ( factor > MPT_ULTRA320 )
2816 noQas = 0;
2817
James Bottomleyc92f2222006-03-01 09:02:49 -06002818 if (noQas && (pspi_data->noQas == 0)) {
2819 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2820 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
James Bottomleyc92f2222006-03-01 09:02:49 -06002822 /* Disable QAS in a mixed configuration case
2823 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
James Bottomleyc92f2222006-03-01 09:02:49 -06002825 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 }
2827}
2828
2829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
2831/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2832/*
2833 * SCSI Config Page functionality ...
2834 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837/* mptscsih_writeIOCPage4 - write IOC Page 4
2838 * @hd: Pointer to a SCSI Host Structure
2839 * @target_id: write IOC Page4 for this ID & Bus
2840 *
2841 * Return: -EAGAIN if unable to obtain a Message Frame
2842 * or 0 if success.
2843 *
2844 * Remark: We do not wait for a return, write pages sequentially.
2845 */
2846static int
2847mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2848{
2849 MPT_ADAPTER *ioc = hd->ioc;
2850 Config_t *pReq;
2851 IOCPage4_t *IOCPage4Ptr;
2852 MPT_FRAME_HDR *mf;
2853 dma_addr_t dataDma;
2854 u16 req_idx;
2855 u32 frameOffset;
2856 u32 flagsLength;
2857 int ii;
2858
2859 /* Get a MF for this command.
2860 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002861 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002862 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 ioc->name));
2864 return -EAGAIN;
2865 }
2866
2867 /* Set the request and the data pointers.
2868 * Place data at end of MF.
2869 */
2870 pReq = (Config_t *)mf;
2871
2872 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2873 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2874
2875 /* Complete the request frame (same for all requests).
2876 */
2877 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2878 pReq->Reserved = 0;
2879 pReq->ChainOffset = 0;
2880 pReq->Function = MPI_FUNCTION_CONFIG;
2881 pReq->ExtPageLength = 0;
2882 pReq->ExtPageType = 0;
2883 pReq->MsgFlags = 0;
2884 for (ii=0; ii < 8; ii++) {
2885 pReq->Reserved2[ii] = 0;
2886 }
2887
2888 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2889 dataDma = ioc->spi_data.IocPg4_dma;
2890 ii = IOCPage4Ptr->ActiveSEP++;
2891 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2892 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2893 pReq->Header = IOCPage4Ptr->Header;
2894 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2895
2896 /* Add a SGE to the config request.
2897 */
2898 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2899 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2900
2901 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2902
2903 dinitprintk((MYIOC_s_INFO_FMT
2904 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2905 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2906
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002907 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 return 0;
2910}
2911
2912/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2913/*
2914 * Bus Scan and Domain Validation functionality ...
2915 */
2916
2917/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2918/*
2919 * mptscsih_scandv_complete - Scan and DV callback routine registered
2920 * to Fustion MPT (base) driver.
2921 *
2922 * @ioc: Pointer to MPT_ADAPTER structure
2923 * @mf: Pointer to original MPT request frame
2924 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2925 *
2926 * This routine is called from mpt.c::mpt_interrupt() at the completion
2927 * of any SCSI IO request.
2928 * This routine is registered with the Fusion MPT (base) driver at driver
2929 * load/init time via the mpt_register() API call.
2930 *
2931 * Returns 1 indicating alloc'd request frame ptr should be freed.
2932 *
2933 * Remark: Sets a completion code and (possibly) saves sense data
2934 * in the IOC member localReply structure.
2935 * Used ONLY for DV and other internal commands.
2936 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002937int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2939{
2940 MPT_SCSI_HOST *hd;
2941 SCSIIORequest_t *pReq;
2942 int completionCode;
2943 u16 req_idx;
2944
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002945 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2946
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 if ((mf == NULL) ||
2948 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2949 printk(MYIOC_s_ERR_FMT
2950 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2951 ioc->name, mf?"BAD":"NULL", (void *) mf);
2952 goto wakeup;
2953 }
2954
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 del_timer(&hd->timer);
2956 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2957 hd->ScsiLookup[req_idx] = NULL;
2958 pReq = (SCSIIORequest_t *) mf;
2959
2960 if (mf != hd->cmdPtr) {
2961 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2962 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2963 }
2964 hd->cmdPtr = NULL;
2965
2966 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2967 hd->ioc->name, mf, mr, req_idx));
2968
2969 hd->pLocal = &hd->localReply;
2970 hd->pLocal->scsiStatus = 0;
2971
2972 /* If target struct exists, clear sense valid flag.
2973 */
2974 if (mr == NULL) {
2975 completionCode = MPT_SCANDV_GOOD;
2976 } else {
2977 SCSIIOReply_t *pReply;
2978 u16 status;
2979 u8 scsi_status;
2980
2981 pReply = (SCSIIOReply_t *) mr;
2982
2983 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2984 scsi_status = pReply->SCSIStatus;
2985
2986 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2987 status, pReply->SCSIState, scsi_status,
2988 le32_to_cpu(pReply->IOCLogInfo)));
2989
2990 switch(status) {
2991
2992 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2993 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2994 break;
2995
2996 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2997 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2998 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2999 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3000 completionCode = MPT_SCANDV_DID_RESET;
3001 break;
3002
3003 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3004 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3005 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3006 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3007 ConfigReply_t *pr = (ConfigReply_t *)mr;
3008 completionCode = MPT_SCANDV_GOOD;
3009 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3010 hd->pLocal->header.PageLength = pr->Header.PageLength;
3011 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3012 hd->pLocal->header.PageType = pr->Header.PageType;
3013
3014 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3015 /* If the RAID Volume request is successful,
3016 * return GOOD, else indicate that
3017 * some type of error occurred.
3018 */
3019 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003020 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 completionCode = MPT_SCANDV_GOOD;
3022 else
3023 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06003024 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
3026 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3027 u8 *sense_data;
3028 int sz;
3029
3030 /* save sense data in global structure
3031 */
3032 completionCode = MPT_SCANDV_SENSE;
3033 hd->pLocal->scsiStatus = scsi_status;
3034 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3035 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3036
3037 sz = min_t(int, pReq->SenseBufferLength,
3038 SCSI_STD_SENSE_BYTES);
3039 memcpy(hd->pLocal->sense, sense_data, sz);
3040
3041 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3042 sense_data));
3043 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3044 if (pReq->CDB[0] == INQUIRY)
3045 completionCode = MPT_SCANDV_ISSUE_SENSE;
3046 else
3047 completionCode = MPT_SCANDV_DID_RESET;
3048 }
3049 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3050 completionCode = MPT_SCANDV_DID_RESET;
3051 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3052 completionCode = MPT_SCANDV_DID_RESET;
3053 else {
3054 completionCode = MPT_SCANDV_GOOD;
3055 hd->pLocal->scsiStatus = scsi_status;
3056 }
3057 break;
3058
3059 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3060 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3061 completionCode = MPT_SCANDV_DID_RESET;
3062 else
3063 completionCode = MPT_SCANDV_SOME_ERROR;
3064 break;
3065
3066 default:
3067 completionCode = MPT_SCANDV_SOME_ERROR;
3068 break;
3069
3070 } /* switch(status) */
3071
3072 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3073 completionCode));
3074 } /* end of address reply case */
3075
3076 hd->pLocal->completion = completionCode;
3077
3078 /* MF and RF are freed in mpt_interrupt
3079 */
3080wakeup:
3081 /* Free Chain buffers (will never chain) in scan or dv */
3082 //mptscsih_freeChainBuffers(ioc, req_idx);
3083
3084 /*
3085 * Wake up the original calling thread
3086 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003087 hd->scandv_wait_done = 1;
3088 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
3090 return 1;
3091}
3092
3093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3094/* mptscsih_timer_expired - Call back for timer process.
3095 * Used only for dv functionality.
3096 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3097 *
3098 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003099void
3100mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101{
3102 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3103
3104 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3105
3106 if (hd->cmdPtr) {
3107 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3108
3109 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3110 /* Desire to issue a task management request here.
3111 * TM requests MUST be single threaded.
3112 * If old eh code and no TM current, issue request.
3113 * If new eh code, do nothing. Wait for OS cmd timeout
3114 * for bus reset.
3115 */
3116 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3117 } else {
3118 /* Perform a FW reload */
3119 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3120 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3121 }
3122 }
3123 } else {
3124 /* This should NEVER happen */
3125 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3126 }
3127
3128 /* No more processing.
3129 * TM call will generate an interrupt for SCSI TM Management.
3130 * The FW will reply to all outstanding commands, callback will finish cleanup.
3131 * Hard reset clean-up will free all resources.
3132 */
3133 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3134
3135 return;
3136}
3137
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
3139/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3140/**
3141 * mptscsih_do_cmd - Do internal command.
3142 * @hd: MPT_SCSI_HOST pointer
3143 * @io: INTERNAL_CMD pointer.
3144 *
3145 * Issue the specified internally generated command and do command
3146 * specific cleanup. For bus scan / DV only.
3147 * NOTES: If command is Inquiry and status is good,
3148 * initialize a target structure, save the data
3149 *
3150 * Remark: Single threaded access only.
3151 *
3152 * Return:
3153 * < 0 if an illegal command or no resources
3154 *
3155 * 0 if good
3156 *
3157 * > 0 if command complete but some type of completion error.
3158 */
3159static int
3160mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3161{
3162 MPT_FRAME_HDR *mf;
3163 SCSIIORequest_t *pScsiReq;
3164 SCSIIORequest_t ReqCopy;
3165 int my_idx, ii, dir;
3166 int rc, cmdTimeout;
3167 int in_isr;
3168 char cmdLen;
3169 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3170 char cmd = io->cmd;
3171
3172 in_isr = in_interrupt();
3173 if (in_isr) {
3174 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3175 hd->ioc->name));
3176 return -EPERM;
3177 }
3178
3179
3180 /* Set command specific information
3181 */
3182 switch (cmd) {
3183 case INQUIRY:
3184 cmdLen = 6;
3185 dir = MPI_SCSIIO_CONTROL_READ;
3186 CDB[0] = cmd;
3187 CDB[4] = io->size;
3188 cmdTimeout = 10;
3189 break;
3190
3191 case TEST_UNIT_READY:
3192 cmdLen = 6;
3193 dir = MPI_SCSIIO_CONTROL_READ;
3194 cmdTimeout = 10;
3195 break;
3196
3197 case START_STOP:
3198 cmdLen = 6;
3199 dir = MPI_SCSIIO_CONTROL_READ;
3200 CDB[0] = cmd;
3201 CDB[4] = 1; /*Spin up the disk */
3202 cmdTimeout = 15;
3203 break;
3204
3205 case REQUEST_SENSE:
3206 cmdLen = 6;
3207 CDB[0] = cmd;
3208 CDB[4] = io->size;
3209 dir = MPI_SCSIIO_CONTROL_READ;
3210 cmdTimeout = 10;
3211 break;
3212
3213 case READ_BUFFER:
3214 cmdLen = 10;
3215 dir = MPI_SCSIIO_CONTROL_READ;
3216 CDB[0] = cmd;
3217 if (io->flags & MPT_ICFLAG_ECHO) {
3218 CDB[1] = 0x0A;
3219 } else {
3220 CDB[1] = 0x02;
3221 }
3222
3223 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3224 CDB[1] |= 0x01;
3225 }
3226 CDB[6] = (io->size >> 16) & 0xFF;
3227 CDB[7] = (io->size >> 8) & 0xFF;
3228 CDB[8] = io->size & 0xFF;
3229 cmdTimeout = 10;
3230 break;
3231
3232 case WRITE_BUFFER:
3233 cmdLen = 10;
3234 dir = MPI_SCSIIO_CONTROL_WRITE;
3235 CDB[0] = cmd;
3236 if (io->flags & MPT_ICFLAG_ECHO) {
3237 CDB[1] = 0x0A;
3238 } else {
3239 CDB[1] = 0x02;
3240 }
3241 CDB[6] = (io->size >> 16) & 0xFF;
3242 CDB[7] = (io->size >> 8) & 0xFF;
3243 CDB[8] = io->size & 0xFF;
3244 cmdTimeout = 10;
3245 break;
3246
3247 case RESERVE:
3248 cmdLen = 6;
3249 dir = MPI_SCSIIO_CONTROL_READ;
3250 CDB[0] = cmd;
3251 cmdTimeout = 10;
3252 break;
3253
3254 case RELEASE:
3255 cmdLen = 6;
3256 dir = MPI_SCSIIO_CONTROL_READ;
3257 CDB[0] = cmd;
3258 cmdTimeout = 10;
3259 break;
3260
3261 case SYNCHRONIZE_CACHE:
3262 cmdLen = 10;
3263 dir = MPI_SCSIIO_CONTROL_READ;
3264 CDB[0] = cmd;
3265// CDB[1] = 0x02; /* set immediate bit */
3266 cmdTimeout = 10;
3267 break;
3268
3269 default:
3270 /* Error Case */
3271 return -EFAULT;
3272 }
3273
3274 /* Get and Populate a free Frame
3275 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003276 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3278 hd->ioc->name));
3279 return -EBUSY;
3280 }
3281
3282 pScsiReq = (SCSIIORequest_t *) mf;
3283
3284 /* Get the request index */
3285 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3286 ADD_INDEX_LOG(my_idx); /* for debug */
3287
3288 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3289 pScsiReq->TargetID = io->physDiskNum;
3290 pScsiReq->Bus = 0;
3291 pScsiReq->ChainOffset = 0;
3292 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3293 } else {
3294 pScsiReq->TargetID = io->id;
3295 pScsiReq->Bus = io->bus;
3296 pScsiReq->ChainOffset = 0;
3297 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3298 }
3299
3300 pScsiReq->CDBLength = cmdLen;
3301 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3302
3303 pScsiReq->Reserved = 0;
3304
3305 pScsiReq->MsgFlags = mpt_msg_flags();
3306 /* MsgContext set in mpt_get_msg_fram call */
3307
3308 for (ii=0; ii < 8; ii++)
3309 pScsiReq->LUN[ii] = 0;
3310 pScsiReq->LUN[1] = io->lun;
3311
3312 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3313 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3314 else
3315 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3316
3317 if (cmd == REQUEST_SENSE) {
3318 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3319 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3320 hd->ioc->name, cmd));
3321 }
3322
3323 for (ii=0; ii < 16; ii++)
3324 pScsiReq->CDB[ii] = CDB[ii];
3325
3326 pScsiReq->DataLength = cpu_to_le32(io->size);
3327 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3328 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3329
3330 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3331 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3332
3333 if (dir == MPI_SCSIIO_CONTROL_READ) {
3334 mpt_add_sge((char *) &pScsiReq->SGL,
3335 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3336 io->data_dma);
3337 } else {
3338 mpt_add_sge((char *) &pScsiReq->SGL,
3339 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3340 io->data_dma);
3341 }
3342
3343 /* The ISR will free the request frame, but we need
3344 * the information to initialize the target. Duplicate.
3345 */
3346 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3347
3348 /* Issue this command after:
3349 * finish init
3350 * add timer
3351 * Wait until the reply has been received
3352 * ScsiScanDvCtx callback function will
3353 * set hd->pLocal;
3354 * set scandv_wait_done and call wake_up
3355 */
3356 hd->pLocal = NULL;
3357 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003358 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 /* Save cmd pointer, for resource free if timeout or
3361 * FW reload occurs
3362 */
3363 hd->cmdPtr = mf;
3364
3365 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003366 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3367 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368
3369 if (hd->pLocal) {
3370 rc = hd->pLocal->completion;
3371 hd->pLocal->skip = 0;
3372
3373 /* Always set fatal error codes in some cases.
3374 */
3375 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3376 rc = -ENXIO;
3377 else if (rc == MPT_SCANDV_SOME_ERROR)
3378 rc = -rc;
3379 } else {
3380 rc = -EFAULT;
3381 /* This should never happen. */
3382 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3383 hd->ioc->name));
3384 }
3385
3386 return rc;
3387}
3388
3389/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3390/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003391 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3392 * @hd: Pointer to a SCSI HOST structure
3393 * @vtarget: per device private data
3394 * @lun: lun
3395 *
3396 * Uses the ISR, but with special processing.
3397 * MUST be single-threaded.
3398 *
3399 */
3400static void
3401mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3402{
3403 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404
3405 /* Following parameters will not change
3406 * in this routine.
3407 */
3408 iocmd.cmd = SYNCHRONIZE_CACHE;
3409 iocmd.flags = 0;
3410 iocmd.physDiskNum = -1;
3411 iocmd.data = NULL;
3412 iocmd.data_dma = -1;
3413 iocmd.size = 0;
3414 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003415 iocmd.bus = vdevice->vtarget->bus_id;
3416 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003417 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418
James Bottomleyc92f2222006-03-01 09:02:49 -06003419 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003420 (vdevice->configured_lun))
3421 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422}
3423
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003424EXPORT_SYMBOL(mptscsih_remove);
3425EXPORT_SYMBOL(mptscsih_shutdown);
3426#ifdef CONFIG_PM
3427EXPORT_SYMBOL(mptscsih_suspend);
3428EXPORT_SYMBOL(mptscsih_resume);
3429#endif
3430EXPORT_SYMBOL(mptscsih_proc_info);
3431EXPORT_SYMBOL(mptscsih_info);
3432EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003433EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003434EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003435EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003436EXPORT_SYMBOL(mptscsih_slave_destroy);
3437EXPORT_SYMBOL(mptscsih_slave_configure);
3438EXPORT_SYMBOL(mptscsih_abort);
3439EXPORT_SYMBOL(mptscsih_dev_reset);
3440EXPORT_SYMBOL(mptscsih_bus_reset);
3441EXPORT_SYMBOL(mptscsih_host_reset);
3442EXPORT_SYMBOL(mptscsih_bios_param);
3443EXPORT_SYMBOL(mptscsih_io_done);
3444EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3445EXPORT_SYMBOL(mptscsih_scandv_complete);
3446EXPORT_SYMBOL(mptscsih_event_process);
3447EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003448EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003449EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003450EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/