blob: 8242b16e316841643e85db9d235ac314e2265bc8 [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
500/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
501/*
502 * mptscsih_io_done - Main SCSI IO callback routine registered to
503 * Fusion MPT (base) driver
504 * @ioc: Pointer to MPT_ADAPTER structure
505 * @mf: Pointer to original MPT request frame
506 * @r: Pointer to MPT reply frame (NULL if TurboReply)
507 *
508 * This routine is called from mpt.c::mpt_interrupt() at the completion
509 * of any SCSI IO request.
510 * This routine is registered with the Fusion MPT (base) driver at driver
511 * load/init time via the mpt_register() API call.
512 *
513 * Returns 1 indicating alloc'd request frame ptr should be freed.
514 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400515int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
517{
518 struct scsi_cmnd *sc;
519 MPT_SCSI_HOST *hd;
520 SCSIIORequest_t *pScsiReq;
521 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700522 u16 req_idx, req_idx_MR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
525
526 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700527 req_idx_MR = (mr != NULL) ?
528 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
529 if ((req_idx != req_idx_MR) ||
530 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
531 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
532 ioc->name);
533 printk (MYIOC_s_ERR_FMT
534 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
535 ioc->name, req_idx, req_idx_MR, mf, mr,
536 hd->ScsiLookup[req_idx_MR]);
537 return 0;
538 }
539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 sc = hd->ScsiLookup[req_idx];
541 if (sc == NULL) {
542 MPIHeader_t *hdr = (MPIHeader_t *)mf;
543
544 /* Remark: writeSDP1 will use the ScsiDoneCtx
545 * If a SCSI I/O cmd, device disabled by OS and
546 * completion done. Cannot touch sc struct. Just free mem.
547 */
548 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
549 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
550 ioc->name);
551
552 mptscsih_freeChainBuffers(ioc, req_idx);
553 return 1;
554 }
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 sc->result = DID_OK << 16; /* Set default reply as OK */
557 pScsiReq = (SCSIIORequest_t *) mf;
558 pScsiReply = (SCSIIOReply_t *) mr;
559
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200560 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
561 dmfprintk((MYIOC_s_INFO_FMT
562 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
563 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
564 }else{
565 dmfprintk((MYIOC_s_INFO_FMT
566 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
567 ioc->name, mf, mr, sc, req_idx));
568 }
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (pScsiReply == NULL) {
571 /* special context reply handling */
572 ;
573 } else {
574 u32 xfer_cnt;
575 u16 status;
576 u8 scsi_state, scsi_status;
577
578 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
579 scsi_state = pScsiReply->SCSIState;
580 scsi_status = pScsiReply->SCSIStatus;
581 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
582 sc->resid = sc->request_bufflen - xfer_cnt;
583
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600584 /*
585 * if we get a data underrun indication, yet no data was
586 * transferred and the SCSI status indicates that the
587 * command was never started, change the data underrun
588 * to success
589 */
590 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
591 (scsi_status == MPI_SCSI_STATUS_BUSY ||
592 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
593 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
594 status = MPI_IOCSTATUS_SUCCESS;
595 }
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
598 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
599 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700600 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600601 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 sc->request_bufflen, xfer_cnt));
603
604 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400605 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 /*
608 * Look for + dump FCP ResponseInfo[]!
609 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600610 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
611 pScsiReply->ResponseInfo) {
612 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
613 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700614 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 le32_to_cpu(pScsiReply->ResponseInfo));
616 }
617
618 switch(status) {
619 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
620 /* CHECKME!
621 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
622 * But not: DID_BUS_BUSY lest one risk
623 * killing interrupt handler:-(
624 */
625 sc->result = SAM_STAT_BUSY;
626 break;
627
628 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
629 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
630 sc->result = DID_BAD_TARGET << 16;
631 break;
632
633 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
634 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600635 if (ioc->bus_type != FC)
636 sc->result = DID_NO_CONNECT << 16;
637 /* else fibre, just stall until rescan event */
638 else
639 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
642 hd->sel_timeout[pScsiReq->TargetID]++;
643 break;
644
645 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
646 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
647 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
648 /* Linux handles an unsolicited DID_RESET better
649 * than an unsolicited DID_ABORT.
650 */
651 sc->result = DID_RESET << 16;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 break;
654
655 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600656 sc->resid = sc->request_bufflen - xfer_cnt;
657 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
658 sc->result=DID_SOFT_ERROR << 16;
659 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600661 dreplyprintk((KERN_NOTICE
662 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
666 /*
667 * Do upfront check for valid SenseData and give it
668 * precedence!
669 */
670 sc->result = (DID_OK << 16) | scsi_status;
671 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
672 /* Have already saved the status and sense data
673 */
674 ;
675 } else {
676 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600677 if (scsi_status == SAM_STAT_BUSY)
678 sc->result = SAM_STAT_BUSY;
679 else
680 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
683 /* What to do?
684 */
685 sc->result = DID_SOFT_ERROR << 16;
686 }
687 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
688 /* Not real sure here either... */
689 sc->result = DID_RESET << 16;
690 }
691 }
692
693 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
694 sc->underflow));
695 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
696 /* Report Queue Full
697 */
698 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
699 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 break;
702
Moore, Eric7e551472006-01-16 18:53:21 -0700703 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
704 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
706 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600707 if (scsi_status == MPI_SCSI_STATUS_BUSY)
708 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
709 else
710 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 if (scsi_state == 0) {
712 ;
713 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
714 /*
715 * If running against circa 200003dd 909 MPT f/w,
716 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
717 * (QUEUE_FULL) returned from device! --> get 0x0000?128
718 * and with SenseBytes set to 0.
719 */
720 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
721 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
722
723 }
724 else if (scsi_state &
725 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
726 ) {
727 /*
728 * What to do?
729 */
730 sc->result = DID_SOFT_ERROR << 16;
731 }
732 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
733 /* Not real sure here either... */
734 sc->result = DID_RESET << 16;
735 }
736 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
737 /* Device Inq. data indicates that it supports
738 * QTags, but rejects QTag messages.
739 * This command completed OK.
740 *
741 * Not real sure here either so do nothing... */
742 }
743
744 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
745 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
746
747 /* Add handling of:
748 * Reservation Conflict, Busy,
749 * Command Terminated, CHECK
750 */
751 break;
752
753 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
754 sc->result = DID_SOFT_ERROR << 16;
755 break;
756
757 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
758 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
759 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
760 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
761 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
762 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
763 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
765 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
766 default:
767 /*
768 * What to do?
769 */
770 sc->result = DID_SOFT_ERROR << 16;
771 break;
772
773 } /* switch(status) */
774
775 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
776 } /* end of address reply case */
777
778 /* Unmap the DMA buffers, if any. */
779 if (sc->use_sg) {
780 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
781 sc->use_sg, sc->sc_data_direction);
782 } else if (sc->request_bufflen) {
783 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
784 sc->request_bufflen, sc->sc_data_direction);
785 }
786
787 hd->ScsiLookup[req_idx] = NULL;
788
789 sc->scsi_done(sc); /* Issue the command callback */
790
791 /* Free Chain buffers */
792 mptscsih_freeChainBuffers(ioc, req_idx);
793 return 1;
794}
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796/*
797 * mptscsih_flush_running_cmds - For each command found, search
798 * Scsi_Host instance taskQ and reply to OS.
799 * Called only if recovering from a FW reload.
800 * @hd: Pointer to a SCSI HOST structure
801 *
802 * Returns: None.
803 *
804 * Must be called while new I/Os are being queued.
805 */
806static void
807mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
808{
809 MPT_ADAPTER *ioc = hd->ioc;
810 struct scsi_cmnd *SCpnt;
811 MPT_FRAME_HDR *mf;
812 int ii;
813 int max = ioc->req_depth;
814
815 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
816 for (ii= 0; ii < max; ii++) {
817 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
818
819 /* Command found.
820 */
821
822 /* Null ScsiLookup index
823 */
824 hd->ScsiLookup[ii] = NULL;
825
826 mf = MPT_INDEX_2_MFPTR(ioc, ii);
827 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
828 mf, SCpnt));
829
830 /* Set status, free OS resources (SG DMA buffers)
831 * Do OS callback
832 * Free driver resources (chain, msg buffers)
833 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400834 if (SCpnt->use_sg) {
835 pci_unmap_sg(ioc->pcidev,
836 (struct scatterlist *) SCpnt->request_buffer,
837 SCpnt->use_sg,
838 SCpnt->sc_data_direction);
839 } else if (SCpnt->request_bufflen) {
840 pci_unmap_single(ioc->pcidev,
841 SCpnt->SCp.dma_handle,
842 SCpnt->request_bufflen,
843 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
845 SCpnt->result = DID_RESET << 16;
846 SCpnt->host_scribble = NULL;
847
848 /* Free Chain buffers */
849 mptscsih_freeChainBuffers(ioc, ii);
850
851 /* Free Message frames */
852 mpt_free_msg_frame(ioc, mf);
853
854 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
855 }
856 }
857
858 return;
859}
860
861/*
862 * mptscsih_search_running_cmds - Delete any commands associated
863 * with the specified target and lun. Function called only
864 * when a lun is disable by mid-layer.
865 * Do NOT access the referenced scsi_cmnd structure or
866 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600867 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700868 * @hd: Pointer to a SCSI HOST structure
869 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 *
871 * Returns: None.
872 *
873 * Called from slave_destroy.
874 */
875static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700876mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 SCSIIORequest_t *mf = NULL;
879 int ii;
880 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600881 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Ericbd23e942006-04-17 12:43:04 -0600884 vdevice->vtarget->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600887 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
890
891 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
892 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
893
Moore, Eric914c2d82006-03-14 09:19:36 -0700894 if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 continue;
896
897 /* Cleanup
898 */
899 hd->ScsiLookup[ii] = NULL;
900 mptscsih_freeChainBuffers(hd->ioc, ii);
901 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600902 if (sc->use_sg) {
903 pci_unmap_sg(hd->ioc->pcidev,
904 (struct scatterlist *) sc->request_buffer,
905 sc->use_sg,
906 sc->sc_data_direction);
907 } else if (sc->request_bufflen) {
908 pci_unmap_single(hd->ioc->pcidev,
909 sc->SCp.dma_handle,
910 sc->request_bufflen,
911 sc->sc_data_direction);
912 }
913 sc->host_scribble = NULL;
914 sc->result = DID_NO_CONNECT << 16;
915 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 return;
919}
920
921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
924/*
925 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
926 * from a SCSI target device.
927 * @sc: Pointer to scsi_cmnd structure
928 * @pScsiReply: Pointer to SCSIIOReply_t
929 * @pScsiReq: Pointer to original SCSI request
930 *
931 * This routine periodically reports QUEUE_FULL status returned from a
932 * SCSI target device. It reports this to the console via kernel
933 * printk() API call, not more than once every 10 seconds.
934 */
935static void
936mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
937{
938 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400941 if (sc->device == NULL)
942 return;
943 if (sc->device->host == NULL)
944 return;
945 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
946 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400948 if (time - hd->last_queue_full > 10 * HZ) {
949 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
950 hd->ioc->name, 0, sc->device->id, sc->device->lun));
951 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953}
954
955/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
956/*
957 * mptscsih_remove - Removed scsi devices
958 * @pdev: Pointer to pci_dev structure
959 *
960 *
961 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400962void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963mptscsih_remove(struct pci_dev *pdev)
964{
965 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
966 struct Scsi_Host *host = ioc->sh;
967 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400968 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600970 if(!host) {
971 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 scsi_remove_host(host);
976
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400977 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
978 return;
979
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700980 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400982 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400984 if (hd->ScsiLookup != NULL) {
985 sz1 = hd->ioc->req_depth * sizeof(void *);
986 kfree(hd->ScsiLookup);
987 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 }
989
Moore, Eric Dean d485eb82005-05-11 17:37:26 -0600990 /*
991 * Free pointer array.
992 */
993 kfree(hd->Targets);
994 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400996 dprintk((MYIOC_s_INFO_FMT
997 "Free'd ScsiLookup (%d) memory\n",
998 hd->ioc->name, sz1));
999
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001000 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001001
1002 /* NULL the Scsi_Host pointer
1003 */
1004 hd->ioc->sh = NULL;
1005
1006 scsi_host_put(host);
1007
1008 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
1012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1013/*
1014 * mptscsih_shutdown - reboot notifier
1015 *
1016 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001017void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001018mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001020 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 struct Scsi_Host *host = ioc->sh;
1022 MPT_SCSI_HOST *hd;
1023
1024 if(!host)
1025 return;
1026
1027 hd = (MPT_SCSI_HOST *)host->hostdata;
1028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029}
1030
1031#ifdef CONFIG_PM
1032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1033/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 *
1036 *
1037 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001038int
Pavel Machek8d189f72005-04-16 15:25:28 -07001039mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001041 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001042 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043}
1044
1045/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1046/*
1047 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1048 *
1049 *
1050 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001051int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052mptscsih_resume(struct pci_dev *pdev)
1053{
1054 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1055 struct Scsi_Host *host = ioc->sh;
1056 MPT_SCSI_HOST *hd;
1057
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001058 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 if(!host)
1061 return 0;
1062
1063 hd = (MPT_SCSI_HOST *)host->hostdata;
1064 if(!hd)
1065 return 0;
1066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 return 0;
1068}
1069
1070#endif
1071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1073/**
1074 * mptscsih_info - Return information about MPT adapter
1075 * @SChost: Pointer to Scsi_Host structure
1076 *
1077 * (linux scsi_host_template.info routine)
1078 *
1079 * Returns pointer to buffer where information was written.
1080 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001081const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082mptscsih_info(struct Scsi_Host *SChost)
1083{
1084 MPT_SCSI_HOST *h;
1085 int size = 0;
1086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001090 if (h->info_kbuf == NULL)
1091 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1092 return h->info_kbuf;
1093 h->info_kbuf[0] = '\0';
1094
1095 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1096 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 }
1098
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001099 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100}
1101
1102struct info_str {
1103 char *buffer;
1104 int length;
1105 int offset;
1106 int pos;
1107};
1108
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001109static void
1110mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111{
1112 if (info->pos + len > info->length)
1113 len = info->length - info->pos;
1114
1115 if (info->pos + len < info->offset) {
1116 info->pos += len;
1117 return;
1118 }
1119
1120 if (info->pos < info->offset) {
1121 data += (info->offset - info->pos);
1122 len -= (info->offset - info->pos);
1123 }
1124
1125 if (len > 0) {
1126 memcpy(info->buffer + info->pos, data, len);
1127 info->pos += len;
1128 }
1129}
1130
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001131static int
1132mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
1134 va_list args;
1135 char buf[81];
1136 int len;
1137
1138 va_start(args, fmt);
1139 len = vsprintf(buf, fmt, args);
1140 va_end(args);
1141
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001142 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return len;
1144}
1145
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001146static int
1147mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148{
1149 struct info_str info;
1150
1151 info.buffer = pbuf;
1152 info.length = len;
1153 info.offset = offset;
1154 info.pos = 0;
1155
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1157 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1158 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1159 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
1161 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1162}
1163
1164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1165/**
1166 * mptscsih_proc_info - Return information about MPT adapter
1167 *
1168 * (linux scsi_host_template.info routine)
1169 *
1170 * buffer: if write, user data; if read, buffer for user
1171 * length: if write, return length;
1172 * offset: if write, 0; if read, the current offset into the buffer from
1173 * the previous read.
1174 * hostno: scsi host number
1175 * func: if write = 1; if read = 0
1176 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001177int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1179 int length, int func)
1180{
1181 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1182 MPT_ADAPTER *ioc = hd->ioc;
1183 int size = 0;
1184
1185 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001186 /*
1187 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 */
1189 } else {
1190 if (start)
1191 *start = buffer;
1192
1193 size = mptscsih_host_info(ioc, buffer, offset, length);
1194 }
1195
1196 return size;
1197}
1198
1199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1200#define ADD_INDEX_LOG(req_ent) do { } while(0)
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/**
1204 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1205 * @SCpnt: Pointer to scsi_cmnd structure
1206 * @done: Pointer SCSI mid-layer IO completion function
1207 *
1208 * (linux scsi_host_template.queuecommand routine)
1209 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1210 * from a linux scsi_cmnd request and send it to the IOC.
1211 *
1212 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1213 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001214int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1216{
1217 MPT_SCSI_HOST *hd;
1218 MPT_FRAME_HDR *mf;
1219 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001220 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 int lun;
1222 u32 datalen;
1223 u32 scsictl;
1224 u32 scsidir;
1225 u32 cmd_len;
1226 int my_idx;
1227 int ii;
1228
1229 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 lun = SCpnt->device->lun;
1231 SCpnt->scsi_done = done;
1232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1234 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1235
1236 if (hd->resetPending) {
1237 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1238 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1239 return SCSI_MLQUEUE_HOST_BUSY;
1240 }
1241
Moore, Ericf44e5462006-03-14 09:14:21 -07001242 if ((hd->ioc->bus_type == SPI) &&
1243 vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001244 mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
1245 SCpnt->result = DID_NO_CONNECT << 16;
1246 done(SCpnt);
1247 return 0;
1248 }
1249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 /*
1251 * Put together a MPT SCSI request...
1252 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001253 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1255 hd->ioc->name));
1256 return SCSI_MLQUEUE_HOST_BUSY;
1257 }
1258
1259 pScsiReq = (SCSIIORequest_t *) mf;
1260
1261 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1262
1263 ADD_INDEX_LOG(my_idx);
1264
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001265 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 * Seems we may receive a buffer (datalen>0) even when there
1267 * will be no data transfer! GRRRRR...
1268 */
1269 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1270 datalen = SCpnt->request_bufflen;
1271 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1272 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1273 datalen = SCpnt->request_bufflen;
1274 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1275 } else {
1276 datalen = 0;
1277 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1278 }
1279
1280 /* Default to untagged. Once a target structure has been allocated,
1281 * use the Inquiry data to determine if device supports tagged.
1282 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001283 if (vdev
1284 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 && (SCpnt->device->tagged_supported)) {
1286 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1287 } else {
1288 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1289 }
1290
1291 /* Use the above information to set up the message frame
1292 */
Moore, Eric914c2d82006-03-14 09:19:36 -07001293 pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
1294 pScsiReq->Bus = vdev->vtarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001296 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1297 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1298 else
1299 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 pScsiReq->CDBLength = SCpnt->cmd_len;
1301 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1302 pScsiReq->Reserved = 0;
1303 pScsiReq->MsgFlags = mpt_msg_flags();
1304 pScsiReq->LUN[0] = 0;
1305 pScsiReq->LUN[1] = lun;
1306 pScsiReq->LUN[2] = 0;
1307 pScsiReq->LUN[3] = 0;
1308 pScsiReq->LUN[4] = 0;
1309 pScsiReq->LUN[5] = 0;
1310 pScsiReq->LUN[6] = 0;
1311 pScsiReq->LUN[7] = 0;
1312 pScsiReq->Control = cpu_to_le32(scsictl);
1313
1314 /*
1315 * Write SCSI CDB into the message
1316 */
1317 cmd_len = SCpnt->cmd_len;
1318 for (ii=0; ii < cmd_len; ii++)
1319 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1320
1321 for (ii=cmd_len; ii < 16; ii++)
1322 pScsiReq->CDB[ii] = 0;
1323
1324 /* DataLength */
1325 pScsiReq->DataLength = cpu_to_le32(datalen);
1326
1327 /* SenseBuffer low address */
1328 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1329 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1330
1331 /* Now add the SG list
1332 * Always have a SGE even if null length.
1333 */
1334 if (datalen == 0) {
1335 /* Add a NULL SGE */
1336 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1337 (dma_addr_t) -1);
1338 } else {
1339 /* Add a 32 or 64 bit SGE */
1340 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1341 goto fail;
1342 }
1343
1344 hd->ScsiLookup[my_idx] = SCpnt;
1345 SCpnt->host_scribble = NULL;
1346
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001347 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1349 hd->ioc->name, SCpnt, mf, my_idx));
1350 DBG_DUMP_REQUEST_FRAME(mf)
1351 return 0;
1352
1353 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001354 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1356 mpt_free_msg_frame(hd->ioc, mf);
1357 return SCSI_MLQUEUE_HOST_BUSY;
1358}
1359
1360/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1361/*
1362 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1363 * with a SCSI IO request
1364 * @hd: Pointer to the MPT_SCSI_HOST instance
1365 * @req_idx: Index of the SCSI IO request frame.
1366 *
1367 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1368 * No return.
1369 */
1370static void
1371mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1372{
1373 MPT_FRAME_HDR *chain;
1374 unsigned long flags;
1375 int chain_idx;
1376 int next;
1377
1378 /* Get the first chain index and reset
1379 * tracker state.
1380 */
1381 chain_idx = ioc->ReqToChain[req_idx];
1382 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1383
1384 while (chain_idx != MPT_HOST_NO_CHAIN) {
1385
1386 /* Save the next chain buffer index */
1387 next = ioc->ChainToChain[chain_idx];
1388
1389 /* Free this chain buffer and reset
1390 * tracker
1391 */
1392 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1393
1394 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1395 + (chain_idx * ioc->req_sz));
1396
1397 spin_lock_irqsave(&ioc->FreeQlock, flags);
1398 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1399 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1400
1401 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1402 ioc->name, chain_idx));
1403
1404 /* handle next */
1405 chain_idx = next;
1406 }
1407 return;
1408}
1409
1410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1411/*
1412 * Reset Handling
1413 */
1414
1415/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1416/*
1417 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1418 * Fall through to mpt_HardResetHandler if: not operational, too many
1419 * failed TM requests or handshake failure.
1420 *
1421 * @ioc: Pointer to MPT_ADAPTER structure
1422 * @type: Task Management type
1423 * @target: Logical Target ID for reset (if appropriate)
1424 * @lun: Logical Unit for reset (if appropriate)
1425 * @ctx2abort: Context for the task to be aborted (if appropriate)
1426 *
1427 * Remark: Currently invoked from a non-interrupt thread (_bh).
1428 *
1429 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1430 * will be active.
1431 *
1432 * Returns 0 for SUCCESS or -1 if FAILED.
1433 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001434int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1436{
1437 MPT_ADAPTER *ioc;
1438 int rc = -1;
1439 int doTask = 1;
1440 u32 ioc_raw_state;
1441 unsigned long flags;
1442
1443 /* If FW is being reloaded currently, return success to
1444 * the calling function.
1445 */
1446 if (hd == NULL)
1447 return 0;
1448
1449 ioc = hd->ioc;
1450 if (ioc == NULL) {
1451 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1452 return FAILED;
1453 }
1454 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1455
1456 // SJR - CHECKME - Can we avoid this here?
1457 // (mpt_HardResetHandler has this check...)
1458 spin_lock_irqsave(&ioc->diagLock, flags);
1459 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1460 spin_unlock_irqrestore(&ioc->diagLock, flags);
1461 return FAILED;
1462 }
1463 spin_unlock_irqrestore(&ioc->diagLock, flags);
1464
1465 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1466 * If we time out and not bus reset, then we return a FAILED status to the caller.
1467 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1468 * successful. Otherwise, reload the FW.
1469 */
1470 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1471 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001472 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 "Timed out waiting for last TM (%d) to complete! \n",
1474 hd->ioc->name, hd->tmPending));
1475 return FAILED;
1476 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001477 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 "Timed out waiting for last TM (%d) to complete! \n",
1479 hd->ioc->name, hd->tmPending));
1480 return FAILED;
1481 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001482 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 "Timed out waiting for last TM (%d) to complete! \n",
1484 hd->ioc->name, hd->tmPending));
1485 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1486 return FAILED;
1487
1488 doTask = 0;
1489 }
1490 } else {
1491 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1492 hd->tmPending |= (1 << type);
1493 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1494 }
1495
1496 /* Is operational?
1497 */
1498 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1499
1500#ifdef MPT_DEBUG_RESET
1501 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1502 printk(MYIOC_s_WARN_FMT
1503 "TM Handler: IOC Not operational(0x%x)!\n",
1504 hd->ioc->name, ioc_raw_state);
1505 }
1506#endif
1507
1508 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1509 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1510
1511 /* Isse the Task Mgmt request.
1512 */
1513 if (hd->hard_resets < -1)
1514 hd->hard_resets++;
1515 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1516 if (rc) {
1517 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1518 } else {
1519 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1520 }
1521 }
1522
1523 /* Only fall through to the HRH if this is a bus reset
1524 */
1525 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1526 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1527 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1528 hd->ioc->name));
1529 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1530 }
1531
1532 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1533
1534 return rc;
1535}
1536
1537
1538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1539/*
1540 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1541 * @hd: Pointer to MPT_SCSI_HOST structure
1542 * @type: Task Management type
1543 * @target: Logical Target ID for reset (if appropriate)
1544 * @lun: Logical Unit for reset (if appropriate)
1545 * @ctx2abort: Context for the task to be aborted (if appropriate)
1546 *
1547 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1548 * or a non-interrupt thread. In the former, must not call schedule().
1549 *
1550 * Not all fields are meaningfull for all task types.
1551 *
1552 * Returns 0 for SUCCESS, -999 for "no msg frames",
1553 * else other non-zero value returned.
1554 */
1555static int
1556mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1557{
1558 MPT_FRAME_HDR *mf;
1559 SCSITaskMgmt_t *pScsiTm;
1560 int ii;
1561 int retval;
1562
1563 /* Return Fail to calling function if no message frames available.
1564 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001565 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1567 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001568 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 }
1570 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1571 hd->ioc->name, mf));
1572
1573 /* Format the Request
1574 */
1575 pScsiTm = (SCSITaskMgmt_t *) mf;
1576 pScsiTm->TargetID = target;
1577 pScsiTm->Bus = channel;
1578 pScsiTm->ChainOffset = 0;
1579 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1580
1581 pScsiTm->Reserved = 0;
1582 pScsiTm->TaskType = type;
1583 pScsiTm->Reserved1 = 0;
1584 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1585 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1586
1587 for (ii= 0; ii < 8; ii++) {
1588 pScsiTm->LUN[ii] = 0;
1589 }
1590 pScsiTm->LUN[1] = lun;
1591
1592 for (ii=0; ii < 7; ii++)
1593 pScsiTm->Reserved2[ii] = 0;
1594
1595 pScsiTm->TaskMsgContext = ctx2abort;
1596
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001597 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1598 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
1600 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1601
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001602 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1604 CAN_SLEEP)) != 0) {
1605 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1606 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1607 hd->ioc, mf));
1608 mpt_free_msg_frame(hd->ioc, mf);
1609 return retval;
1610 }
1611
1612 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1613 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1614 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1615 hd->ioc, mf));
1616 mpt_free_msg_frame(hd->ioc, mf);
1617 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1618 hd->ioc->name));
1619 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1620 }
1621
1622 return retval;
1623}
1624
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001625static int
1626mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1627{
1628 switch (ioc->bus_type) {
1629 case FC:
1630 return 40;
1631 case SAS:
1632 return 10;
1633 case SPI:
1634 default:
1635 return 2;
1636 }
1637}
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1640/**
1641 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1642 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1643 *
1644 * (linux scsi_host_template.eh_abort_handler routine)
1645 *
1646 * Returns SUCCESS or FAILED.
1647 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001648int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649mptscsih_abort(struct scsi_cmnd * SCpnt)
1650{
1651 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 MPT_FRAME_HDR *mf;
1653 u32 ctx2abort;
1654 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001655 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001656 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
1658 /* If we can't locate our host adapter structure, return FAILED status.
1659 */
1660 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1661 SCpnt->result = DID_RESET << 16;
1662 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001663 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 "Can't locate host! (sc=%p)\n",
1665 SCpnt));
1666 return FAILED;
1667 }
1668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 /* Find this command
1670 */
1671 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001672 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 * Do OS callback.
1674 */
1675 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001676 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 "Command not in the active list! (sc=%p)\n",
1678 hd->ioc->name, SCpnt));
1679 return SUCCESS;
1680 }
1681
Moore, Eric65207fe2006-04-21 16:14:35 -06001682 if (hd->resetPending) {
1683 return FAILED;
1684 }
1685
1686 if (hd->timeouts < -1)
1687 hd->timeouts++;
1688
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001689 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1690 hd->ioc->name, SCpnt);
1691 scsi_print_command(SCpnt);
1692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1694 * (the IO to be ABORT'd)
1695 *
1696 * NOTE: Since we do not byteswap MsgContext, we do not
1697 * swap it here either. It is an opaque cookie to
1698 * the controller, so it does not matter. -DaveM
1699 */
1700 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1701 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1702
1703 hd->abortSCpnt = SCpnt;
1704
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001705 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001706 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric914c2d82006-03-14 09:19:36 -07001707 vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001708 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001710 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1711 hd->ioc->name,
1712 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001714 if (retval == 0)
1715 return SUCCESS;
1716
1717 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 hd->tmPending = 0;
1719 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001721 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
1723
1724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1725/**
1726 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1727 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1728 *
1729 * (linux scsi_host_template.eh_dev_reset_handler routine)
1730 *
1731 * Returns SUCCESS or FAILED.
1732 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001733int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1735{
1736 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001737 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001738 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 /* If we can't locate our host adapter structure, return FAILED status.
1741 */
1742 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001743 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 "Can't locate host! (sc=%p)\n",
1745 SCpnt));
1746 return FAILED;
1747 }
1748
1749 if (hd->resetPending)
1750 return FAILED;
1751
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001752 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001754 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001756 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001757 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -07001758 vdev->vtarget->bus_id, vdev->vtarget->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001759 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001760
1761 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1762 hd->ioc->name,
1763 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1764
1765 if (retval == 0)
1766 return SUCCESS;
1767
1768 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 hd->tmPending = 0;
1770 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001772 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773}
1774
1775/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1776/**
1777 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1778 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1779 *
1780 * (linux scsi_host_template.eh_bus_reset_handler routine)
1781 *
1782 * Returns SUCCESS or FAILED.
1783 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001784int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1786{
1787 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001788 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001789 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 /* If we can't locate our host adapter structure, return FAILED status.
1792 */
1793 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001794 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 "Can't locate host! (sc=%p)\n",
1796 SCpnt ) );
1797 return FAILED;
1798 }
1799
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001802 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 if (hd->timeouts < -1)
1805 hd->timeouts++;
1806
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001807 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001808 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric914c2d82006-03-14 09:19:36 -07001809 vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001811 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1812 hd->ioc->name,
1813 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1814
1815 if (retval == 0)
1816 return SUCCESS;
1817
1818 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 hd->tmPending = 0;
1820 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001822 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823}
1824
1825/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1826/**
1827 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1828 * new_eh variant
1829 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1830 *
1831 * (linux scsi_host_template.eh_host_reset_handler routine)
1832 *
1833 * Returns SUCCESS or FAILED.
1834 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001835int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1837{
1838 MPT_SCSI_HOST * hd;
1839 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 /* If we can't locate the host to reset, then we failed. */
1842 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001843 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 "Can't locate host! (sc=%p)\n",
1845 SCpnt ) );
1846 return FAILED;
1847 }
1848
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001849 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 hd->ioc->name, SCpnt);
1851
1852 /* If our attempts to reset the host failed, then return a failed
1853 * status. The host will be taken off line by the SCSI mid-layer.
1854 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1856 status = FAILED;
1857 } else {
1858 /* Make sure TM pending is cleared and TM state is set to
1859 * NONE.
1860 */
1861 hd->tmPending = 0;
1862 hd->tmState = TM_STATE_NONE;
1863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001865 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 "Status = %s\n",
1867 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1868
1869 return status;
1870}
1871
1872/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1873/**
1874 * mptscsih_tm_pending_wait - wait for pending task management request to
1875 * complete.
1876 * @hd: Pointer to MPT host structure.
1877 *
1878 * Returns {SUCCESS,FAILED}.
1879 */
1880static int
1881mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1882{
1883 unsigned long flags;
1884 int loop_count = 4 * 10; /* Wait 10 seconds */
1885 int status = FAILED;
1886
1887 do {
1888 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1889 if (hd->tmState == TM_STATE_NONE) {
1890 hd->tmState = TM_STATE_IN_PROGRESS;
1891 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001893 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 break;
1895 }
1896 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1897 msleep(250);
1898 } while (--loop_count);
1899
1900 return status;
1901}
1902
1903/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1904/**
1905 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1906 * @hd: Pointer to MPT host structure.
1907 *
1908 * Returns {SUCCESS,FAILED}.
1909 */
1910static int
1911mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1912{
1913 unsigned long flags;
1914 int loop_count = 4 * timeout;
1915 int status = FAILED;
1916
1917 do {
1918 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1919 if(hd->tmPending == 0) {
1920 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001921 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 break;
1923 }
1924 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05001925 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 } while (--loop_count);
1927
1928 return status;
1929}
1930
1931/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07001932static void
1933mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1934{
1935 char *desc;
1936
1937 switch (response_code) {
1938 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1939 desc = "The task completed.";
1940 break;
1941 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1942 desc = "The IOC received an invalid frame status.";
1943 break;
1944 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1945 desc = "The task type is not supported.";
1946 break;
1947 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1948 desc = "The requested task failed.";
1949 break;
1950 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1951 desc = "The task completed successfully.";
1952 break;
1953 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1954 desc = "The LUN request is invalid.";
1955 break;
1956 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1957 desc = "The task is in the IOC queue and has not been sent to target.";
1958 break;
1959 default:
1960 desc = "unknown";
1961 break;
1962 }
1963 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
1964 ioc->name, response_code, desc);
1965}
1966
1967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968/**
1969 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
1970 * @ioc: Pointer to MPT_ADAPTER structure
1971 * @mf: Pointer to SCSI task mgmt request frame
1972 * @mr: Pointer to SCSI task mgmt reply frame
1973 *
1974 * This routine is called from mptbase.c::mpt_interrupt() at the completion
1975 * of any SCSI task management request.
1976 * This routine is registered with the MPT (base) driver at driver
1977 * load/init time via the mpt_register() API call.
1978 *
1979 * Returns 1 indicating alloc'd request frame ptr should be freed.
1980 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001981int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
1983{
1984 SCSITaskMgmtReply_t *pScsiTmReply;
1985 SCSITaskMgmt_t *pScsiTmReq;
1986 MPT_SCSI_HOST *hd;
1987 unsigned long flags;
1988 u16 iocstatus;
1989 u8 tmType;
1990
1991 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
1992 ioc->name, mf, mr));
1993 if (ioc->sh) {
1994 /* Depending on the thread, a timer is activated for
1995 * the TM request. Delete this timer on completion of TM.
1996 * Decrement count of outstanding TM requests.
1997 */
1998 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
1999 } else {
2000 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2001 ioc->name));
2002 return 1;
2003 }
2004
2005 if (mr == NULL) {
2006 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2007 ioc->name, mf));
2008 return 1;
2009 } else {
2010 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2011 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2012
2013 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2014 tmType = pScsiTmReq->TaskType;
2015
Moore, Eric9f63bb72006-01-16 18:53:26 -07002016 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2017 pScsiTmReply->ResponseCode)
2018 mptscsih_taskmgmt_response_code(ioc,
2019 pScsiTmReply->ResponseCode);
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2022 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2023 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2024
2025 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2026 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2027 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2028 /* Error? (anything non-zero?) */
2029 if (iocstatus) {
2030
2031 /* clear flags and continue.
2032 */
2033 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2034 hd->abortSCpnt = NULL;
2035
2036 /* If an internal command is present
2037 * or the TM failed - reload the FW.
2038 * FC FW may respond FAILED to an ABORT
2039 */
2040 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2041 if ((hd->cmdPtr) ||
2042 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2043 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2044 printk((KERN_WARNING
2045 " Firmware Reload FAILED!!\n"));
2046 }
2047 }
2048 }
2049 } else {
2050 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2051
2052 hd->abortSCpnt = NULL;
2053
2054 }
2055 }
2056
2057 spin_lock_irqsave(&ioc->FreeQlock, flags);
2058 hd->tmPending = 0;
2059 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2060 hd->tmState = TM_STATE_NONE;
2061
2062 return 1;
2063}
2064
2065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2066/*
2067 * This is anyones guess quite frankly.
2068 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002069int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2071 sector_t capacity, int geom[])
2072{
2073 int heads;
2074 int sectors;
2075 sector_t cylinders;
2076 ulong dummy;
2077
2078 heads = 64;
2079 sectors = 32;
2080
2081 dummy = heads * sectors;
2082 cylinders = capacity;
2083 sector_div(cylinders,dummy);
2084
2085 /*
2086 * Handle extended translation size for logical drives
2087 * > 1Gb
2088 */
2089 if ((ulong)capacity >= 0x200000) {
2090 heads = 255;
2091 sectors = 63;
2092 dummy = heads * sectors;
2093 cylinders = capacity;
2094 sector_div(cylinders,dummy);
2095 }
2096
2097 /* return result */
2098 geom[0] = heads;
2099 geom[1] = sectors;
2100 geom[2] = cylinders;
2101
2102 dprintk((KERN_NOTICE
2103 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2104 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2105
2106 return 0;
2107}
2108
Moore, Ericf44e5462006-03-14 09:14:21 -07002109/* Search IOC page 3 to determine if this is hidden physical disk
2110 *
2111 */
2112int
2113mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2114{
2115 int i;
2116
2117 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2118 return 0;
2119 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2120 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2121 return 1;
2122 }
2123 return 0;
2124}
2125EXPORT_SYMBOL(mptscsih_is_phys_disk);
2126
James Bottomleyc92f2222006-03-01 09:02:49 -06002127int
2128mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2129{
2130 int i;
2131
2132 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2133 return -ENXIO;
2134
2135 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2136 if (physdiskid ==
2137 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2138 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2139 }
2140
2141 return -ENXIO;
2142}
2143EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2146/*
2147 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002148 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002151int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002152mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002154 VirtTarget *vtarget;
2155
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002156 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002157 if (!vtarget)
2158 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002159 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002160 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002161 return 0;
2162}
2163
2164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2165/*
2166 * OS entry point to allow host driver to alloc memory
2167 * for each scsi device. Called once per device the bus scan.
2168 * Return non-zero if allocation fails.
2169 */
2170int
2171mptscsih_slave_alloc(struct scsi_device *sdev)
2172{
2173 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002175 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002177 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002179 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 if (!vdev) {
2181 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2182 hd->ioc->name, sizeof(VirtDevice));
2183 return -ENOMEM;
2184 }
2185
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002186 vdev->lun = sdev->lun;
2187 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002189 starget = scsi_target(sdev);
2190 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002191
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002192 vdev->vtarget = vtarget;
2193
2194 if (vtarget->num_luns == 0) {
2195 hd->Targets[sdev->id] = vtarget;
2196 vtarget->ioc_id = hd->ioc->id;
2197 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2198 vtarget->target_id = sdev->id;
2199 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002200 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2201 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2202 vtarget->raidVolume = 1;
2203 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002204 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002205 }
2206 }
2207 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 return 0;
2209}
2210
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211/*
2212 * OS entry point to allow for host driver to free allocated memory
2213 * Called if no device present or device being unloaded
2214 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002215void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002216mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002218 if (starget->hostdata)
2219 kfree(starget->hostdata);
2220 starget->hostdata = NULL;
2221}
2222
2223/*
2224 * OS entry point to allow for host driver to free allocated memory
2225 * Called if no device present or device being unloaded
2226 */
2227void
2228mptscsih_slave_destroy(struct scsi_device *sdev)
2229{
2230 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002232 VirtTarget *vtarget;
2233 VirtDevice *vdevice;
2234 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002236 starget = scsi_target(sdev);
2237 vtarget = starget->hostdata;
2238 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002240 mptscsih_search_running_cmds(hd, vdevice);
2241 vtarget->luns[0] &= ~(1 << vdevice->lun);
2242 vtarget->num_luns--;
2243 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002244 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002246 mptscsih_synchronize_cache(hd, vdevice);
2247 kfree(vdevice);
2248 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249}
2250
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002251/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2252/*
2253 * mptscsih_change_queue_depth - This function will set a devices queue depth
2254 * @sdev: per scsi_device pointer
2255 * @qdepth: requested queue depth
2256 *
2257 * Adding support for new 'change_queue_depth' api.
2258*/
2259int
2260mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002262 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2263 VirtTarget *vtarget;
2264 struct scsi_target *starget;
2265 int max_depth;
2266 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002268 starget = scsi_target(sdev);
2269 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002270
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002271 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002272 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002274 else if (sdev->type == TYPE_DISK &&
2275 vtarget->minSyncFactor <= MPT_ULTRA160)
2276 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2277 else
2278 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 } else
2280 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2281
2282 if (qdepth > max_depth)
2283 qdepth = max_depth;
2284 if (qdepth == 1)
2285 tagged = 0;
2286 else
2287 tagged = MSG_SIMPLE_TAG;
2288
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002289 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2290 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291}
2292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293/*
2294 * OS entry point to adjust the queue_depths on a per-device basis.
2295 * Called once per device the bus scan. Use it to force the queue_depth
2296 * member to 1 if a device does not support Q tags.
2297 * Return non-zero if fails.
2298 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002299int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002300mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002302 struct Scsi_Host *sh = sdev->host;
2303 VirtTarget *vtarget;
2304 VirtDevice *vdevice;
2305 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002307 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002309 starget = scsi_target(sdev);
2310 vtarget = starget->hostdata;
2311 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 dsprintk((MYIOC_s_INFO_FMT
2314 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002315 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2316 if (hd->ioc->bus_type == SPI)
2317 dsprintk((MYIOC_s_INFO_FMT
2318 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2319 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2320 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 goto slave_configure_exit;
2326 }
2327
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002328 vdevice->configured_lun=1;
2329 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2330 indexed_lun = (vdevice->lun % 32);
2331 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002332 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002333 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334
2335 dsprintk((MYIOC_s_INFO_FMT
2336 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002337 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002339 if (hd->ioc->bus_type == SPI)
2340 dsprintk((MYIOC_s_INFO_FMT
2341 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2342 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2343 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345slave_configure_exit:
2346
2347 dsprintk((MYIOC_s_INFO_FMT
2348 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002349 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2350 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
2352 return 0;
2353}
2354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2356/*
2357 * Private routines...
2358 */
2359
2360/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2361/* Utility function to copy sense data from the scsi_cmnd buffer
2362 * to the FC and SCSI target structures.
2363 *
2364 */
2365static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002366mptscsih_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 -07002367{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 SCSIIORequest_t *pReq;
2370 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 /* Get target structure
2373 */
2374 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002375 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
2377 if (sense_count) {
2378 u8 *sense_data;
2379 int req_index;
2380
2381 /* Copy the sense received into the scsi command block. */
2382 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2383 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2384 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2385
2386 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2387 */
2388 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002389 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 int idx;
2391 MPT_ADAPTER *ioc = hd->ioc;
2392
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002393 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2395 ioc->events[idx].eventContext = ioc->eventContext;
2396
2397 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2398 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002399 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2402
2403 ioc->eventContext++;
2404 }
2405 }
2406 } else {
2407 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2408 hd->ioc->name));
2409 }
2410}
2411
2412static u32
2413SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2414{
2415 MPT_SCSI_HOST *hd;
2416 int i;
2417
2418 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2419
2420 for (i = 0; i < hd->ioc->req_depth; i++) {
2421 if (hd->ScsiLookup[i] == sc) {
2422 return i;
2423 }
2424 }
2425
2426 return -1;
2427}
2428
2429/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002430int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2432{
2433 MPT_SCSI_HOST *hd;
2434 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002435 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
2437 dtmprintk((KERN_WARNING MYNAM
2438 ": IOC %s_reset routed to SCSI host driver!\n",
2439 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2440 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2441
2442 /* If a FW reload request arrives after base installed but
2443 * before all scsi hosts have been attached, then an alt_ioc
2444 * may have a NULL sh pointer.
2445 */
2446 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2447 return 0;
2448 else
2449 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2450
2451 if (reset_phase == MPT_IOC_SETUP_RESET) {
2452 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2453
2454 /* Clean Up:
2455 * 1. Set Hard Reset Pending Flag
2456 * All new commands go to doneQ
2457 */
2458 hd->resetPending = 1;
2459
2460 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2461 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2462
2463 /* 2. Flush running commands
2464 * Clean ScsiLookup (and associated memory)
2465 * AND clean mytaskQ
2466 */
2467
2468 /* 2b. Reply to OS all known outstanding I/O commands.
2469 */
2470 mptscsih_flush_running_cmds(hd);
2471
2472 /* 2c. If there was an internal command that
2473 * has not completed, configuration or io request,
2474 * free these resources.
2475 */
2476 if (hd->cmdPtr) {
2477 del_timer(&hd->timer);
2478 mpt_free_msg_frame(ioc, hd->cmdPtr);
2479 }
2480
2481 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2482
2483 } else {
2484 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2485
2486 /* Once a FW reload begins, all new OS commands are
2487 * redirected to the doneQ w/ a reset status.
2488 * Init all control structures.
2489 */
2490
2491 /* ScsiLookup initialization
2492 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002493 for (ii=0; ii < hd->ioc->req_depth; ii++)
2494 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
2496 /* 2. Chain Buffer initialization
2497 */
2498
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002499 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
2502 /* 5. Enable new commands to be posted
2503 */
2504 spin_lock_irqsave(&ioc->FreeQlock, flags);
2505 hd->tmPending = 0;
2506 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2507 hd->resetPending = 0;
2508 hd->tmState = TM_STATE_NONE;
2509
2510 /* 6. If there was an internal command,
2511 * wake this process up.
2512 */
2513 if (hd->cmdPtr) {
2514 /*
2515 * Wake up the original calling thread
2516 */
2517 hd->pLocal = &hd->localReply;
2518 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002519 hd->scandv_wait_done = 1;
2520 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 hd->cmdPtr = NULL;
2522 }
2523
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2525
2526 }
2527
2528 return 1; /* currently means nothing really */
2529}
2530
2531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002532int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2534{
2535 MPT_SCSI_HOST *hd;
2536 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2537
Moore, Eric3a892be2006-03-14 09:14:03 -07002538 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 ioc->name, event));
2540
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002541 if (ioc->sh == NULL ||
2542 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2543 return 1;
2544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 switch (event) {
2546 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2547 /* FIXME! */
2548 break;
2549 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2550 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002551 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002552 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 break;
2554 case MPI_EVENT_LOGOUT: /* 09 */
2555 /* FIXME! */
2556 break;
2557
Michael Reed05e8ec12006-01-13 14:31:54 -06002558 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002559 break;
2560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 /*
2562 * CHECKME! Don't think we need to do
2563 * anything for these, but...
2564 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2566 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2567 /*
2568 * CHECKME! Falling thru...
2569 */
2570 break;
2571
2572 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002573 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 case MPI_EVENT_NONE: /* 00 */
2576 case MPI_EVENT_LOG_DATA: /* 01 */
2577 case MPI_EVENT_STATE_CHANGE: /* 02 */
2578 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2579 default:
2580 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2581 break;
2582 }
2583
2584 return 1; /* currently means nothing really */
2585}
2586
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2588/*
2589 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2590 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002591 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002592 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 *
2594 * NOTE: It's only SAFE to call this routine if data points to
2595 * sane & valid STANDARD INQUIRY data!
2596 *
2597 * Allocate and initialize memory for this target.
2598 * Save inquiry data.
2599 *
2600 */
2601static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002602mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2603 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002606 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 /* Is LUN supported? If so, upper 2 bits will be 0
2609 * in first byte of inquiry data.
2610 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002611 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 return;
2613
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002614 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
James Bottomleyc92f2222006-03-01 09:02:49 -06002617 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002619 if (hd->ioc->bus_type != SPI)
2620 return;
2621
James Bottomleyc92f2222006-03-01 09:02:49 -06002622 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002623 /* Treat all Processors as SAF-TE if
2624 * command line option is set */
2625 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2626 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002627 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002628 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002629 if (sdev->inquiry_len > 49 ) {
2630 if (sdev->inquiry[44] == 'S' &&
2631 sdev->inquiry[45] == 'A' &&
2632 sdev->inquiry[46] == 'F' &&
2633 sdev->inquiry[47] == '-' &&
2634 sdev->inquiry[48] == 'T' &&
2635 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002636 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2637 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 }
2639 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002640 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002641 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642}
2643
2644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2645/*
2646 * Update the target negotiation parameters based on the
2647 * the Inquiry data, adapter capabilities, and NVRAM settings.
2648 *
2649 */
2650static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002651mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2652 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002654 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 int id = (int) target->target_id;
2656 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 u8 width = MPT_NARROW;
2658 u8 factor = MPT_ASYNC;
2659 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002660 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 u8 noQas = 1;
2662
2663 target->negoFlags = pspi_data->noQas;
2664
James Bottomleyc92f2222006-03-01 09:02:49 -06002665 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
James Bottomleyc92f2222006-03-01 09:02:49 -06002667 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 width = 0;
2669 factor = MPT_ULTRA2;
2670 offset = pspi_data->maxSyncOffset;
2671 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2672 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002673 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 width = 1;
2675 }
2676
James Bottomleyc92f2222006-03-01 09:02:49 -06002677 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002679 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002681 else {
2682 if (!scsi_device_ius(sdev) &&
2683 !scsi_device_qas(sdev))
2684 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002686 factor = MPT_ULTRA320;
2687 if (scsi_device_qas(sdev)) {
2688 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2689 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002691 if (sdev->type == TYPE_TAPE &&
2692 scsi_device_ius(sdev))
2693 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 offset = pspi_data->maxSyncOffset;
2697
2698 /* If RAID, never disable QAS
2699 * else if non RAID, do not disable
2700 * QAS if bit 1 is set
2701 * bit 1 QAS support, non-raid only
2702 * bit 0 IU support
2703 */
2704 if (target->raidVolume == 1) {
2705 noQas = 0;
2706 }
2707 } else {
2708 factor = MPT_ASYNC;
2709 offset = 0;
2710 }
2711 }
2712
James Bottomleyc92f2222006-03-01 09:02:49 -06002713 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2715 }
2716
2717 /* Update tflags based on NVRAM settings. (SCSI only)
2718 */
2719 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2720 nvram = pspi_data->nvram[id];
2721 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2722
2723 if (width)
2724 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2725
2726 if (offset > 0) {
2727 /* Ensure factor is set to the
2728 * maximum of: adapter, nvram, inquiry
2729 */
2730 if (nfactor) {
2731 if (nfactor < pspi_data->minSyncFactor )
2732 nfactor = pspi_data->minSyncFactor;
2733
2734 factor = max(factor, nfactor);
2735 if (factor == MPT_ASYNC)
2736 offset = 0;
2737 } else {
2738 offset = 0;
2739 factor = MPT_ASYNC;
2740 }
2741 } else {
2742 factor = MPT_ASYNC;
2743 }
2744 }
2745
2746 /* Make sure data is consistent
2747 */
2748 if ((!width) && (factor < MPT_ULTRA2)) {
2749 factor = MPT_ULTRA2;
2750 }
2751
2752 /* Save the data to the target structure.
2753 */
2754 target->minSyncFactor = factor;
2755 target->maxOffset = offset;
2756 target->maxWidth = width;
2757
2758 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2759
2760 /* Disable unused features.
2761 */
2762 if (!width)
2763 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2764
2765 if (!offset)
2766 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2767
2768 if ( factor > MPT_ULTRA320 )
2769 noQas = 0;
2770
James Bottomleyc92f2222006-03-01 09:02:49 -06002771 if (noQas && (pspi_data->noQas == 0)) {
2772 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2773 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
James Bottomleyc92f2222006-03-01 09:02:49 -06002775 /* Disable QAS in a mixed configuration case
2776 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777
James Bottomleyc92f2222006-03-01 09:02:49 -06002778 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 }
2780}
2781
2782/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2785/*
2786 * SCSI Config Page functionality ...
2787 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790/* mptscsih_writeIOCPage4 - write IOC Page 4
2791 * @hd: Pointer to a SCSI Host Structure
2792 * @target_id: write IOC Page4 for this ID & Bus
2793 *
2794 * Return: -EAGAIN if unable to obtain a Message Frame
2795 * or 0 if success.
2796 *
2797 * Remark: We do not wait for a return, write pages sequentially.
2798 */
2799static int
2800mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2801{
2802 MPT_ADAPTER *ioc = hd->ioc;
2803 Config_t *pReq;
2804 IOCPage4_t *IOCPage4Ptr;
2805 MPT_FRAME_HDR *mf;
2806 dma_addr_t dataDma;
2807 u16 req_idx;
2808 u32 frameOffset;
2809 u32 flagsLength;
2810 int ii;
2811
2812 /* Get a MF for this command.
2813 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002814 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002815 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 ioc->name));
2817 return -EAGAIN;
2818 }
2819
2820 /* Set the request and the data pointers.
2821 * Place data at end of MF.
2822 */
2823 pReq = (Config_t *)mf;
2824
2825 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2826 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2827
2828 /* Complete the request frame (same for all requests).
2829 */
2830 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2831 pReq->Reserved = 0;
2832 pReq->ChainOffset = 0;
2833 pReq->Function = MPI_FUNCTION_CONFIG;
2834 pReq->ExtPageLength = 0;
2835 pReq->ExtPageType = 0;
2836 pReq->MsgFlags = 0;
2837 for (ii=0; ii < 8; ii++) {
2838 pReq->Reserved2[ii] = 0;
2839 }
2840
2841 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2842 dataDma = ioc->spi_data.IocPg4_dma;
2843 ii = IOCPage4Ptr->ActiveSEP++;
2844 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2845 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2846 pReq->Header = IOCPage4Ptr->Header;
2847 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2848
2849 /* Add a SGE to the config request.
2850 */
2851 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2852 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2853
2854 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2855
2856 dinitprintk((MYIOC_s_INFO_FMT
2857 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2858 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2859
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002860 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 return 0;
2863}
2864
2865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2866/*
2867 * Bus Scan and Domain Validation functionality ...
2868 */
2869
2870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2871/*
2872 * mptscsih_scandv_complete - Scan and DV callback routine registered
2873 * to Fustion MPT (base) driver.
2874 *
2875 * @ioc: Pointer to MPT_ADAPTER structure
2876 * @mf: Pointer to original MPT request frame
2877 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2878 *
2879 * This routine is called from mpt.c::mpt_interrupt() at the completion
2880 * of any SCSI IO request.
2881 * This routine is registered with the Fusion MPT (base) driver at driver
2882 * load/init time via the mpt_register() API call.
2883 *
2884 * Returns 1 indicating alloc'd request frame ptr should be freed.
2885 *
2886 * Remark: Sets a completion code and (possibly) saves sense data
2887 * in the IOC member localReply structure.
2888 * Used ONLY for DV and other internal commands.
2889 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002890int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2892{
2893 MPT_SCSI_HOST *hd;
2894 SCSIIORequest_t *pReq;
2895 int completionCode;
2896 u16 req_idx;
2897
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002898 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2899
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 if ((mf == NULL) ||
2901 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2902 printk(MYIOC_s_ERR_FMT
2903 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2904 ioc->name, mf?"BAD":"NULL", (void *) mf);
2905 goto wakeup;
2906 }
2907
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 del_timer(&hd->timer);
2909 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2910 hd->ScsiLookup[req_idx] = NULL;
2911 pReq = (SCSIIORequest_t *) mf;
2912
2913 if (mf != hd->cmdPtr) {
2914 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2915 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2916 }
2917 hd->cmdPtr = NULL;
2918
2919 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2920 hd->ioc->name, mf, mr, req_idx));
2921
2922 hd->pLocal = &hd->localReply;
2923 hd->pLocal->scsiStatus = 0;
2924
2925 /* If target struct exists, clear sense valid flag.
2926 */
2927 if (mr == NULL) {
2928 completionCode = MPT_SCANDV_GOOD;
2929 } else {
2930 SCSIIOReply_t *pReply;
2931 u16 status;
2932 u8 scsi_status;
2933
2934 pReply = (SCSIIOReply_t *) mr;
2935
2936 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2937 scsi_status = pReply->SCSIStatus;
2938
2939 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2940 status, pReply->SCSIState, scsi_status,
2941 le32_to_cpu(pReply->IOCLogInfo)));
2942
2943 switch(status) {
2944
2945 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2946 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2947 break;
2948
2949 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2950 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2951 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2952 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2953 completionCode = MPT_SCANDV_DID_RESET;
2954 break;
2955
2956 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2957 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2958 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2959 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2960 ConfigReply_t *pr = (ConfigReply_t *)mr;
2961 completionCode = MPT_SCANDV_GOOD;
2962 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2963 hd->pLocal->header.PageLength = pr->Header.PageLength;
2964 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2965 hd->pLocal->header.PageType = pr->Header.PageType;
2966
2967 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2968 /* If the RAID Volume request is successful,
2969 * return GOOD, else indicate that
2970 * some type of error occurred.
2971 */
2972 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002973 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 completionCode = MPT_SCANDV_GOOD;
2975 else
2976 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002977 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
2979 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2980 u8 *sense_data;
2981 int sz;
2982
2983 /* save sense data in global structure
2984 */
2985 completionCode = MPT_SCANDV_SENSE;
2986 hd->pLocal->scsiStatus = scsi_status;
2987 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2988 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2989
2990 sz = min_t(int, pReq->SenseBufferLength,
2991 SCSI_STD_SENSE_BYTES);
2992 memcpy(hd->pLocal->sense, sense_data, sz);
2993
2994 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2995 sense_data));
2996 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2997 if (pReq->CDB[0] == INQUIRY)
2998 completionCode = MPT_SCANDV_ISSUE_SENSE;
2999 else
3000 completionCode = MPT_SCANDV_DID_RESET;
3001 }
3002 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3003 completionCode = MPT_SCANDV_DID_RESET;
3004 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3005 completionCode = MPT_SCANDV_DID_RESET;
3006 else {
3007 completionCode = MPT_SCANDV_GOOD;
3008 hd->pLocal->scsiStatus = scsi_status;
3009 }
3010 break;
3011
3012 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3013 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3014 completionCode = MPT_SCANDV_DID_RESET;
3015 else
3016 completionCode = MPT_SCANDV_SOME_ERROR;
3017 break;
3018
3019 default:
3020 completionCode = MPT_SCANDV_SOME_ERROR;
3021 break;
3022
3023 } /* switch(status) */
3024
3025 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3026 completionCode));
3027 } /* end of address reply case */
3028
3029 hd->pLocal->completion = completionCode;
3030
3031 /* MF and RF are freed in mpt_interrupt
3032 */
3033wakeup:
3034 /* Free Chain buffers (will never chain) in scan or dv */
3035 //mptscsih_freeChainBuffers(ioc, req_idx);
3036
3037 /*
3038 * Wake up the original calling thread
3039 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003040 hd->scandv_wait_done = 1;
3041 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
3043 return 1;
3044}
3045
3046/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3047/* mptscsih_timer_expired - Call back for timer process.
3048 * Used only for dv functionality.
3049 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3050 *
3051 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003052void
3053mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054{
3055 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3056
3057 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3058
3059 if (hd->cmdPtr) {
3060 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3061
3062 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3063 /* Desire to issue a task management request here.
3064 * TM requests MUST be single threaded.
3065 * If old eh code and no TM current, issue request.
3066 * If new eh code, do nothing. Wait for OS cmd timeout
3067 * for bus reset.
3068 */
3069 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3070 } else {
3071 /* Perform a FW reload */
3072 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3073 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3074 }
3075 }
3076 } else {
3077 /* This should NEVER happen */
3078 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3079 }
3080
3081 /* No more processing.
3082 * TM call will generate an interrupt for SCSI TM Management.
3083 * The FW will reply to all outstanding commands, callback will finish cleanup.
3084 * Hard reset clean-up will free all resources.
3085 */
3086 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3087
3088 return;
3089}
3090
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
3092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3093/**
3094 * mptscsih_do_cmd - Do internal command.
3095 * @hd: MPT_SCSI_HOST pointer
3096 * @io: INTERNAL_CMD pointer.
3097 *
3098 * Issue the specified internally generated command and do command
3099 * specific cleanup. For bus scan / DV only.
3100 * NOTES: If command is Inquiry and status is good,
3101 * initialize a target structure, save the data
3102 *
3103 * Remark: Single threaded access only.
3104 *
3105 * Return:
3106 * < 0 if an illegal command or no resources
3107 *
3108 * 0 if good
3109 *
3110 * > 0 if command complete but some type of completion error.
3111 */
3112static int
3113mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3114{
3115 MPT_FRAME_HDR *mf;
3116 SCSIIORequest_t *pScsiReq;
3117 SCSIIORequest_t ReqCopy;
3118 int my_idx, ii, dir;
3119 int rc, cmdTimeout;
3120 int in_isr;
3121 char cmdLen;
3122 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3123 char cmd = io->cmd;
3124
3125 in_isr = in_interrupt();
3126 if (in_isr) {
3127 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3128 hd->ioc->name));
3129 return -EPERM;
3130 }
3131
3132
3133 /* Set command specific information
3134 */
3135 switch (cmd) {
3136 case INQUIRY:
3137 cmdLen = 6;
3138 dir = MPI_SCSIIO_CONTROL_READ;
3139 CDB[0] = cmd;
3140 CDB[4] = io->size;
3141 cmdTimeout = 10;
3142 break;
3143
3144 case TEST_UNIT_READY:
3145 cmdLen = 6;
3146 dir = MPI_SCSIIO_CONTROL_READ;
3147 cmdTimeout = 10;
3148 break;
3149
3150 case START_STOP:
3151 cmdLen = 6;
3152 dir = MPI_SCSIIO_CONTROL_READ;
3153 CDB[0] = cmd;
3154 CDB[4] = 1; /*Spin up the disk */
3155 cmdTimeout = 15;
3156 break;
3157
3158 case REQUEST_SENSE:
3159 cmdLen = 6;
3160 CDB[0] = cmd;
3161 CDB[4] = io->size;
3162 dir = MPI_SCSIIO_CONTROL_READ;
3163 cmdTimeout = 10;
3164 break;
3165
3166 case READ_BUFFER:
3167 cmdLen = 10;
3168 dir = MPI_SCSIIO_CONTROL_READ;
3169 CDB[0] = cmd;
3170 if (io->flags & MPT_ICFLAG_ECHO) {
3171 CDB[1] = 0x0A;
3172 } else {
3173 CDB[1] = 0x02;
3174 }
3175
3176 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3177 CDB[1] |= 0x01;
3178 }
3179 CDB[6] = (io->size >> 16) & 0xFF;
3180 CDB[7] = (io->size >> 8) & 0xFF;
3181 CDB[8] = io->size & 0xFF;
3182 cmdTimeout = 10;
3183 break;
3184
3185 case WRITE_BUFFER:
3186 cmdLen = 10;
3187 dir = MPI_SCSIIO_CONTROL_WRITE;
3188 CDB[0] = cmd;
3189 if (io->flags & MPT_ICFLAG_ECHO) {
3190 CDB[1] = 0x0A;
3191 } else {
3192 CDB[1] = 0x02;
3193 }
3194 CDB[6] = (io->size >> 16) & 0xFF;
3195 CDB[7] = (io->size >> 8) & 0xFF;
3196 CDB[8] = io->size & 0xFF;
3197 cmdTimeout = 10;
3198 break;
3199
3200 case RESERVE:
3201 cmdLen = 6;
3202 dir = MPI_SCSIIO_CONTROL_READ;
3203 CDB[0] = cmd;
3204 cmdTimeout = 10;
3205 break;
3206
3207 case RELEASE:
3208 cmdLen = 6;
3209 dir = MPI_SCSIIO_CONTROL_READ;
3210 CDB[0] = cmd;
3211 cmdTimeout = 10;
3212 break;
3213
3214 case SYNCHRONIZE_CACHE:
3215 cmdLen = 10;
3216 dir = MPI_SCSIIO_CONTROL_READ;
3217 CDB[0] = cmd;
3218// CDB[1] = 0x02; /* set immediate bit */
3219 cmdTimeout = 10;
3220 break;
3221
3222 default:
3223 /* Error Case */
3224 return -EFAULT;
3225 }
3226
3227 /* Get and Populate a free Frame
3228 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003229 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3231 hd->ioc->name));
3232 return -EBUSY;
3233 }
3234
3235 pScsiReq = (SCSIIORequest_t *) mf;
3236
3237 /* Get the request index */
3238 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3239 ADD_INDEX_LOG(my_idx); /* for debug */
3240
3241 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3242 pScsiReq->TargetID = io->physDiskNum;
3243 pScsiReq->Bus = 0;
3244 pScsiReq->ChainOffset = 0;
3245 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3246 } else {
3247 pScsiReq->TargetID = io->id;
3248 pScsiReq->Bus = io->bus;
3249 pScsiReq->ChainOffset = 0;
3250 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3251 }
3252
3253 pScsiReq->CDBLength = cmdLen;
3254 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3255
3256 pScsiReq->Reserved = 0;
3257
3258 pScsiReq->MsgFlags = mpt_msg_flags();
3259 /* MsgContext set in mpt_get_msg_fram call */
3260
3261 for (ii=0; ii < 8; ii++)
3262 pScsiReq->LUN[ii] = 0;
3263 pScsiReq->LUN[1] = io->lun;
3264
3265 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3266 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3267 else
3268 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3269
3270 if (cmd == REQUEST_SENSE) {
3271 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3272 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3273 hd->ioc->name, cmd));
3274 }
3275
3276 for (ii=0; ii < 16; ii++)
3277 pScsiReq->CDB[ii] = CDB[ii];
3278
3279 pScsiReq->DataLength = cpu_to_le32(io->size);
3280 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3281 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3282
3283 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3284 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3285
3286 if (dir == MPI_SCSIIO_CONTROL_READ) {
3287 mpt_add_sge((char *) &pScsiReq->SGL,
3288 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3289 io->data_dma);
3290 } else {
3291 mpt_add_sge((char *) &pScsiReq->SGL,
3292 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3293 io->data_dma);
3294 }
3295
3296 /* The ISR will free the request frame, but we need
3297 * the information to initialize the target. Duplicate.
3298 */
3299 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3300
3301 /* Issue this command after:
3302 * finish init
3303 * add timer
3304 * Wait until the reply has been received
3305 * ScsiScanDvCtx callback function will
3306 * set hd->pLocal;
3307 * set scandv_wait_done and call wake_up
3308 */
3309 hd->pLocal = NULL;
3310 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003311 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
3313 /* Save cmd pointer, for resource free if timeout or
3314 * FW reload occurs
3315 */
3316 hd->cmdPtr = mf;
3317
3318 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003319 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3320 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
3322 if (hd->pLocal) {
3323 rc = hd->pLocal->completion;
3324 hd->pLocal->skip = 0;
3325
3326 /* Always set fatal error codes in some cases.
3327 */
3328 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3329 rc = -ENXIO;
3330 else if (rc == MPT_SCANDV_SOME_ERROR)
3331 rc = -rc;
3332 } else {
3333 rc = -EFAULT;
3334 /* This should never happen. */
3335 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3336 hd->ioc->name));
3337 }
3338
3339 return rc;
3340}
3341
3342/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3343/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003344 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3345 * @hd: Pointer to a SCSI HOST structure
3346 * @vtarget: per device private data
3347 * @lun: lun
3348 *
3349 * Uses the ISR, but with special processing.
3350 * MUST be single-threaded.
3351 *
3352 */
3353static void
3354mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3355{
3356 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
3358 /* Following parameters will not change
3359 * in this routine.
3360 */
3361 iocmd.cmd = SYNCHRONIZE_CACHE;
3362 iocmd.flags = 0;
3363 iocmd.physDiskNum = -1;
3364 iocmd.data = NULL;
3365 iocmd.data_dma = -1;
3366 iocmd.size = 0;
3367 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003368 iocmd.bus = vdevice->vtarget->bus_id;
3369 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003370 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
James Bottomleyc92f2222006-03-01 09:02:49 -06003372 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003373 (vdevice->configured_lun))
3374 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375}
3376
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003377EXPORT_SYMBOL(mptscsih_remove);
3378EXPORT_SYMBOL(mptscsih_shutdown);
3379#ifdef CONFIG_PM
3380EXPORT_SYMBOL(mptscsih_suspend);
3381EXPORT_SYMBOL(mptscsih_resume);
3382#endif
3383EXPORT_SYMBOL(mptscsih_proc_info);
3384EXPORT_SYMBOL(mptscsih_info);
3385EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003386EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003387EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003388EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003389EXPORT_SYMBOL(mptscsih_slave_destroy);
3390EXPORT_SYMBOL(mptscsih_slave_configure);
3391EXPORT_SYMBOL(mptscsih_abort);
3392EXPORT_SYMBOL(mptscsih_dev_reset);
3393EXPORT_SYMBOL(mptscsih_bus_reset);
3394EXPORT_SYMBOL(mptscsih_host_reset);
3395EXPORT_SYMBOL(mptscsih_bios_param);
3396EXPORT_SYMBOL(mptscsih_io_done);
3397EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3398EXPORT_SYMBOL(mptscsih_scandv_complete);
3399EXPORT_SYMBOL(mptscsih_event_process);
3400EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003401EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003402EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003403EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/