blob: bc099651df73b4015fe961f24ff4752cfde074a1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04006 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * (mailto:mpt_linux_developer@lsil.com)
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include "linux_compat.h" /* linux-2.6 tweaks */
48#include <linux/module.h>
49#include <linux/kernel.h>
50#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
57#include <linux/sched.h>
58#include <linux/workqueue.h>
59
60#include <scsi/scsi.h>
61#include <scsi/scsi_cmnd.h>
62#include <scsi/scsi_device.h>
63#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060065#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060069#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
72#define my_NAME "Fusion MPT SCSI Host driver"
73#define my_VERSION MPT_LINUX_VERSION_COMMON
74#define MYNAM "mptscsih"
75
76MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
81
82typedef struct _BIG_SENSE_BUF {
83 u8 data[MPT_SENSE_BUFFER_ALLOC];
84} BIG_SENSE_BUF;
85
86#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
87#define MPT_SCANDV_DID_RESET (0x00000001)
88#define MPT_SCANDV_SENSE (0x00000002)
89#define MPT_SCANDV_SOME_ERROR (0x00000004)
90#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
91#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
92#define MPT_SCANDV_FALLBACK (0x00000020)
93
94#define MPT_SCANDV_MAX_RETRIES (10)
95
96#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
97#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
Moore, Eric Dean466544d2005-09-14 18:09:10 -060098#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
99#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
100#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
102#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
103
104typedef struct _internal_cmd {
105 char *data; /* data pointer */
106 dma_addr_t data_dma; /* data dma address */
107 int size; /* transfer size */
108 u8 cmd; /* SCSI Op Code */
109 u8 bus; /* bus number */
110 u8 id; /* SCSI ID (virtual) */
111 u8 lun;
112 u8 flags; /* Bit Field - See above */
113 u8 physDiskNum; /* Phys disk number, -1 else */
114 u8 rsvd2;
115 u8 rsvd;
116} INTERNAL_CMD;
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*
119 * Other private/forward protos...
120 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400121int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400123int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
126 SCSIIORequest_t *pReq, int req_idx);
127static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400128static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
130static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
131static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
134
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400135int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
136int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
James Bottomleyc92f2222006-03-01 09:02:49 -0600138static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
139static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400141int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700143static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400145void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700146void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400148int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
149int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150#endif
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
155/**
156 * mptscsih_add_sge - Place a simple SGE at address pAddr.
157 * @pAddr: virtual address for SGE
158 * @flagslength: SGE flags and data transfer length
159 * @dma_addr: Physical address
160 *
161 * This routine places a MPT request frame back on the MPT adapter's
162 * FreeQ.
163 */
164static inline void
165mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
166{
167 if (sizeof(dma_addr_t) == sizeof(u64)) {
168 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
169 u32 tmp = dma_addr & 0xFFFFFFFF;
170
171 pSge->FlagsLength = cpu_to_le32(flagslength);
172 pSge->Address.Low = cpu_to_le32(tmp);
173 tmp = (u32) ((u64)dma_addr >> 32);
174 pSge->Address.High = cpu_to_le32(tmp);
175
176 } else {
177 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
178 pSge->FlagsLength = cpu_to_le32(flagslength);
179 pSge->Address = cpu_to_le32(dma_addr);
180 }
181} /* mptscsih_add_sge() */
182
183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
184/**
185 * mptscsih_add_chain - Place a chain SGE at address pAddr.
186 * @pAddr: virtual address for SGE
187 * @next: nextChainOffset value (u32's)
188 * @length: length of next SGL segment
189 * @dma_addr: Physical address
190 *
191 * This routine places a MPT request frame back on the MPT adapter's
192 * FreeQ.
193 */
194static inline void
195mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
196{
197 if (sizeof(dma_addr_t) == sizeof(u64)) {
198 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
199 u32 tmp = dma_addr & 0xFFFFFFFF;
200
201 pChain->Length = cpu_to_le16(length);
202 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
203
204 pChain->NextChainOffset = next;
205
206 pChain->Address.Low = cpu_to_le32(tmp);
207 tmp = (u32) ((u64)dma_addr >> 32);
208 pChain->Address.High = cpu_to_le32(tmp);
209 } else {
210 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
211 pChain->Length = cpu_to_le16(length);
212 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
213 pChain->NextChainOffset = next;
214 pChain->Address = cpu_to_le32(dma_addr);
215 }
216} /* mptscsih_add_chain() */
217
218/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
219/*
220 * mptscsih_getFreeChainBuffer - Function to get a free chain
221 * from the MPT_SCSI_HOST FreeChainQ.
222 * @ioc: Pointer to MPT_ADAPTER structure
223 * @req_idx: Index of the SCSI IO request frame. (output)
224 *
225 * return SUCCESS or FAILED
226 */
227static inline int
228mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
229{
230 MPT_FRAME_HDR *chainBuf;
231 unsigned long flags;
232 int rc;
233 int chain_idx;
234
235 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
236 ioc->name));
237 spin_lock_irqsave(&ioc->FreeQlock, flags);
238 if (!list_empty(&ioc->FreeChainQ)) {
239 int offset;
240
241 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
242 u.frame.linkage.list);
243 list_del(&chainBuf->u.frame.linkage.list);
244 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
245 chain_idx = offset / ioc->req_sz;
246 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200247 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
248 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 } else {
250 rc = FAILED;
251 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200252 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 ioc->name));
254 }
255 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
256
257 *retIndex = chain_idx;
258 return rc;
259} /* mptscsih_getFreeChainBuffer() */
260
261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
262/*
263 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
264 * SCSIIORequest_t Message Frame.
265 * @ioc: Pointer to MPT_ADAPTER structure
266 * @SCpnt: Pointer to scsi_cmnd structure
267 * @pReq: Pointer to SCSIIORequest_t structure
268 *
269 * Returns ...
270 */
271static int
272mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
273 SCSIIORequest_t *pReq, int req_idx)
274{
275 char *psge;
276 char *chainSge;
277 struct scatterlist *sg;
278 int frm_sz;
279 int sges_left, sg_done;
280 int chain_idx = MPT_HOST_NO_CHAIN;
281 int sgeOffset;
282 int numSgeSlots, numSgeThisFrame;
283 u32 sgflags, sgdir, thisxfer = 0;
284 int chain_dma_off = 0;
285 int newIndex;
286 int ii;
287 dma_addr_t v2;
288 u32 RequestNB;
289
290 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
291 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
292 sgdir = MPT_TRANSFER_HOST_TO_IOC;
293 } else {
294 sgdir = MPT_TRANSFER_IOC_TO_HOST;
295 }
296
297 psge = (char *) &pReq->SGL;
298 frm_sz = ioc->req_sz;
299
300 /* Map the data portion, if any.
301 * sges_left = 0 if no data transfer.
302 */
303 if ( (sges_left = SCpnt->use_sg) ) {
304 sges_left = pci_map_sg(ioc->pcidev,
305 (struct scatterlist *) SCpnt->request_buffer,
306 SCpnt->use_sg,
307 SCpnt->sc_data_direction);
308 if (sges_left == 0)
309 return FAILED;
310 } else if (SCpnt->request_bufflen) {
311 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
312 SCpnt->request_buffer,
313 SCpnt->request_bufflen,
314 SCpnt->sc_data_direction);
315 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
316 ioc->name, SCpnt, SCpnt->request_bufflen));
317 mptscsih_add_sge((char *) &pReq->SGL,
318 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
319 SCpnt->SCp.dma_handle);
320
321 return SUCCESS;
322 }
323
324 /* Handle the SG case.
325 */
326 sg = (struct scatterlist *) SCpnt->request_buffer;
327 sg_done = 0;
328 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
329 chainSge = NULL;
330
331 /* Prior to entering this loop - the following must be set
332 * current MF: sgeOffset (bytes)
333 * chainSge (Null if original MF is not a chain buffer)
334 * sg_done (num SGE done for this MF)
335 */
336
337nextSGEset:
338 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
339 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
340
341 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
342
343 /* Get first (num - 1) SG elements
344 * Skip any SG entries with a length of 0
345 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
346 */
347 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
348 thisxfer = sg_dma_len(sg);
349 if (thisxfer == 0) {
350 sg ++; /* Get next SG element from the OS */
351 sg_done++;
352 continue;
353 }
354
355 v2 = sg_dma_address(sg);
356 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
357
358 sg++; /* Get next SG element from the OS */
359 psge += (sizeof(u32) + sizeof(dma_addr_t));
360 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
361 sg_done++;
362 }
363
364 if (numSgeThisFrame == sges_left) {
365 /* Add last element, end of buffer and end of list flags.
366 */
367 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
368 MPT_SGE_FLAGS_END_OF_BUFFER |
369 MPT_SGE_FLAGS_END_OF_LIST;
370
371 /* Add last SGE and set termination flags.
372 * Note: Last SGE may have a length of 0 - which should be ok.
373 */
374 thisxfer = sg_dma_len(sg);
375
376 v2 = sg_dma_address(sg);
377 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
378 /*
379 sg++;
380 psge += (sizeof(u32) + sizeof(dma_addr_t));
381 */
382 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
383 sg_done++;
384
385 if (chainSge) {
386 /* The current buffer is a chain buffer,
387 * but there is not another one.
388 * Update the chain element
389 * Offset and Length fields.
390 */
391 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
392 } else {
393 /* The current buffer is the original MF
394 * and there is no Chain buffer.
395 */
396 pReq->ChainOffset = 0;
397 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200398 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
400 ioc->RequestNB[req_idx] = RequestNB;
401 }
402 } else {
403 /* At least one chain buffer is needed.
404 * Complete the first MF
405 * - last SGE element, set the LastElement bit
406 * - set ChainOffset (words) for orig MF
407 * (OR finish previous MF chain buffer)
408 * - update MFStructPtr ChainIndex
409 * - Populate chain element
410 * Also
411 * Loop until done.
412 */
413
414 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
415 ioc->name, sg_done));
416
417 /* Set LAST_ELEMENT flag for last non-chain element
418 * in the buffer. Since psge points at the NEXT
419 * SGE element, go back one SGE element, update the flags
420 * and reset the pointer. (Note: sgflags & thisxfer are already
421 * set properly).
422 */
423 if (sg_done) {
424 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
425 sgflags = le32_to_cpu(*ptmp);
426 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
427 *ptmp = cpu_to_le32(sgflags);
428 }
429
430 if (chainSge) {
431 /* The current buffer is a chain buffer.
432 * chainSge points to the previous Chain Element.
433 * Update its chain element Offset and Length (must
434 * include chain element size) fields.
435 * Old chain element is now complete.
436 */
437 u8 nextChain = (u8) (sgeOffset >> 2);
438 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
439 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
440 } else {
441 /* The original MF buffer requires a chain buffer -
442 * set the offset.
443 * Last element in this MF is a chain element.
444 */
445 pReq->ChainOffset = (u8) (sgeOffset >> 2);
446 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
447 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
448 ioc->RequestNB[req_idx] = RequestNB;
449 }
450
451 sges_left -= sg_done;
452
453
454 /* NOTE: psge points to the beginning of the chain element
455 * in current buffer. Get a chain buffer.
456 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200457 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
458 dfailprintk((MYIOC_s_INFO_FMT
459 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
460 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 /* Update the tracking arrays.
465 * If chainSge == NULL, update ReqToChain, else ChainToChain
466 */
467 if (chainSge) {
468 ioc->ChainToChain[chain_idx] = newIndex;
469 } else {
470 ioc->ReqToChain[req_idx] = newIndex;
471 }
472 chain_idx = newIndex;
473 chain_dma_off = ioc->req_sz * chain_idx;
474
475 /* Populate the chainSGE for the current buffer.
476 * - Set chain buffer pointer to psge and fill
477 * out the Address and Flags fields.
478 */
479 chainSge = (char *) psge;
480 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
481 psge, req_idx));
482
483 /* Start the SGE for the next buffer
484 */
485 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
486 sgeOffset = 0;
487 sg_done = 0;
488
489 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
490 psge, chain_idx));
491
492 /* Start the SGE for the next buffer
493 */
494
495 goto nextSGEset;
496 }
497
498 return SUCCESS;
499} /* mptscsih_AddSGE() */
500
Eric Moore786899b2006-07-11 17:22:22 -0600501static void
502mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
503 U32 SlotStatus)
504{
505 MPT_FRAME_HDR *mf;
506 SEPRequest_t *SEPMsg;
507
508 if (ioc->bus_type == FC)
509 return;
510
511 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
512 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
513 ioc->name,__FUNCTION__));
514 return;
515 }
516
517 SEPMsg = (SEPRequest_t *)mf;
518 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
519 SEPMsg->Bus = vtarget->bus_id;
520 SEPMsg->TargetID = vtarget->target_id;
521 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
522 SEPMsg->SlotStatus = SlotStatus;
523 devtverboseprintk((MYIOC_s_WARN_FMT
524 "Sending SEP cmd=%x id=%d bus=%d\n",
525 ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
526 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
527}
528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
530/*
531 * mptscsih_io_done - Main SCSI IO callback routine registered to
532 * Fusion MPT (base) driver
533 * @ioc: Pointer to MPT_ADAPTER structure
534 * @mf: Pointer to original MPT request frame
535 * @r: Pointer to MPT reply frame (NULL if TurboReply)
536 *
537 * This routine is called from mpt.c::mpt_interrupt() at the completion
538 * of any SCSI IO request.
539 * This routine is registered with the Fusion MPT (base) driver at driver
540 * load/init time via the mpt_register() API call.
541 *
542 * Returns 1 indicating alloc'd request frame ptr should be freed.
543 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400544int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
546{
547 struct scsi_cmnd *sc;
548 MPT_SCSI_HOST *hd;
549 SCSIIORequest_t *pScsiReq;
550 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700551 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600552 VirtDevice *vdev;
553 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
556
557 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700558 req_idx_MR = (mr != NULL) ?
559 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
560 if ((req_idx != req_idx_MR) ||
561 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
562 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
563 ioc->name);
564 printk (MYIOC_s_ERR_FMT
565 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
566 ioc->name, req_idx, req_idx_MR, mf, mr,
567 hd->ScsiLookup[req_idx_MR]);
568 return 0;
569 }
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 sc = hd->ScsiLookup[req_idx];
572 if (sc == NULL) {
573 MPIHeader_t *hdr = (MPIHeader_t *)mf;
574
575 /* Remark: writeSDP1 will use the ScsiDoneCtx
576 * If a SCSI I/O cmd, device disabled by OS and
577 * completion done. Cannot touch sc struct. Just free mem.
578 */
579 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
580 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
581 ioc->name);
582
583 mptscsih_freeChainBuffers(ioc, req_idx);
584 return 1;
585 }
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 sc->result = DID_OK << 16; /* Set default reply as OK */
588 pScsiReq = (SCSIIORequest_t *) mf;
589 pScsiReply = (SCSIIOReply_t *) mr;
590
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200591 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
592 dmfprintk((MYIOC_s_INFO_FMT
593 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
594 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
595 }else{
596 dmfprintk((MYIOC_s_INFO_FMT
597 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
598 ioc->name, mf, mr, sc, req_idx));
599 }
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 if (pScsiReply == NULL) {
602 /* special context reply handling */
603 ;
604 } else {
605 u32 xfer_cnt;
606 u16 status;
607 u8 scsi_state, scsi_status;
608
609 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
610 scsi_state = pScsiReply->SCSIState;
611 scsi_status = pScsiReply->SCSIStatus;
612 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
613 sc->resid = sc->request_bufflen - xfer_cnt;
614
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600615 /*
616 * if we get a data underrun indication, yet no data was
617 * transferred and the SCSI status indicates that the
618 * command was never started, change the data underrun
619 * to success
620 */
621 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
622 (scsi_status == MPI_SCSI_STATUS_BUSY ||
623 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
624 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
625 status = MPI_IOCSTATUS_SUCCESS;
626 }
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
629 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
630 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700631 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600632 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 sc->request_bufflen, xfer_cnt));
634
635 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400636 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /*
639 * Look for + dump FCP ResponseInfo[]!
640 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600641 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
642 pScsiReply->ResponseInfo) {
643 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
644 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700645 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 le32_to_cpu(pScsiReply->ResponseInfo));
647 }
648
649 switch(status) {
650 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
651 /* CHECKME!
652 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
653 * But not: DID_BUS_BUSY lest one risk
654 * killing interrupt handler:-(
655 */
656 sc->result = SAM_STAT_BUSY;
657 break;
658
659 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
660 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
661 sc->result = DID_BAD_TARGET << 16;
662 break;
663
664 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
665 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600666 if (ioc->bus_type != FC)
667 sc->result = DID_NO_CONNECT << 16;
668 /* else fibre, just stall until rescan event */
669 else
670 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
673 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600674
675 vdev = sc->device->hostdata;
676 if (!vdev)
677 break;
678 vtarget = vdev->vtarget;
679 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
680 mptscsih_issue_sep_command(ioc, vtarget,
681 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
682 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 break;
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600687 if ( ioc->bus_type == SAS ) {
688 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
689 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
690 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
691 log_info &=SAS_LOGINFO_MASK;
692 if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
693 sc->result = (DID_BUS_BUSY << 16);
694 break;
695 }
696 }
697 }
698
699 /*
700 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
701 */
702
703 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
705 /* Linux handles an unsolicited DID_RESET better
706 * than an unsolicited DID_ABORT.
707 */
708 sc->result = DID_RESET << 16;
709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 break;
711
712 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600713 sc->resid = sc->request_bufflen - xfer_cnt;
714 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
715 sc->result=DID_SOFT_ERROR << 16;
716 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600718 dreplyprintk((KERN_NOTICE
719 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
723 /*
724 * Do upfront check for valid SenseData and give it
725 * precedence!
726 */
727 sc->result = (DID_OK << 16) | scsi_status;
728 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
729 /* Have already saved the status and sense data
730 */
731 ;
732 } else {
733 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600734 if (scsi_status == SAM_STAT_BUSY)
735 sc->result = SAM_STAT_BUSY;
736 else
737 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
739 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
740 /* What to do?
741 */
742 sc->result = DID_SOFT_ERROR << 16;
743 }
744 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
745 /* Not real sure here either... */
746 sc->result = DID_RESET << 16;
747 }
748 }
749
750 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
751 sc->underflow));
752 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
753 /* Report Queue Full
754 */
755 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
756 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 break;
759
Moore, Eric7e551472006-01-16 18:53:21 -0700760 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
761 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
763 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600764 if (scsi_status == MPI_SCSI_STATUS_BUSY)
765 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
766 else
767 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if (scsi_state == 0) {
769 ;
770 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
771 /*
772 * If running against circa 200003dd 909 MPT f/w,
773 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
774 * (QUEUE_FULL) returned from device! --> get 0x0000?128
775 * and with SenseBytes set to 0.
776 */
777 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
778 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
779
780 }
781 else if (scsi_state &
782 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
783 ) {
784 /*
785 * What to do?
786 */
787 sc->result = DID_SOFT_ERROR << 16;
788 }
789 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
790 /* Not real sure here either... */
791 sc->result = DID_RESET << 16;
792 }
793 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
794 /* Device Inq. data indicates that it supports
795 * QTags, but rejects QTag messages.
796 * This command completed OK.
797 *
798 * Not real sure here either so do nothing... */
799 }
800
801 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
802 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
803
804 /* Add handling of:
805 * Reservation Conflict, Busy,
806 * Command Terminated, CHECK
807 */
808 break;
809
810 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
811 sc->result = DID_SOFT_ERROR << 16;
812 break;
813
814 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
815 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
816 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
817 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
818 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
819 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
820 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
822 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
823 default:
824 /*
825 * What to do?
826 */
827 sc->result = DID_SOFT_ERROR << 16;
828 break;
829
830 } /* switch(status) */
831
832 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
833 } /* end of address reply case */
834
835 /* Unmap the DMA buffers, if any. */
836 if (sc->use_sg) {
837 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
838 sc->use_sg, sc->sc_data_direction);
839 } else if (sc->request_bufflen) {
840 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
841 sc->request_bufflen, sc->sc_data_direction);
842 }
843
844 hd->ScsiLookup[req_idx] = NULL;
845
846 sc->scsi_done(sc); /* Issue the command callback */
847
848 /* Free Chain buffers */
849 mptscsih_freeChainBuffers(ioc, req_idx);
850 return 1;
851}
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853/*
854 * mptscsih_flush_running_cmds - For each command found, search
855 * Scsi_Host instance taskQ and reply to OS.
856 * Called only if recovering from a FW reload.
857 * @hd: Pointer to a SCSI HOST structure
858 *
859 * Returns: None.
860 *
861 * Must be called while new I/Os are being queued.
862 */
863static void
864mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
865{
866 MPT_ADAPTER *ioc = hd->ioc;
867 struct scsi_cmnd *SCpnt;
868 MPT_FRAME_HDR *mf;
869 int ii;
870 int max = ioc->req_depth;
871
872 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
873 for (ii= 0; ii < max; ii++) {
874 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
875
876 /* Command found.
877 */
878
879 /* Null ScsiLookup index
880 */
881 hd->ScsiLookup[ii] = NULL;
882
883 mf = MPT_INDEX_2_MFPTR(ioc, ii);
884 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
885 mf, SCpnt));
886
887 /* Set status, free OS resources (SG DMA buffers)
888 * Do OS callback
889 * Free driver resources (chain, msg buffers)
890 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400891 if (SCpnt->use_sg) {
892 pci_unmap_sg(ioc->pcidev,
893 (struct scatterlist *) SCpnt->request_buffer,
894 SCpnt->use_sg,
895 SCpnt->sc_data_direction);
896 } else if (SCpnt->request_bufflen) {
897 pci_unmap_single(ioc->pcidev,
898 SCpnt->SCp.dma_handle,
899 SCpnt->request_bufflen,
900 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902 SCpnt->result = DID_RESET << 16;
903 SCpnt->host_scribble = NULL;
904
905 /* Free Chain buffers */
906 mptscsih_freeChainBuffers(ioc, ii);
907
908 /* Free Message frames */
909 mpt_free_msg_frame(ioc, mf);
910
911 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
912 }
913 }
914
915 return;
916}
917
918/*
919 * mptscsih_search_running_cmds - Delete any commands associated
920 * with the specified target and lun. Function called only
921 * when a lun is disable by mid-layer.
922 * Do NOT access the referenced scsi_cmnd structure or
923 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600924 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700925 * @hd: Pointer to a SCSI HOST structure
926 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 *
928 * Returns: None.
929 *
930 * Called from slave_destroy.
931 */
932static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700933mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
935 SCSIIORequest_t *mf = NULL;
936 int ii;
937 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600938 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Ericbd23e942006-04-17 12:43:04 -0600941 vdevice->vtarget->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600944 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
947
948 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
949 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
950
Moore, Eric914c2d82006-03-14 09:19:36 -0700951 if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 continue;
953
954 /* Cleanup
955 */
956 hd->ScsiLookup[ii] = NULL;
957 mptscsih_freeChainBuffers(hd->ioc, ii);
958 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600959 if (sc->use_sg) {
960 pci_unmap_sg(hd->ioc->pcidev,
961 (struct scatterlist *) sc->request_buffer,
962 sc->use_sg,
963 sc->sc_data_direction);
964 } else if (sc->request_bufflen) {
965 pci_unmap_single(hd->ioc->pcidev,
966 sc->SCp.dma_handle,
967 sc->request_bufflen,
968 sc->sc_data_direction);
969 }
970 sc->host_scribble = NULL;
971 sc->result = DID_NO_CONNECT << 16;
972 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 return;
976}
977
978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
981/*
982 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
983 * from a SCSI target device.
984 * @sc: Pointer to scsi_cmnd structure
985 * @pScsiReply: Pointer to SCSIIOReply_t
986 * @pScsiReq: Pointer to original SCSI request
987 *
988 * This routine periodically reports QUEUE_FULL status returned from a
989 * SCSI target device. It reports this to the console via kernel
990 * printk() API call, not more than once every 10 seconds.
991 */
992static void
993mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
994{
995 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400998 if (sc->device == NULL)
999 return;
1000 if (sc->device->host == NULL)
1001 return;
1002 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1003 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001005 if (time - hd->last_queue_full > 10 * HZ) {
1006 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1007 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1008 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010}
1011
1012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1013/*
1014 * mptscsih_remove - Removed scsi devices
1015 * @pdev: Pointer to pci_dev structure
1016 *
1017 *
1018 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001019void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020mptscsih_remove(struct pci_dev *pdev)
1021{
1022 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1023 struct Scsi_Host *host = ioc->sh;
1024 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001025 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001027 if(!host) {
1028 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 scsi_remove_host(host);
1033
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1035 return;
1036
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001037 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001039 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001041 if (hd->ScsiLookup != NULL) {
1042 sz1 = hd->ioc->req_depth * sizeof(void *);
1043 kfree(hd->ScsiLookup);
1044 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
1046
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001047 /*
1048 * Free pointer array.
1049 */
1050 kfree(hd->Targets);
1051 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001053 dprintk((MYIOC_s_INFO_FMT
1054 "Free'd ScsiLookup (%d) memory\n",
1055 hd->ioc->name, sz1));
1056
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001057 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001058
1059 /* NULL the Scsi_Host pointer
1060 */
1061 hd->ioc->sh = NULL;
1062
1063 scsi_host_put(host);
1064
1065 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067}
1068
1069/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1070/*
1071 * mptscsih_shutdown - reboot notifier
1072 *
1073 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001074void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001075mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001077 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 struct Scsi_Host *host = ioc->sh;
1079 MPT_SCSI_HOST *hd;
1080
1081 if(!host)
1082 return;
1083
1084 hd = (MPT_SCSI_HOST *)host->hostdata;
1085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086}
1087
1088#ifdef CONFIG_PM
1089/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1090/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001091 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 *
1093 *
1094 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001095int
Pavel Machek8d189f72005-04-16 15:25:28 -07001096mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001098 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001099 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100}
1101
1102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1103/*
1104 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1105 *
1106 *
1107 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001108int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109mptscsih_resume(struct pci_dev *pdev)
1110{
1111 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1112 struct Scsi_Host *host = ioc->sh;
1113 MPT_SCSI_HOST *hd;
1114
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001115 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if(!host)
1118 return 0;
1119
1120 hd = (MPT_SCSI_HOST *)host->hostdata;
1121 if(!hd)
1122 return 0;
1123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return 0;
1125}
1126
1127#endif
1128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1130/**
1131 * mptscsih_info - Return information about MPT adapter
1132 * @SChost: Pointer to Scsi_Host structure
1133 *
1134 * (linux scsi_host_template.info routine)
1135 *
1136 * Returns pointer to buffer where information was written.
1137 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001138const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139mptscsih_info(struct Scsi_Host *SChost)
1140{
1141 MPT_SCSI_HOST *h;
1142 int size = 0;
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001147 if (h->info_kbuf == NULL)
1148 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1149 return h->info_kbuf;
1150 h->info_kbuf[0] = '\0';
1151
1152 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1153 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
1158
1159struct info_str {
1160 char *buffer;
1161 int length;
1162 int offset;
1163 int pos;
1164};
1165
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001166static void
1167mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
1169 if (info->pos + len > info->length)
1170 len = info->length - info->pos;
1171
1172 if (info->pos + len < info->offset) {
1173 info->pos += len;
1174 return;
1175 }
1176
1177 if (info->pos < info->offset) {
1178 data += (info->offset - info->pos);
1179 len -= (info->offset - info->pos);
1180 }
1181
1182 if (len > 0) {
1183 memcpy(info->buffer + info->pos, data, len);
1184 info->pos += len;
1185 }
1186}
1187
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001188static int
1189mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190{
1191 va_list args;
1192 char buf[81];
1193 int len;
1194
1195 va_start(args, fmt);
1196 len = vsprintf(buf, fmt, args);
1197 va_end(args);
1198
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001199 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 return len;
1201}
1202
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001203static int
1204mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
1206 struct info_str info;
1207
1208 info.buffer = pbuf;
1209 info.length = len;
1210 info.offset = offset;
1211 info.pos = 0;
1212
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001213 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1214 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1215 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1216 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1219}
1220
1221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1222/**
1223 * mptscsih_proc_info - Return information about MPT adapter
1224 *
1225 * (linux scsi_host_template.info routine)
1226 *
1227 * buffer: if write, user data; if read, buffer for user
1228 * length: if write, return length;
1229 * offset: if write, 0; if read, the current offset into the buffer from
1230 * the previous read.
1231 * hostno: scsi host number
1232 * func: if write = 1; if read = 0
1233 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1236 int length, int func)
1237{
1238 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1239 MPT_ADAPTER *ioc = hd->ioc;
1240 int size = 0;
1241
1242 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001243 /*
1244 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 */
1246 } else {
1247 if (start)
1248 *start = buffer;
1249
1250 size = mptscsih_host_info(ioc, buffer, offset, length);
1251 }
1252
1253 return size;
1254}
1255
1256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1257#define ADD_INDEX_LOG(req_ent) do { } while(0)
1258
1259/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1260/**
1261 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1262 * @SCpnt: Pointer to scsi_cmnd structure
1263 * @done: Pointer SCSI mid-layer IO completion function
1264 *
1265 * (linux scsi_host_template.queuecommand routine)
1266 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1267 * from a linux scsi_cmnd request and send it to the IOC.
1268 *
1269 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1270 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001271int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1273{
1274 MPT_SCSI_HOST *hd;
1275 MPT_FRAME_HDR *mf;
1276 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001277 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 int lun;
1279 u32 datalen;
1280 u32 scsictl;
1281 u32 scsidir;
1282 u32 cmd_len;
1283 int my_idx;
1284 int ii;
1285
1286 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 lun = SCpnt->device->lun;
1288 SCpnt->scsi_done = done;
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1291 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1292
1293 if (hd->resetPending) {
1294 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1295 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1296 return SCSI_MLQUEUE_HOST_BUSY;
1297 }
1298
Moore, Ericf44e5462006-03-14 09:14:21 -07001299 if ((hd->ioc->bus_type == SPI) &&
1300 vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001301 mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
1302 SCpnt->result = DID_NO_CONNECT << 16;
1303 done(SCpnt);
1304 return 0;
1305 }
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 /*
1308 * Put together a MPT SCSI request...
1309 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001310 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1312 hd->ioc->name));
1313 return SCSI_MLQUEUE_HOST_BUSY;
1314 }
1315
1316 pScsiReq = (SCSIIORequest_t *) mf;
1317
1318 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1319
1320 ADD_INDEX_LOG(my_idx);
1321
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001322 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 * Seems we may receive a buffer (datalen>0) even when there
1324 * will be no data transfer! GRRRRR...
1325 */
1326 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1327 datalen = SCpnt->request_bufflen;
1328 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1329 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1330 datalen = SCpnt->request_bufflen;
1331 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1332 } else {
1333 datalen = 0;
1334 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1335 }
1336
1337 /* Default to untagged. Once a target structure has been allocated,
1338 * use the Inquiry data to determine if device supports tagged.
1339 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001340 if (vdev
1341 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 && (SCpnt->device->tagged_supported)) {
1343 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1344 } else {
1345 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1346 }
1347
1348 /* Use the above information to set up the message frame
1349 */
Moore, Eric914c2d82006-03-14 09:19:36 -07001350 pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
1351 pScsiReq->Bus = vdev->vtarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001353 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1354 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1355 else
1356 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 pScsiReq->CDBLength = SCpnt->cmd_len;
1358 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1359 pScsiReq->Reserved = 0;
1360 pScsiReq->MsgFlags = mpt_msg_flags();
1361 pScsiReq->LUN[0] = 0;
1362 pScsiReq->LUN[1] = lun;
1363 pScsiReq->LUN[2] = 0;
1364 pScsiReq->LUN[3] = 0;
1365 pScsiReq->LUN[4] = 0;
1366 pScsiReq->LUN[5] = 0;
1367 pScsiReq->LUN[6] = 0;
1368 pScsiReq->LUN[7] = 0;
1369 pScsiReq->Control = cpu_to_le32(scsictl);
1370
1371 /*
1372 * Write SCSI CDB into the message
1373 */
1374 cmd_len = SCpnt->cmd_len;
1375 for (ii=0; ii < cmd_len; ii++)
1376 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1377
1378 for (ii=cmd_len; ii < 16; ii++)
1379 pScsiReq->CDB[ii] = 0;
1380
1381 /* DataLength */
1382 pScsiReq->DataLength = cpu_to_le32(datalen);
1383
1384 /* SenseBuffer low address */
1385 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1386 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1387
1388 /* Now add the SG list
1389 * Always have a SGE even if null length.
1390 */
1391 if (datalen == 0) {
1392 /* Add a NULL SGE */
1393 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1394 (dma_addr_t) -1);
1395 } else {
1396 /* Add a 32 or 64 bit SGE */
1397 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1398 goto fail;
1399 }
1400
1401 hd->ScsiLookup[my_idx] = SCpnt;
1402 SCpnt->host_scribble = NULL;
1403
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001404 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1406 hd->ioc->name, SCpnt, mf, my_idx));
1407 DBG_DUMP_REQUEST_FRAME(mf)
1408 return 0;
1409
1410 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001411 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1413 mpt_free_msg_frame(hd->ioc, mf);
1414 return SCSI_MLQUEUE_HOST_BUSY;
1415}
1416
1417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1418/*
1419 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1420 * with a SCSI IO request
1421 * @hd: Pointer to the MPT_SCSI_HOST instance
1422 * @req_idx: Index of the SCSI IO request frame.
1423 *
1424 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1425 * No return.
1426 */
1427static void
1428mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1429{
1430 MPT_FRAME_HDR *chain;
1431 unsigned long flags;
1432 int chain_idx;
1433 int next;
1434
1435 /* Get the first chain index and reset
1436 * tracker state.
1437 */
1438 chain_idx = ioc->ReqToChain[req_idx];
1439 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1440
1441 while (chain_idx != MPT_HOST_NO_CHAIN) {
1442
1443 /* Save the next chain buffer index */
1444 next = ioc->ChainToChain[chain_idx];
1445
1446 /* Free this chain buffer and reset
1447 * tracker
1448 */
1449 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1450
1451 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1452 + (chain_idx * ioc->req_sz));
1453
1454 spin_lock_irqsave(&ioc->FreeQlock, flags);
1455 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1456 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1457
1458 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1459 ioc->name, chain_idx));
1460
1461 /* handle next */
1462 chain_idx = next;
1463 }
1464 return;
1465}
1466
1467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1468/*
1469 * Reset Handling
1470 */
1471
1472/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1473/*
1474 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1475 * Fall through to mpt_HardResetHandler if: not operational, too many
1476 * failed TM requests or handshake failure.
1477 *
1478 * @ioc: Pointer to MPT_ADAPTER structure
1479 * @type: Task Management type
1480 * @target: Logical Target ID for reset (if appropriate)
1481 * @lun: Logical Unit for reset (if appropriate)
1482 * @ctx2abort: Context for the task to be aborted (if appropriate)
1483 *
1484 * Remark: Currently invoked from a non-interrupt thread (_bh).
1485 *
1486 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1487 * will be active.
1488 *
1489 * Returns 0 for SUCCESS or -1 if FAILED.
1490 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001491int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1493{
1494 MPT_ADAPTER *ioc;
1495 int rc = -1;
1496 int doTask = 1;
1497 u32 ioc_raw_state;
1498 unsigned long flags;
1499
1500 /* If FW is being reloaded currently, return success to
1501 * the calling function.
1502 */
1503 if (hd == NULL)
1504 return 0;
1505
1506 ioc = hd->ioc;
1507 if (ioc == NULL) {
1508 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1509 return FAILED;
1510 }
1511 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1512
1513 // SJR - CHECKME - Can we avoid this here?
1514 // (mpt_HardResetHandler has this check...)
1515 spin_lock_irqsave(&ioc->diagLock, flags);
1516 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1517 spin_unlock_irqrestore(&ioc->diagLock, flags);
1518 return FAILED;
1519 }
1520 spin_unlock_irqrestore(&ioc->diagLock, flags);
1521
1522 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1523 * If we time out and not bus reset, then we return a FAILED status to the caller.
1524 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1525 * successful. Otherwise, reload the FW.
1526 */
1527 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1528 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001529 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 "Timed out waiting for last TM (%d) to complete! \n",
1531 hd->ioc->name, hd->tmPending));
1532 return FAILED;
1533 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001534 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 "Timed out waiting for last TM (%d) to complete! \n",
1536 hd->ioc->name, hd->tmPending));
1537 return FAILED;
1538 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001539 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 "Timed out waiting for last TM (%d) to complete! \n",
1541 hd->ioc->name, hd->tmPending));
1542 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1543 return FAILED;
1544
1545 doTask = 0;
1546 }
1547 } else {
1548 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1549 hd->tmPending |= (1 << type);
1550 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1551 }
1552
1553 /* Is operational?
1554 */
1555 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1556
1557#ifdef MPT_DEBUG_RESET
1558 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1559 printk(MYIOC_s_WARN_FMT
1560 "TM Handler: IOC Not operational(0x%x)!\n",
1561 hd->ioc->name, ioc_raw_state);
1562 }
1563#endif
1564
1565 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1566 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1567
1568 /* Isse the Task Mgmt request.
1569 */
1570 if (hd->hard_resets < -1)
1571 hd->hard_resets++;
1572 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1573 if (rc) {
1574 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1575 } else {
1576 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1577 }
1578 }
1579
1580 /* Only fall through to the HRH if this is a bus reset
1581 */
1582 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1583 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1584 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1585 hd->ioc->name));
1586 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1587 }
1588
1589 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1590
1591 return rc;
1592}
1593
1594
1595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1596/*
1597 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1598 * @hd: Pointer to MPT_SCSI_HOST structure
1599 * @type: Task Management type
1600 * @target: Logical Target ID for reset (if appropriate)
1601 * @lun: Logical Unit for reset (if appropriate)
1602 * @ctx2abort: Context for the task to be aborted (if appropriate)
1603 *
1604 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1605 * or a non-interrupt thread. In the former, must not call schedule().
1606 *
1607 * Not all fields are meaningfull for all task types.
1608 *
1609 * Returns 0 for SUCCESS, -999 for "no msg frames",
1610 * else other non-zero value returned.
1611 */
1612static int
1613mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1614{
1615 MPT_FRAME_HDR *mf;
1616 SCSITaskMgmt_t *pScsiTm;
1617 int ii;
1618 int retval;
1619
1620 /* Return Fail to calling function if no message frames available.
1621 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001622 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1624 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001625 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
1627 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1628 hd->ioc->name, mf));
1629
1630 /* Format the Request
1631 */
1632 pScsiTm = (SCSITaskMgmt_t *) mf;
1633 pScsiTm->TargetID = target;
1634 pScsiTm->Bus = channel;
1635 pScsiTm->ChainOffset = 0;
1636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1637
1638 pScsiTm->Reserved = 0;
1639 pScsiTm->TaskType = type;
1640 pScsiTm->Reserved1 = 0;
1641 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1642 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1643
1644 for (ii= 0; ii < 8; ii++) {
1645 pScsiTm->LUN[ii] = 0;
1646 }
1647 pScsiTm->LUN[1] = lun;
1648
1649 for (ii=0; ii < 7; ii++)
1650 pScsiTm->Reserved2[ii] = 0;
1651
1652 pScsiTm->TaskMsgContext = ctx2abort;
1653
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001654 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1655 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1658
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001659 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1661 CAN_SLEEP)) != 0) {
1662 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1663 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1664 hd->ioc, mf));
1665 mpt_free_msg_frame(hd->ioc, mf);
1666 return retval;
1667 }
1668
1669 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1670 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1671 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1672 hd->ioc, mf));
1673 mpt_free_msg_frame(hd->ioc, mf);
1674 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1675 hd->ioc->name));
1676 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1677 }
1678
1679 return retval;
1680}
1681
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001682static int
1683mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1684{
1685 switch (ioc->bus_type) {
1686 case FC:
1687 return 40;
1688 case SAS:
1689 return 10;
1690 case SPI:
1691 default:
1692 return 2;
1693 }
1694}
1695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1697/**
1698 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1699 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1700 *
1701 * (linux scsi_host_template.eh_abort_handler routine)
1702 *
1703 * Returns SUCCESS or FAILED.
1704 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001705int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706mptscsih_abort(struct scsi_cmnd * SCpnt)
1707{
1708 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 MPT_FRAME_HDR *mf;
1710 u32 ctx2abort;
1711 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001712 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001713 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 /* If we can't locate our host adapter structure, return FAILED status.
1716 */
1717 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1718 SCpnt->result = DID_RESET << 16;
1719 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001720 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 "Can't locate host! (sc=%p)\n",
1722 SCpnt));
1723 return FAILED;
1724 }
1725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 /* Find this command
1727 */
1728 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001729 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 * Do OS callback.
1731 */
1732 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001733 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 "Command not in the active list! (sc=%p)\n",
1735 hd->ioc->name, SCpnt));
1736 return SUCCESS;
1737 }
1738
Moore, Eric65207fe2006-04-21 16:14:35 -06001739 if (hd->resetPending) {
1740 return FAILED;
1741 }
1742
1743 if (hd->timeouts < -1)
1744 hd->timeouts++;
1745
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001746 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1747 hd->ioc->name, SCpnt);
1748 scsi_print_command(SCpnt);
1749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1751 * (the IO to be ABORT'd)
1752 *
1753 * NOTE: Since we do not byteswap MsgContext, we do not
1754 * swap it here either. It is an opaque cookie to
1755 * the controller, so it does not matter. -DaveM
1756 */
1757 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1758 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1759
1760 hd->abortSCpnt = SCpnt;
1761
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001762 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001763 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric914c2d82006-03-14 09:19:36 -07001764 vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001765 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001767 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1768 hd->ioc->name,
1769 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001771 if (retval == 0)
1772 return SUCCESS;
1773
1774 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 hd->tmPending = 0;
1776 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001778 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779}
1780
1781/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1782/**
1783 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1784 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1785 *
1786 * (linux scsi_host_template.eh_dev_reset_handler routine)
1787 *
1788 * Returns SUCCESS or FAILED.
1789 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001790int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1792{
1793 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001794 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001795 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797 /* If we can't locate our host adapter structure, return FAILED status.
1798 */
1799 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 "Can't locate host! (sc=%p)\n",
1802 SCpnt));
1803 return FAILED;
1804 }
1805
1806 if (hd->resetPending)
1807 return FAILED;
1808
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001809 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001811 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001813 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001814 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -07001815 vdev->vtarget->bus_id, vdev->vtarget->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001816 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001817
1818 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1819 hd->ioc->name,
1820 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1821
1822 if (retval == 0)
1823 return SUCCESS;
1824
1825 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 hd->tmPending = 0;
1827 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001829 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830}
1831
1832/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1833/**
1834 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1835 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1836 *
1837 * (linux scsi_host_template.eh_bus_reset_handler routine)
1838 *
1839 * Returns SUCCESS or FAILED.
1840 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001841int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1843{
1844 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001845 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001846 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
1848 /* If we can't locate our host adapter structure, return FAILED status.
1849 */
1850 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001851 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 "Can't locate host! (sc=%p)\n",
1853 SCpnt ) );
1854 return FAILED;
1855 }
1856
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001857 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001859 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861 if (hd->timeouts < -1)
1862 hd->timeouts++;
1863
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001864 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001865 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric914c2d82006-03-14 09:19:36 -07001866 vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001868 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1869 hd->ioc->name,
1870 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1871
1872 if (retval == 0)
1873 return SUCCESS;
1874
1875 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 hd->tmPending = 0;
1877 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001879 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880}
1881
1882/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1883/**
1884 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1885 * new_eh variant
1886 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1887 *
1888 * (linux scsi_host_template.eh_host_reset_handler routine)
1889 *
1890 * Returns SUCCESS or FAILED.
1891 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001892int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1894{
1895 MPT_SCSI_HOST * hd;
1896 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898 /* If we can't locate the host to reset, then we failed. */
1899 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001900 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 "Can't locate host! (sc=%p)\n",
1902 SCpnt ) );
1903 return FAILED;
1904 }
1905
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001906 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 hd->ioc->name, SCpnt);
1908
1909 /* If our attempts to reset the host failed, then return a failed
1910 * status. The host will be taken off line by the SCSI mid-layer.
1911 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1913 status = FAILED;
1914 } else {
1915 /* Make sure TM pending is cleared and TM state is set to
1916 * NONE.
1917 */
1918 hd->tmPending = 0;
1919 hd->tmState = TM_STATE_NONE;
1920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001922 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 "Status = %s\n",
1924 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1925
1926 return status;
1927}
1928
1929/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1930/**
1931 * mptscsih_tm_pending_wait - wait for pending task management request to
1932 * complete.
1933 * @hd: Pointer to MPT host structure.
1934 *
1935 * Returns {SUCCESS,FAILED}.
1936 */
1937static int
1938mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1939{
1940 unsigned long flags;
1941 int loop_count = 4 * 10; /* Wait 10 seconds */
1942 int status = FAILED;
1943
1944 do {
1945 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1946 if (hd->tmState == TM_STATE_NONE) {
1947 hd->tmState = TM_STATE_IN_PROGRESS;
1948 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001950 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 break;
1952 }
1953 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1954 msleep(250);
1955 } while (--loop_count);
1956
1957 return status;
1958}
1959
1960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1961/**
1962 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1963 * @hd: Pointer to MPT host structure.
1964 *
1965 * Returns {SUCCESS,FAILED}.
1966 */
1967static int
1968mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1969{
1970 unsigned long flags;
1971 int loop_count = 4 * timeout;
1972 int status = FAILED;
1973
1974 do {
1975 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1976 if(hd->tmPending == 0) {
1977 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001978 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 break;
1980 }
1981 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05001982 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 } while (--loop_count);
1984
1985 return status;
1986}
1987
1988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07001989static void
1990mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1991{
1992 char *desc;
1993
1994 switch (response_code) {
1995 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1996 desc = "The task completed.";
1997 break;
1998 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1999 desc = "The IOC received an invalid frame status.";
2000 break;
2001 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2002 desc = "The task type is not supported.";
2003 break;
2004 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2005 desc = "The requested task failed.";
2006 break;
2007 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2008 desc = "The task completed successfully.";
2009 break;
2010 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2011 desc = "The LUN request is invalid.";
2012 break;
2013 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2014 desc = "The task is in the IOC queue and has not been sent to target.";
2015 break;
2016 default:
2017 desc = "unknown";
2018 break;
2019 }
2020 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2021 ioc->name, response_code, desc);
2022}
2023
2024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025/**
2026 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2027 * @ioc: Pointer to MPT_ADAPTER structure
2028 * @mf: Pointer to SCSI task mgmt request frame
2029 * @mr: Pointer to SCSI task mgmt reply frame
2030 *
2031 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2032 * of any SCSI task management request.
2033 * This routine is registered with the MPT (base) driver at driver
2034 * load/init time via the mpt_register() API call.
2035 *
2036 * Returns 1 indicating alloc'd request frame ptr should be freed.
2037 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002038int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2040{
2041 SCSITaskMgmtReply_t *pScsiTmReply;
2042 SCSITaskMgmt_t *pScsiTmReq;
2043 MPT_SCSI_HOST *hd;
2044 unsigned long flags;
2045 u16 iocstatus;
2046 u8 tmType;
2047
2048 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2049 ioc->name, mf, mr));
2050 if (ioc->sh) {
2051 /* Depending on the thread, a timer is activated for
2052 * the TM request. Delete this timer on completion of TM.
2053 * Decrement count of outstanding TM requests.
2054 */
2055 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2056 } else {
2057 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2058 ioc->name));
2059 return 1;
2060 }
2061
2062 if (mr == NULL) {
2063 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2064 ioc->name, mf));
2065 return 1;
2066 } else {
2067 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2068 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2069
2070 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2071 tmType = pScsiTmReq->TaskType;
2072
Moore, Eric9f63bb72006-01-16 18:53:26 -07002073 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2074 pScsiTmReply->ResponseCode)
2075 mptscsih_taskmgmt_response_code(ioc,
2076 pScsiTmReply->ResponseCode);
2077
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2079 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2080 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2081
2082 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2083 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2084 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2085 /* Error? (anything non-zero?) */
2086 if (iocstatus) {
2087
2088 /* clear flags and continue.
2089 */
2090 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2091 hd->abortSCpnt = NULL;
2092
2093 /* If an internal command is present
2094 * or the TM failed - reload the FW.
2095 * FC FW may respond FAILED to an ABORT
2096 */
2097 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2098 if ((hd->cmdPtr) ||
2099 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2100 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2101 printk((KERN_WARNING
2102 " Firmware Reload FAILED!!\n"));
2103 }
2104 }
2105 }
2106 } else {
2107 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2108
2109 hd->abortSCpnt = NULL;
2110
2111 }
2112 }
2113
2114 spin_lock_irqsave(&ioc->FreeQlock, flags);
2115 hd->tmPending = 0;
2116 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2117 hd->tmState = TM_STATE_NONE;
2118
2119 return 1;
2120}
2121
2122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2123/*
2124 * This is anyones guess quite frankly.
2125 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002126int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2128 sector_t capacity, int geom[])
2129{
2130 int heads;
2131 int sectors;
2132 sector_t cylinders;
2133 ulong dummy;
2134
2135 heads = 64;
2136 sectors = 32;
2137
2138 dummy = heads * sectors;
2139 cylinders = capacity;
2140 sector_div(cylinders,dummy);
2141
2142 /*
2143 * Handle extended translation size for logical drives
2144 * > 1Gb
2145 */
2146 if ((ulong)capacity >= 0x200000) {
2147 heads = 255;
2148 sectors = 63;
2149 dummy = heads * sectors;
2150 cylinders = capacity;
2151 sector_div(cylinders,dummy);
2152 }
2153
2154 /* return result */
2155 geom[0] = heads;
2156 geom[1] = sectors;
2157 geom[2] = cylinders;
2158
2159 dprintk((KERN_NOTICE
2160 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2161 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2162
2163 return 0;
2164}
2165
Moore, Ericf44e5462006-03-14 09:14:21 -07002166/* Search IOC page 3 to determine if this is hidden physical disk
2167 *
2168 */
2169int
2170mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
2171{
2172 int i;
2173
2174 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
2175 return 0;
2176 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2177 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2178 return 1;
2179 }
2180 return 0;
2181}
2182EXPORT_SYMBOL(mptscsih_is_phys_disk);
2183
James Bottomleyc92f2222006-03-01 09:02:49 -06002184int
2185mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
2186{
2187 int i;
2188
2189 if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
2190 return -ENXIO;
2191
2192 for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2193 if (physdiskid ==
2194 hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
2195 return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2196 }
2197
2198 return -ENXIO;
2199}
2200EXPORT_SYMBOL(mptscsih_raid_id_to_num);
2201
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2203/*
2204 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002205 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002208int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002209mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002211 VirtTarget *vtarget;
2212
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002213 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002214 if (!vtarget)
2215 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002216 starget->hostdata = vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -06002217 vtarget->starget = starget;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002218 return 0;
2219}
2220
2221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2222/*
2223 * OS entry point to allow host driver to alloc memory
2224 * for each scsi device. Called once per device the bus scan.
2225 * Return non-zero if allocation fails.
2226 */
2227int
2228mptscsih_slave_alloc(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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002234 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002236 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 if (!vdev) {
2238 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2239 hd->ioc->name, sizeof(VirtDevice));
2240 return -ENOMEM;
2241 }
2242
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002243 vdev->lun = sdev->lun;
2244 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002246 starget = scsi_target(sdev);
2247 vtarget = starget->hostdata;
James Bottomleyc92f2222006-03-01 09:02:49 -06002248
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002249 vdev->vtarget = vtarget;
2250
2251 if (vtarget->num_luns == 0) {
2252 hd->Targets[sdev->id] = vtarget;
2253 vtarget->ioc_id = hd->ioc->id;
2254 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2255 vtarget->target_id = sdev->id;
2256 vtarget->bus_id = sdev->channel;
James Bottomleyc92f2222006-03-01 09:02:49 -06002257 if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
2258 hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2259 vtarget->raidVolume = 1;
2260 ddvtprintk((KERN_INFO
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002261 "RAID Volume @ id %d\n", sdev->id));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002262 }
2263 }
2264 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 return 0;
2266}
2267
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268/*
2269 * OS entry point to allow for host driver to free allocated memory
2270 * Called if no device present or device being unloaded
2271 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002272void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002273mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002275 if (starget->hostdata)
2276 kfree(starget->hostdata);
2277 starget->hostdata = NULL;
2278}
2279
2280/*
2281 * OS entry point to allow for host driver to free allocated memory
2282 * Called if no device present or device being unloaded
2283 */
2284void
2285mptscsih_slave_destroy(struct scsi_device *sdev)
2286{
2287 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002289 VirtTarget *vtarget;
2290 VirtDevice *vdevice;
2291 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002293 starget = scsi_target(sdev);
2294 vtarget = starget->hostdata;
2295 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002297 mptscsih_search_running_cmds(hd, vdevice);
2298 vtarget->luns[0] &= ~(1 << vdevice->lun);
2299 vtarget->num_luns--;
2300 if (vtarget->num_luns == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002301 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002303 mptscsih_synchronize_cache(hd, vdevice);
2304 kfree(vdevice);
2305 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306}
2307
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002308/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2309/*
2310 * mptscsih_change_queue_depth - This function will set a devices queue depth
2311 * @sdev: per scsi_device pointer
2312 * @qdepth: requested queue depth
2313 *
2314 * Adding support for new 'change_queue_depth' api.
2315*/
2316int
2317mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002319 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2320 VirtTarget *vtarget;
2321 struct scsi_target *starget;
2322 int max_depth;
2323 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002325 starget = scsi_target(sdev);
2326 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002327
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002328 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002329 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002331 else if (sdev->type == TYPE_DISK &&
2332 vtarget->minSyncFactor <= MPT_ULTRA160)
2333 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2334 else
2335 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 } else
2337 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2338
2339 if (qdepth > max_depth)
2340 qdepth = max_depth;
2341 if (qdepth == 1)
2342 tagged = 0;
2343 else
2344 tagged = MSG_SIMPLE_TAG;
2345
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002346 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2347 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348}
2349
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350/*
2351 * OS entry point to adjust the queue_depths on a per-device basis.
2352 * Called once per device the bus scan. Use it to force the queue_depth
2353 * member to 1 if a device does not support Q tags.
2354 * Return non-zero if fails.
2355 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002356int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002357mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002359 struct Scsi_Host *sh = sdev->host;
2360 VirtTarget *vtarget;
2361 VirtDevice *vdevice;
2362 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002364 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002366 starget = scsi_target(sdev);
2367 vtarget = starget->hostdata;
2368 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
2370 dsprintk((MYIOC_s_INFO_FMT
2371 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002372 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2373 if (hd->ioc->bus_type == SPI)
2374 dsprintk((MYIOC_s_INFO_FMT
2375 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2376 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2377 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002381 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 goto slave_configure_exit;
2383 }
2384
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002385 vdevice->configured_lun=1;
2386 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2387 indexed_lun = (vdevice->lun % 32);
2388 vtarget->luns[lun_index] |= (1 << indexed_lun);
James Bottomleyc92f2222006-03-01 09:02:49 -06002389 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002390 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391
2392 dsprintk((MYIOC_s_INFO_FMT
2393 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002394 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002396 if (hd->ioc->bus_type == SPI)
2397 dsprintk((MYIOC_s_INFO_FMT
2398 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2399 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2400 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402slave_configure_exit:
2403
2404 dsprintk((MYIOC_s_INFO_FMT
2405 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002406 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2407 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409 return 0;
2410}
2411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2413/*
2414 * Private routines...
2415 */
2416
2417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2418/* Utility function to copy sense data from the scsi_cmnd buffer
2419 * to the FC and SCSI target structures.
2420 *
2421 */
2422static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002423mptscsih_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 -07002424{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002425 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 SCSIIORequest_t *pReq;
2427 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
2429 /* Get target structure
2430 */
2431 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002432 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 if (sense_count) {
2435 u8 *sense_data;
2436 int req_index;
2437
2438 /* Copy the sense received into the scsi command block. */
2439 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2440 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2441 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2442
2443 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2444 */
2445 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002446 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 int idx;
2448 MPT_ADAPTER *ioc = hd->ioc;
2449
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002450 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2452 ioc->events[idx].eventContext = ioc->eventContext;
2453
2454 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2455 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002456 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
2458 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2459
2460 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002461 if (hd->ioc->pcidev->vendor ==
2462 PCI_VENDOR_ID_IBM) {
2463 mptscsih_issue_sep_command(hd->ioc,
2464 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2465 vdev->vtarget->tflags |=
2466 MPT_TARGET_FLAGS_LED_ON;
2467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
2469 }
2470 } else {
2471 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2472 hd->ioc->name));
2473 }
2474}
2475
2476static u32
2477SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2478{
2479 MPT_SCSI_HOST *hd;
2480 int i;
2481
2482 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2483
2484 for (i = 0; i < hd->ioc->req_depth; i++) {
2485 if (hd->ScsiLookup[i] == sc) {
2486 return i;
2487 }
2488 }
2489
2490 return -1;
2491}
2492
2493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002494int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2496{
2497 MPT_SCSI_HOST *hd;
2498 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002499 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501 dtmprintk((KERN_WARNING MYNAM
2502 ": IOC %s_reset routed to SCSI host driver!\n",
2503 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2504 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2505
2506 /* If a FW reload request arrives after base installed but
2507 * before all scsi hosts have been attached, then an alt_ioc
2508 * may have a NULL sh pointer.
2509 */
2510 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2511 return 0;
2512 else
2513 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2514
2515 if (reset_phase == MPT_IOC_SETUP_RESET) {
2516 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2517
2518 /* Clean Up:
2519 * 1. Set Hard Reset Pending Flag
2520 * All new commands go to doneQ
2521 */
2522 hd->resetPending = 1;
2523
2524 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2525 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2526
2527 /* 2. Flush running commands
2528 * Clean ScsiLookup (and associated memory)
2529 * AND clean mytaskQ
2530 */
2531
2532 /* 2b. Reply to OS all known outstanding I/O commands.
2533 */
2534 mptscsih_flush_running_cmds(hd);
2535
2536 /* 2c. If there was an internal command that
2537 * has not completed, configuration or io request,
2538 * free these resources.
2539 */
2540 if (hd->cmdPtr) {
2541 del_timer(&hd->timer);
2542 mpt_free_msg_frame(ioc, hd->cmdPtr);
2543 }
2544
2545 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2546
2547 } else {
2548 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2549
2550 /* Once a FW reload begins, all new OS commands are
2551 * redirected to the doneQ w/ a reset status.
2552 * Init all control structures.
2553 */
2554
2555 /* ScsiLookup initialization
2556 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002557 for (ii=0; ii < hd->ioc->req_depth; ii++)
2558 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
2560 /* 2. Chain Buffer initialization
2561 */
2562
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002563 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
2566 /* 5. Enable new commands to be posted
2567 */
2568 spin_lock_irqsave(&ioc->FreeQlock, flags);
2569 hd->tmPending = 0;
2570 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2571 hd->resetPending = 0;
2572 hd->tmState = TM_STATE_NONE;
2573
2574 /* 6. If there was an internal command,
2575 * wake this process up.
2576 */
2577 if (hd->cmdPtr) {
2578 /*
2579 * Wake up the original calling thread
2580 */
2581 hd->pLocal = &hd->localReply;
2582 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002583 hd->scandv_wait_done = 1;
2584 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 hd->cmdPtr = NULL;
2586 }
2587
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2589
2590 }
2591
2592 return 1; /* currently means nothing really */
2593}
2594
2595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002596int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2598{
2599 MPT_SCSI_HOST *hd;
2600 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2601
Moore, Eric3a892be2006-03-14 09:14:03 -07002602 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 ioc->name, event));
2604
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002605 if (ioc->sh == NULL ||
2606 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2607 return 1;
2608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 switch (event) {
2610 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2611 /* FIXME! */
2612 break;
2613 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2614 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002615 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002616 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 break;
2618 case MPI_EVENT_LOGOUT: /* 09 */
2619 /* FIXME! */
2620 break;
2621
Michael Reed05e8ec12006-01-13 14:31:54 -06002622 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002623 break;
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 /*
2626 * CHECKME! Don't think we need to do
2627 * anything for these, but...
2628 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2630 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2631 /*
2632 * CHECKME! Falling thru...
2633 */
2634 break;
2635
2636 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002637 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 case MPI_EVENT_NONE: /* 00 */
2640 case MPI_EVENT_LOG_DATA: /* 01 */
2641 case MPI_EVENT_STATE_CHANGE: /* 02 */
2642 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2643 default:
2644 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2645 break;
2646 }
2647
2648 return 1; /* currently means nothing really */
2649}
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2652/*
2653 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2654 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002655 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002656 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 *
2658 * NOTE: It's only SAFE to call this routine if data points to
2659 * sane & valid STANDARD INQUIRY data!
2660 *
2661 * Allocate and initialize memory for this target.
2662 * Save inquiry data.
2663 *
2664 */
2665static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002666mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2667 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002670 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 /* Is LUN supported? If so, upper 2 bits will be 0
2673 * in first byte of inquiry data.
2674 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002675 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 return;
2677
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002678 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
James Bottomleyc92f2222006-03-01 09:02:49 -06002681 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002683 if (hd->ioc->bus_type != SPI)
2684 return;
2685
James Bottomleyc92f2222006-03-01 09:02:49 -06002686 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002687 /* Treat all Processors as SAF-TE if
2688 * command line option is set */
2689 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2690 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002691 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002692 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002693 if (sdev->inquiry_len > 49 ) {
2694 if (sdev->inquiry[44] == 'S' &&
2695 sdev->inquiry[45] == 'A' &&
2696 sdev->inquiry[46] == 'F' &&
2697 sdev->inquiry[47] == '-' &&
2698 sdev->inquiry[48] == 'T' &&
2699 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002700 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2701 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 }
2703 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002704 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002705 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706}
2707
2708/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2709/*
2710 * Update the target negotiation parameters based on the
2711 * the Inquiry data, adapter capabilities, and NVRAM settings.
2712 *
2713 */
2714static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002715mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2716 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002718 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 int id = (int) target->target_id;
2720 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 u8 width = MPT_NARROW;
2722 u8 factor = MPT_ASYNC;
2723 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002724 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 u8 noQas = 1;
2726
2727 target->negoFlags = pspi_data->noQas;
2728
James Bottomleyc92f2222006-03-01 09:02:49 -06002729 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
James Bottomleyc92f2222006-03-01 09:02:49 -06002731 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 width = 0;
2733 factor = MPT_ULTRA2;
2734 offset = pspi_data->maxSyncOffset;
2735 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2736 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002737 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 width = 1;
2739 }
2740
James Bottomleyc92f2222006-03-01 09:02:49 -06002741 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002743 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002745 else {
2746 if (!scsi_device_ius(sdev) &&
2747 !scsi_device_qas(sdev))
2748 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002750 factor = MPT_ULTRA320;
2751 if (scsi_device_qas(sdev)) {
2752 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2753 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002755 if (sdev->type == TYPE_TAPE &&
2756 scsi_device_ius(sdev))
2757 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 offset = pspi_data->maxSyncOffset;
2761
2762 /* If RAID, never disable QAS
2763 * else if non RAID, do not disable
2764 * QAS if bit 1 is set
2765 * bit 1 QAS support, non-raid only
2766 * bit 0 IU support
2767 */
2768 if (target->raidVolume == 1) {
2769 noQas = 0;
2770 }
2771 } else {
2772 factor = MPT_ASYNC;
2773 offset = 0;
2774 }
2775 }
2776
James Bottomleyc92f2222006-03-01 09:02:49 -06002777 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2779 }
2780
2781 /* Update tflags based on NVRAM settings. (SCSI only)
2782 */
2783 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2784 nvram = pspi_data->nvram[id];
2785 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2786
2787 if (width)
2788 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2789
2790 if (offset > 0) {
2791 /* Ensure factor is set to the
2792 * maximum of: adapter, nvram, inquiry
2793 */
2794 if (nfactor) {
2795 if (nfactor < pspi_data->minSyncFactor )
2796 nfactor = pspi_data->minSyncFactor;
2797
2798 factor = max(factor, nfactor);
2799 if (factor == MPT_ASYNC)
2800 offset = 0;
2801 } else {
2802 offset = 0;
2803 factor = MPT_ASYNC;
2804 }
2805 } else {
2806 factor = MPT_ASYNC;
2807 }
2808 }
2809
2810 /* Make sure data is consistent
2811 */
2812 if ((!width) && (factor < MPT_ULTRA2)) {
2813 factor = MPT_ULTRA2;
2814 }
2815
2816 /* Save the data to the target structure.
2817 */
2818 target->minSyncFactor = factor;
2819 target->maxOffset = offset;
2820 target->maxWidth = width;
2821
2822 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2823
2824 /* Disable unused features.
2825 */
2826 if (!width)
2827 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2828
2829 if (!offset)
2830 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2831
2832 if ( factor > MPT_ULTRA320 )
2833 noQas = 0;
2834
James Bottomleyc92f2222006-03-01 09:02:49 -06002835 if (noQas && (pspi_data->noQas == 0)) {
2836 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2837 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
James Bottomleyc92f2222006-03-01 09:02:49 -06002839 /* Disable QAS in a mixed configuration case
2840 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
James Bottomleyc92f2222006-03-01 09:02:49 -06002842 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
2844}
2845
2846/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
2848/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2849/*
2850 * SCSI Config Page functionality ...
2851 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854/* mptscsih_writeIOCPage4 - write IOC Page 4
2855 * @hd: Pointer to a SCSI Host Structure
2856 * @target_id: write IOC Page4 for this ID & Bus
2857 *
2858 * Return: -EAGAIN if unable to obtain a Message Frame
2859 * or 0 if success.
2860 *
2861 * Remark: We do not wait for a return, write pages sequentially.
2862 */
2863static int
2864mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
2865{
2866 MPT_ADAPTER *ioc = hd->ioc;
2867 Config_t *pReq;
2868 IOCPage4_t *IOCPage4Ptr;
2869 MPT_FRAME_HDR *mf;
2870 dma_addr_t dataDma;
2871 u16 req_idx;
2872 u32 frameOffset;
2873 u32 flagsLength;
2874 int ii;
2875
2876 /* Get a MF for this command.
2877 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002878 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002879 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 ioc->name));
2881 return -EAGAIN;
2882 }
2883
2884 /* Set the request and the data pointers.
2885 * Place data at end of MF.
2886 */
2887 pReq = (Config_t *)mf;
2888
2889 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2890 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2891
2892 /* Complete the request frame (same for all requests).
2893 */
2894 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2895 pReq->Reserved = 0;
2896 pReq->ChainOffset = 0;
2897 pReq->Function = MPI_FUNCTION_CONFIG;
2898 pReq->ExtPageLength = 0;
2899 pReq->ExtPageType = 0;
2900 pReq->MsgFlags = 0;
2901 for (ii=0; ii < 8; ii++) {
2902 pReq->Reserved2[ii] = 0;
2903 }
2904
2905 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2906 dataDma = ioc->spi_data.IocPg4_dma;
2907 ii = IOCPage4Ptr->ActiveSEP++;
2908 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
2909 IOCPage4Ptr->SEP[ii].SEPBus = bus;
2910 pReq->Header = IOCPage4Ptr->Header;
2911 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
2912
2913 /* Add a SGE to the config request.
2914 */
2915 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2916 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2917
2918 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2919
2920 dinitprintk((MYIOC_s_INFO_FMT
2921 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
2922 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
2923
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002924 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
2926 return 0;
2927}
2928
2929/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2930/*
2931 * Bus Scan and Domain Validation functionality ...
2932 */
2933
2934/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2935/*
2936 * mptscsih_scandv_complete - Scan and DV callback routine registered
2937 * to Fustion MPT (base) driver.
2938 *
2939 * @ioc: Pointer to MPT_ADAPTER structure
2940 * @mf: Pointer to original MPT request frame
2941 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2942 *
2943 * This routine is called from mpt.c::mpt_interrupt() at the completion
2944 * of any SCSI IO request.
2945 * This routine is registered with the Fusion MPT (base) driver at driver
2946 * load/init time via the mpt_register() API call.
2947 *
2948 * Returns 1 indicating alloc'd request frame ptr should be freed.
2949 *
2950 * Remark: Sets a completion code and (possibly) saves sense data
2951 * in the IOC member localReply structure.
2952 * Used ONLY for DV and other internal commands.
2953 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002954int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2956{
2957 MPT_SCSI_HOST *hd;
2958 SCSIIORequest_t *pReq;
2959 int completionCode;
2960 u16 req_idx;
2961
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002962 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2963
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 if ((mf == NULL) ||
2965 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2966 printk(MYIOC_s_ERR_FMT
2967 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2968 ioc->name, mf?"BAD":"NULL", (void *) mf);
2969 goto wakeup;
2970 }
2971
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 del_timer(&hd->timer);
2973 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2974 hd->ScsiLookup[req_idx] = NULL;
2975 pReq = (SCSIIORequest_t *) mf;
2976
2977 if (mf != hd->cmdPtr) {
2978 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2979 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2980 }
2981 hd->cmdPtr = NULL;
2982
2983 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2984 hd->ioc->name, mf, mr, req_idx));
2985
2986 hd->pLocal = &hd->localReply;
2987 hd->pLocal->scsiStatus = 0;
2988
2989 /* If target struct exists, clear sense valid flag.
2990 */
2991 if (mr == NULL) {
2992 completionCode = MPT_SCANDV_GOOD;
2993 } else {
2994 SCSIIOReply_t *pReply;
2995 u16 status;
2996 u8 scsi_status;
2997
2998 pReply = (SCSIIOReply_t *) mr;
2999
3000 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3001 scsi_status = pReply->SCSIStatus;
3002
3003 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3004 status, pReply->SCSIState, scsi_status,
3005 le32_to_cpu(pReply->IOCLogInfo)));
3006
3007 switch(status) {
3008
3009 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3010 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3011 break;
3012
3013 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3014 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3015 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3016 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3017 completionCode = MPT_SCANDV_DID_RESET;
3018 break;
3019
3020 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3021 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3022 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3023 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3024 ConfigReply_t *pr = (ConfigReply_t *)mr;
3025 completionCode = MPT_SCANDV_GOOD;
3026 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3027 hd->pLocal->header.PageLength = pr->Header.PageLength;
3028 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3029 hd->pLocal->header.PageType = pr->Header.PageType;
3030
3031 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3032 /* If the RAID Volume request is successful,
3033 * return GOOD, else indicate that
3034 * some type of error occurred.
3035 */
3036 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003037 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 completionCode = MPT_SCANDV_GOOD;
3039 else
3040 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06003041 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
3043 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3044 u8 *sense_data;
3045 int sz;
3046
3047 /* save sense data in global structure
3048 */
3049 completionCode = MPT_SCANDV_SENSE;
3050 hd->pLocal->scsiStatus = scsi_status;
3051 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3052 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3053
3054 sz = min_t(int, pReq->SenseBufferLength,
3055 SCSI_STD_SENSE_BYTES);
3056 memcpy(hd->pLocal->sense, sense_data, sz);
3057
3058 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3059 sense_data));
3060 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3061 if (pReq->CDB[0] == INQUIRY)
3062 completionCode = MPT_SCANDV_ISSUE_SENSE;
3063 else
3064 completionCode = MPT_SCANDV_DID_RESET;
3065 }
3066 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3067 completionCode = MPT_SCANDV_DID_RESET;
3068 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3069 completionCode = MPT_SCANDV_DID_RESET;
3070 else {
3071 completionCode = MPT_SCANDV_GOOD;
3072 hd->pLocal->scsiStatus = scsi_status;
3073 }
3074 break;
3075
3076 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3077 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3078 completionCode = MPT_SCANDV_DID_RESET;
3079 else
3080 completionCode = MPT_SCANDV_SOME_ERROR;
3081 break;
3082
3083 default:
3084 completionCode = MPT_SCANDV_SOME_ERROR;
3085 break;
3086
3087 } /* switch(status) */
3088
3089 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3090 completionCode));
3091 } /* end of address reply case */
3092
3093 hd->pLocal->completion = completionCode;
3094
3095 /* MF and RF are freed in mpt_interrupt
3096 */
3097wakeup:
3098 /* Free Chain buffers (will never chain) in scan or dv */
3099 //mptscsih_freeChainBuffers(ioc, req_idx);
3100
3101 /*
3102 * Wake up the original calling thread
3103 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003104 hd->scandv_wait_done = 1;
3105 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
3107 return 1;
3108}
3109
3110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3111/* mptscsih_timer_expired - Call back for timer process.
3112 * Used only for dv functionality.
3113 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3114 *
3115 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003116void
3117mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118{
3119 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3120
3121 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3122
3123 if (hd->cmdPtr) {
3124 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3125
3126 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3127 /* Desire to issue a task management request here.
3128 * TM requests MUST be single threaded.
3129 * If old eh code and no TM current, issue request.
3130 * If new eh code, do nothing. Wait for OS cmd timeout
3131 * for bus reset.
3132 */
3133 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3134 } else {
3135 /* Perform a FW reload */
3136 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3137 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3138 }
3139 }
3140 } else {
3141 /* This should NEVER happen */
3142 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3143 }
3144
3145 /* No more processing.
3146 * TM call will generate an interrupt for SCSI TM Management.
3147 * The FW will reply to all outstanding commands, callback will finish cleanup.
3148 * Hard reset clean-up will free all resources.
3149 */
3150 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3151
3152 return;
3153}
3154
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
3156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3157/**
3158 * mptscsih_do_cmd - Do internal command.
3159 * @hd: MPT_SCSI_HOST pointer
3160 * @io: INTERNAL_CMD pointer.
3161 *
3162 * Issue the specified internally generated command and do command
3163 * specific cleanup. For bus scan / DV only.
3164 * NOTES: If command is Inquiry and status is good,
3165 * initialize a target structure, save the data
3166 *
3167 * Remark: Single threaded access only.
3168 *
3169 * Return:
3170 * < 0 if an illegal command or no resources
3171 *
3172 * 0 if good
3173 *
3174 * > 0 if command complete but some type of completion error.
3175 */
3176static int
3177mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3178{
3179 MPT_FRAME_HDR *mf;
3180 SCSIIORequest_t *pScsiReq;
3181 SCSIIORequest_t ReqCopy;
3182 int my_idx, ii, dir;
3183 int rc, cmdTimeout;
3184 int in_isr;
3185 char cmdLen;
3186 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3187 char cmd = io->cmd;
3188
3189 in_isr = in_interrupt();
3190 if (in_isr) {
3191 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3192 hd->ioc->name));
3193 return -EPERM;
3194 }
3195
3196
3197 /* Set command specific information
3198 */
3199 switch (cmd) {
3200 case INQUIRY:
3201 cmdLen = 6;
3202 dir = MPI_SCSIIO_CONTROL_READ;
3203 CDB[0] = cmd;
3204 CDB[4] = io->size;
3205 cmdTimeout = 10;
3206 break;
3207
3208 case TEST_UNIT_READY:
3209 cmdLen = 6;
3210 dir = MPI_SCSIIO_CONTROL_READ;
3211 cmdTimeout = 10;
3212 break;
3213
3214 case START_STOP:
3215 cmdLen = 6;
3216 dir = MPI_SCSIIO_CONTROL_READ;
3217 CDB[0] = cmd;
3218 CDB[4] = 1; /*Spin up the disk */
3219 cmdTimeout = 15;
3220 break;
3221
3222 case REQUEST_SENSE:
3223 cmdLen = 6;
3224 CDB[0] = cmd;
3225 CDB[4] = io->size;
3226 dir = MPI_SCSIIO_CONTROL_READ;
3227 cmdTimeout = 10;
3228 break;
3229
3230 case READ_BUFFER:
3231 cmdLen = 10;
3232 dir = MPI_SCSIIO_CONTROL_READ;
3233 CDB[0] = cmd;
3234 if (io->flags & MPT_ICFLAG_ECHO) {
3235 CDB[1] = 0x0A;
3236 } else {
3237 CDB[1] = 0x02;
3238 }
3239
3240 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3241 CDB[1] |= 0x01;
3242 }
3243 CDB[6] = (io->size >> 16) & 0xFF;
3244 CDB[7] = (io->size >> 8) & 0xFF;
3245 CDB[8] = io->size & 0xFF;
3246 cmdTimeout = 10;
3247 break;
3248
3249 case WRITE_BUFFER:
3250 cmdLen = 10;
3251 dir = MPI_SCSIIO_CONTROL_WRITE;
3252 CDB[0] = cmd;
3253 if (io->flags & MPT_ICFLAG_ECHO) {
3254 CDB[1] = 0x0A;
3255 } else {
3256 CDB[1] = 0x02;
3257 }
3258 CDB[6] = (io->size >> 16) & 0xFF;
3259 CDB[7] = (io->size >> 8) & 0xFF;
3260 CDB[8] = io->size & 0xFF;
3261 cmdTimeout = 10;
3262 break;
3263
3264 case RESERVE:
3265 cmdLen = 6;
3266 dir = MPI_SCSIIO_CONTROL_READ;
3267 CDB[0] = cmd;
3268 cmdTimeout = 10;
3269 break;
3270
3271 case RELEASE:
3272 cmdLen = 6;
3273 dir = MPI_SCSIIO_CONTROL_READ;
3274 CDB[0] = cmd;
3275 cmdTimeout = 10;
3276 break;
3277
3278 case SYNCHRONIZE_CACHE:
3279 cmdLen = 10;
3280 dir = MPI_SCSIIO_CONTROL_READ;
3281 CDB[0] = cmd;
3282// CDB[1] = 0x02; /* set immediate bit */
3283 cmdTimeout = 10;
3284 break;
3285
3286 default:
3287 /* Error Case */
3288 return -EFAULT;
3289 }
3290
3291 /* Get and Populate a free Frame
3292 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003293 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3295 hd->ioc->name));
3296 return -EBUSY;
3297 }
3298
3299 pScsiReq = (SCSIIORequest_t *) mf;
3300
3301 /* Get the request index */
3302 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3303 ADD_INDEX_LOG(my_idx); /* for debug */
3304
3305 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3306 pScsiReq->TargetID = io->physDiskNum;
3307 pScsiReq->Bus = 0;
3308 pScsiReq->ChainOffset = 0;
3309 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3310 } else {
3311 pScsiReq->TargetID = io->id;
3312 pScsiReq->Bus = io->bus;
3313 pScsiReq->ChainOffset = 0;
3314 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3315 }
3316
3317 pScsiReq->CDBLength = cmdLen;
3318 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3319
3320 pScsiReq->Reserved = 0;
3321
3322 pScsiReq->MsgFlags = mpt_msg_flags();
3323 /* MsgContext set in mpt_get_msg_fram call */
3324
3325 for (ii=0; ii < 8; ii++)
3326 pScsiReq->LUN[ii] = 0;
3327 pScsiReq->LUN[1] = io->lun;
3328
3329 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3330 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3331 else
3332 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3333
3334 if (cmd == REQUEST_SENSE) {
3335 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3336 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3337 hd->ioc->name, cmd));
3338 }
3339
3340 for (ii=0; ii < 16; ii++)
3341 pScsiReq->CDB[ii] = CDB[ii];
3342
3343 pScsiReq->DataLength = cpu_to_le32(io->size);
3344 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3345 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3346
3347 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3348 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3349
3350 if (dir == MPI_SCSIIO_CONTROL_READ) {
3351 mpt_add_sge((char *) &pScsiReq->SGL,
3352 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3353 io->data_dma);
3354 } else {
3355 mpt_add_sge((char *) &pScsiReq->SGL,
3356 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3357 io->data_dma);
3358 }
3359
3360 /* The ISR will free the request frame, but we need
3361 * the information to initialize the target. Duplicate.
3362 */
3363 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3364
3365 /* Issue this command after:
3366 * finish init
3367 * add timer
3368 * Wait until the reply has been received
3369 * ScsiScanDvCtx callback function will
3370 * set hd->pLocal;
3371 * set scandv_wait_done and call wake_up
3372 */
3373 hd->pLocal = NULL;
3374 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003375 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376
3377 /* Save cmd pointer, for resource free if timeout or
3378 * FW reload occurs
3379 */
3380 hd->cmdPtr = mf;
3381
3382 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003383 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3384 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
3386 if (hd->pLocal) {
3387 rc = hd->pLocal->completion;
3388 hd->pLocal->skip = 0;
3389
3390 /* Always set fatal error codes in some cases.
3391 */
3392 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3393 rc = -ENXIO;
3394 else if (rc == MPT_SCANDV_SOME_ERROR)
3395 rc = -rc;
3396 } else {
3397 rc = -EFAULT;
3398 /* This should never happen. */
3399 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3400 hd->ioc->name));
3401 }
3402
3403 return rc;
3404}
3405
3406/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3407/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003408 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3409 * @hd: Pointer to a SCSI HOST structure
3410 * @vtarget: per device private data
3411 * @lun: lun
3412 *
3413 * Uses the ISR, but with special processing.
3414 * MUST be single-threaded.
3415 *
3416 */
3417static void
3418mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3419{
3420 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 /* Following parameters will not change
3423 * in this routine.
3424 */
3425 iocmd.cmd = SYNCHRONIZE_CACHE;
3426 iocmd.flags = 0;
3427 iocmd.physDiskNum = -1;
3428 iocmd.data = NULL;
3429 iocmd.data_dma = -1;
3430 iocmd.size = 0;
3431 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric914c2d82006-03-14 09:19:36 -07003432 iocmd.bus = vdevice->vtarget->bus_id;
3433 iocmd.id = vdevice->vtarget->target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003434 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
James Bottomleyc92f2222006-03-01 09:02:49 -06003436 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003437 (vdevice->configured_lun))
3438 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439}
3440
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003441EXPORT_SYMBOL(mptscsih_remove);
3442EXPORT_SYMBOL(mptscsih_shutdown);
3443#ifdef CONFIG_PM
3444EXPORT_SYMBOL(mptscsih_suspend);
3445EXPORT_SYMBOL(mptscsih_resume);
3446#endif
3447EXPORT_SYMBOL(mptscsih_proc_info);
3448EXPORT_SYMBOL(mptscsih_info);
3449EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003450EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003451EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003452EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003453EXPORT_SYMBOL(mptscsih_slave_destroy);
3454EXPORT_SYMBOL(mptscsih_slave_configure);
3455EXPORT_SYMBOL(mptscsih_abort);
3456EXPORT_SYMBOL(mptscsih_dev_reset);
3457EXPORT_SYMBOL(mptscsih_bus_reset);
3458EXPORT_SYMBOL(mptscsih_host_reset);
3459EXPORT_SYMBOL(mptscsih_bios_param);
3460EXPORT_SYMBOL(mptscsih_io_done);
3461EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3462EXPORT_SYMBOL(mptscsih_scandv_complete);
3463EXPORT_SYMBOL(mptscsih_event_process);
3464EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003465EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003466EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003467EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003469/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/