blob: 2e1c9ff4b0283e03becd4a0ffaba9cabbede672d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04006 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * (mailto:mpt_linux_developer@lsil.com)
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include "linux_compat.h" /* linux-2.6 tweaks */
48#include <linux/module.h>
49#include <linux/kernel.h>
50#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
57#include <linux/sched.h>
58#include <linux/workqueue.h>
59
60#include <scsi/scsi.h>
61#include <scsi/scsi_cmnd.h>
62#include <scsi/scsi_device.h>
63#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060065#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68#include "mptscsih.h"
69
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT SCSI Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptscsih"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
80
81typedef struct _BIG_SENSE_BUF {
82 u8 data[MPT_SENSE_BUFFER_ALLOC];
83} BIG_SENSE_BUF;
84
85#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
86#define MPT_SCANDV_DID_RESET (0x00000001)
87#define MPT_SCANDV_SENSE (0x00000002)
88#define MPT_SCANDV_SOME_ERROR (0x00000004)
89#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
90#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
91#define MPT_SCANDV_FALLBACK (0x00000020)
92
93#define MPT_SCANDV_MAX_RETRIES (10)
94
95#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
96#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
Moore, Eric Dean466544d2005-09-14 18:09:10 -060097#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
98#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
99#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
101#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
102
103typedef struct _internal_cmd {
104 char *data; /* data pointer */
105 dma_addr_t data_dma; /* data dma address */
106 int size; /* transfer size */
107 u8 cmd; /* SCSI Op Code */
108 u8 bus; /* bus number */
109 u8 id; /* SCSI ID (virtual) */
110 u8 lun;
111 u8 flags; /* Bit Field - See above */
112 u8 physDiskNum; /* Phys disk number, -1 else */
113 u8 rsvd2;
114 u8 rsvd;
115} INTERNAL_CMD;
116
117typedef struct _negoparms {
118 u8 width;
119 u8 offset;
120 u8 factor;
121 u8 flags;
122} NEGOPARMS;
123
124typedef struct _dv_parameters {
125 NEGOPARMS max;
126 NEGOPARMS now;
127 u8 cmd;
128 u8 id;
129 u16 pad1;
130} DVPARAMETERS;
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/*
133 * Other private/forward protos...
134 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400135int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400137int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
140 SCSIIORequest_t *pReq, int req_idx);
141static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400142static 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 -0700143static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
144static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
145static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
148
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400149int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
150int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700152static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen);
153static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, char byte56);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700155static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
157static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400158int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700160static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Moore, Erica69ac322006-01-17 17:06:26 -0700161static void mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700162static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
165static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
166static void mptscsih_domainValidation(void *hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
168static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
169static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
170static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600171static void mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700172static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400175void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700176void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400178int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
179int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180#endif
181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
183
184#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
185/*
186 * Domain Validation task structure
187 */
188static DEFINE_SPINLOCK(dvtaskQ_lock);
189static int dvtaskQ_active = 0;
190static int dvtaskQ_release = 0;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400191static struct work_struct dvTaskQ_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#endif
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
195/**
196 * mptscsih_add_sge - Place a simple SGE at address pAddr.
197 * @pAddr: virtual address for SGE
198 * @flagslength: SGE flags and data transfer length
199 * @dma_addr: Physical address
200 *
201 * This routine places a MPT request frame back on the MPT adapter's
202 * FreeQ.
203 */
204static inline void
205mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
206{
207 if (sizeof(dma_addr_t) == sizeof(u64)) {
208 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
209 u32 tmp = dma_addr & 0xFFFFFFFF;
210
211 pSge->FlagsLength = cpu_to_le32(flagslength);
212 pSge->Address.Low = cpu_to_le32(tmp);
213 tmp = (u32) ((u64)dma_addr >> 32);
214 pSge->Address.High = cpu_to_le32(tmp);
215
216 } else {
217 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
218 pSge->FlagsLength = cpu_to_le32(flagslength);
219 pSge->Address = cpu_to_le32(dma_addr);
220 }
221} /* mptscsih_add_sge() */
222
223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
224/**
225 * mptscsih_add_chain - Place a chain SGE at address pAddr.
226 * @pAddr: virtual address for SGE
227 * @next: nextChainOffset value (u32's)
228 * @length: length of next SGL segment
229 * @dma_addr: Physical address
230 *
231 * This routine places a MPT request frame back on the MPT adapter's
232 * FreeQ.
233 */
234static inline void
235mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
236{
237 if (sizeof(dma_addr_t) == sizeof(u64)) {
238 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
239 u32 tmp = dma_addr & 0xFFFFFFFF;
240
241 pChain->Length = cpu_to_le16(length);
242 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
243
244 pChain->NextChainOffset = next;
245
246 pChain->Address.Low = cpu_to_le32(tmp);
247 tmp = (u32) ((u64)dma_addr >> 32);
248 pChain->Address.High = cpu_to_le32(tmp);
249 } else {
250 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
251 pChain->Length = cpu_to_le16(length);
252 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
253 pChain->NextChainOffset = next;
254 pChain->Address = cpu_to_le32(dma_addr);
255 }
256} /* mptscsih_add_chain() */
257
258/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
259/*
260 * mptscsih_getFreeChainBuffer - Function to get a free chain
261 * from the MPT_SCSI_HOST FreeChainQ.
262 * @ioc: Pointer to MPT_ADAPTER structure
263 * @req_idx: Index of the SCSI IO request frame. (output)
264 *
265 * return SUCCESS or FAILED
266 */
267static inline int
268mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
269{
270 MPT_FRAME_HDR *chainBuf;
271 unsigned long flags;
272 int rc;
273 int chain_idx;
274
275 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
276 ioc->name));
277 spin_lock_irqsave(&ioc->FreeQlock, flags);
278 if (!list_empty(&ioc->FreeChainQ)) {
279 int offset;
280
281 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
282 u.frame.linkage.list);
283 list_del(&chainBuf->u.frame.linkage.list);
284 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
285 chain_idx = offset / ioc->req_sz;
286 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200287 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
288 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 } else {
290 rc = FAILED;
291 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200292 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 ioc->name));
294 }
295 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
296
297 *retIndex = chain_idx;
298 return rc;
299} /* mptscsih_getFreeChainBuffer() */
300
301/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
302/*
303 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
304 * SCSIIORequest_t Message Frame.
305 * @ioc: Pointer to MPT_ADAPTER structure
306 * @SCpnt: Pointer to scsi_cmnd structure
307 * @pReq: Pointer to SCSIIORequest_t structure
308 *
309 * Returns ...
310 */
311static int
312mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
313 SCSIIORequest_t *pReq, int req_idx)
314{
315 char *psge;
316 char *chainSge;
317 struct scatterlist *sg;
318 int frm_sz;
319 int sges_left, sg_done;
320 int chain_idx = MPT_HOST_NO_CHAIN;
321 int sgeOffset;
322 int numSgeSlots, numSgeThisFrame;
323 u32 sgflags, sgdir, thisxfer = 0;
324 int chain_dma_off = 0;
325 int newIndex;
326 int ii;
327 dma_addr_t v2;
328 u32 RequestNB;
329
330 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
331 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
332 sgdir = MPT_TRANSFER_HOST_TO_IOC;
333 } else {
334 sgdir = MPT_TRANSFER_IOC_TO_HOST;
335 }
336
337 psge = (char *) &pReq->SGL;
338 frm_sz = ioc->req_sz;
339
340 /* Map the data portion, if any.
341 * sges_left = 0 if no data transfer.
342 */
343 if ( (sges_left = SCpnt->use_sg) ) {
344 sges_left = pci_map_sg(ioc->pcidev,
345 (struct scatterlist *) SCpnt->request_buffer,
346 SCpnt->use_sg,
347 SCpnt->sc_data_direction);
348 if (sges_left == 0)
349 return FAILED;
350 } else if (SCpnt->request_bufflen) {
351 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
352 SCpnt->request_buffer,
353 SCpnt->request_bufflen,
354 SCpnt->sc_data_direction);
355 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
356 ioc->name, SCpnt, SCpnt->request_bufflen));
357 mptscsih_add_sge((char *) &pReq->SGL,
358 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
359 SCpnt->SCp.dma_handle);
360
361 return SUCCESS;
362 }
363
364 /* Handle the SG case.
365 */
366 sg = (struct scatterlist *) SCpnt->request_buffer;
367 sg_done = 0;
368 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
369 chainSge = NULL;
370
371 /* Prior to entering this loop - the following must be set
372 * current MF: sgeOffset (bytes)
373 * chainSge (Null if original MF is not a chain buffer)
374 * sg_done (num SGE done for this MF)
375 */
376
377nextSGEset:
378 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
379 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
380
381 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
382
383 /* Get first (num - 1) SG elements
384 * Skip any SG entries with a length of 0
385 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
386 */
387 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
388 thisxfer = sg_dma_len(sg);
389 if (thisxfer == 0) {
390 sg ++; /* Get next SG element from the OS */
391 sg_done++;
392 continue;
393 }
394
395 v2 = sg_dma_address(sg);
396 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
397
398 sg++; /* Get next SG element from the OS */
399 psge += (sizeof(u32) + sizeof(dma_addr_t));
400 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
401 sg_done++;
402 }
403
404 if (numSgeThisFrame == sges_left) {
405 /* Add last element, end of buffer and end of list flags.
406 */
407 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
408 MPT_SGE_FLAGS_END_OF_BUFFER |
409 MPT_SGE_FLAGS_END_OF_LIST;
410
411 /* Add last SGE and set termination flags.
412 * Note: Last SGE may have a length of 0 - which should be ok.
413 */
414 thisxfer = sg_dma_len(sg);
415
416 v2 = sg_dma_address(sg);
417 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
418 /*
419 sg++;
420 psge += (sizeof(u32) + sizeof(dma_addr_t));
421 */
422 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
423 sg_done++;
424
425 if (chainSge) {
426 /* The current buffer is a chain buffer,
427 * but there is not another one.
428 * Update the chain element
429 * Offset and Length fields.
430 */
431 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
432 } else {
433 /* The current buffer is the original MF
434 * and there is no Chain buffer.
435 */
436 pReq->ChainOffset = 0;
437 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200438 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
440 ioc->RequestNB[req_idx] = RequestNB;
441 }
442 } else {
443 /* At least one chain buffer is needed.
444 * Complete the first MF
445 * - last SGE element, set the LastElement bit
446 * - set ChainOffset (words) for orig MF
447 * (OR finish previous MF chain buffer)
448 * - update MFStructPtr ChainIndex
449 * - Populate chain element
450 * Also
451 * Loop until done.
452 */
453
454 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
455 ioc->name, sg_done));
456
457 /* Set LAST_ELEMENT flag for last non-chain element
458 * in the buffer. Since psge points at the NEXT
459 * SGE element, go back one SGE element, update the flags
460 * and reset the pointer. (Note: sgflags & thisxfer are already
461 * set properly).
462 */
463 if (sg_done) {
464 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
465 sgflags = le32_to_cpu(*ptmp);
466 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
467 *ptmp = cpu_to_le32(sgflags);
468 }
469
470 if (chainSge) {
471 /* The current buffer is a chain buffer.
472 * chainSge points to the previous Chain Element.
473 * Update its chain element Offset and Length (must
474 * include chain element size) fields.
475 * Old chain element is now complete.
476 */
477 u8 nextChain = (u8) (sgeOffset >> 2);
478 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
479 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
480 } else {
481 /* The original MF buffer requires a chain buffer -
482 * set the offset.
483 * Last element in this MF is a chain element.
484 */
485 pReq->ChainOffset = (u8) (sgeOffset >> 2);
486 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
487 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
488 ioc->RequestNB[req_idx] = RequestNB;
489 }
490
491 sges_left -= sg_done;
492
493
494 /* NOTE: psge points to the beginning of the chain element
495 * in current buffer. Get a chain buffer.
496 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200497 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
498 dfailprintk((MYIOC_s_INFO_FMT
499 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
500 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 /* Update the tracking arrays.
505 * If chainSge == NULL, update ReqToChain, else ChainToChain
506 */
507 if (chainSge) {
508 ioc->ChainToChain[chain_idx] = newIndex;
509 } else {
510 ioc->ReqToChain[req_idx] = newIndex;
511 }
512 chain_idx = newIndex;
513 chain_dma_off = ioc->req_sz * chain_idx;
514
515 /* Populate the chainSGE for the current buffer.
516 * - Set chain buffer pointer to psge and fill
517 * out the Address and Flags fields.
518 */
519 chainSge = (char *) psge;
520 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
521 psge, req_idx));
522
523 /* Start the SGE for the next buffer
524 */
525 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
526 sgeOffset = 0;
527 sg_done = 0;
528
529 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
530 psge, chain_idx));
531
532 /* Start the SGE for the next buffer
533 */
534
535 goto nextSGEset;
536 }
537
538 return SUCCESS;
539} /* mptscsih_AddSGE() */
540
541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
542/*
543 * mptscsih_io_done - Main SCSI IO callback routine registered to
544 * Fusion MPT (base) driver
545 * @ioc: Pointer to MPT_ADAPTER structure
546 * @mf: Pointer to original MPT request frame
547 * @r: Pointer to MPT reply frame (NULL if TurboReply)
548 *
549 * This routine is called from mpt.c::mpt_interrupt() at the completion
550 * of any SCSI IO request.
551 * This routine is registered with the Fusion MPT (base) driver at driver
552 * load/init time via the mpt_register() API call.
553 *
554 * Returns 1 indicating alloc'd request frame ptr should be freed.
555 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400556int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
558{
559 struct scsi_cmnd *sc;
560 MPT_SCSI_HOST *hd;
561 SCSIIORequest_t *pScsiReq;
562 SCSIIOReply_t *pScsiReply;
563 u16 req_idx;
564
565 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
566
567 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
568 sc = hd->ScsiLookup[req_idx];
569 if (sc == NULL) {
570 MPIHeader_t *hdr = (MPIHeader_t *)mf;
571
572 /* Remark: writeSDP1 will use the ScsiDoneCtx
573 * If a SCSI I/O cmd, device disabled by OS and
574 * completion done. Cannot touch sc struct. Just free mem.
575 */
576 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
577 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
578 ioc->name);
579
580 mptscsih_freeChainBuffers(ioc, req_idx);
581 return 1;
582 }
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 sc->result = DID_OK << 16; /* Set default reply as OK */
585 pScsiReq = (SCSIIORequest_t *) mf;
586 pScsiReply = (SCSIIOReply_t *) mr;
587
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200588 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
589 dmfprintk((MYIOC_s_INFO_FMT
590 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
591 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
592 }else{
593 dmfprintk((MYIOC_s_INFO_FMT
594 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
595 ioc->name, mf, mr, sc, req_idx));
596 }
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 if (pScsiReply == NULL) {
599 /* special context reply handling */
600 ;
601 } else {
602 u32 xfer_cnt;
603 u16 status;
604 u8 scsi_state, scsi_status;
605
606 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
607 scsi_state = pScsiReply->SCSIState;
608 scsi_status = pScsiReply->SCSIStatus;
609 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
610 sc->resid = sc->request_bufflen - xfer_cnt;
611
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600612 /*
613 * if we get a data underrun indication, yet no data was
614 * transferred and the SCSI status indicates that the
615 * command was never started, change the data underrun
616 * to success
617 */
618 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
619 (scsi_status == MPI_SCSI_STATUS_BUSY ||
620 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
621 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
622 status = MPI_IOCSTATUS_SUCCESS;
623 }
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
626 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
627 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700628 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600629 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 sc->request_bufflen, xfer_cnt));
631
632 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400633 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 /*
636 * Look for + dump FCP ResponseInfo[]!
637 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600638 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
639 pScsiReply->ResponseInfo) {
640 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
641 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700642 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 le32_to_cpu(pScsiReply->ResponseInfo));
644 }
645
646 switch(status) {
647 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
648 /* CHECKME!
649 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
650 * But not: DID_BUS_BUSY lest one risk
651 * killing interrupt handler:-(
652 */
653 sc->result = SAM_STAT_BUSY;
654 break;
655
656 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
657 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
658 sc->result = DID_BAD_TARGET << 16;
659 break;
660
661 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
662 /* Spoof to SCSI Selection Timeout! */
663 sc->result = DID_NO_CONNECT << 16;
664
665 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
666 hd->sel_timeout[pScsiReq->TargetID]++;
667 break;
668
669 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
670 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
671 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
672 /* Linux handles an unsolicited DID_RESET better
673 * than an unsolicited DID_ABORT.
674 */
675 sc->result = DID_RESET << 16;
676
677 /* GEM Workaround. */
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700678 if (ioc->bus_type == SPI)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700679 mptscsih_no_negotiate(hd, sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 break;
681
682 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600683 sc->resid = sc->request_bufflen - xfer_cnt;
684 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
685 sc->result=DID_SOFT_ERROR << 16;
686 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600688 dreplyprintk((KERN_NOTICE
689 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
693 /*
694 * Do upfront check for valid SenseData and give it
695 * precedence!
696 */
697 sc->result = (DID_OK << 16) | scsi_status;
698 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
699 /* Have already saved the status and sense data
700 */
701 ;
702 } else {
703 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600704 if (scsi_status == SAM_STAT_BUSY)
705 sc->result = SAM_STAT_BUSY;
706 else
707 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
709 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
710 /* What to do?
711 */
712 sc->result = DID_SOFT_ERROR << 16;
713 }
714 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
715 /* Not real sure here either... */
716 sc->result = DID_RESET << 16;
717 }
718 }
719
720 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
721 sc->underflow));
722 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
723 /* Report Queue Full
724 */
725 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
726 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 break;
729
Moore, Eric7e551472006-01-16 18:53:21 -0700730 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
731 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
733 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600734 if (scsi_status == MPI_SCSI_STATUS_BUSY)
735 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
736 else
737 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (scsi_state == 0) {
739 ;
740 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
741 /*
742 * If running against circa 200003dd 909 MPT f/w,
743 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
744 * (QUEUE_FULL) returned from device! --> get 0x0000?128
745 * and with SenseBytes set to 0.
746 */
747 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
748 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
749
750 }
751 else if (scsi_state &
752 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
753 ) {
754 /*
755 * What to do?
756 */
757 sc->result = DID_SOFT_ERROR << 16;
758 }
759 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
760 /* Not real sure here either... */
761 sc->result = DID_RESET << 16;
762 }
763 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
764 /* Device Inq. data indicates that it supports
765 * QTags, but rejects QTag messages.
766 * This command completed OK.
767 *
768 * Not real sure here either so do nothing... */
769 }
770
771 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
772 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
773
774 /* Add handling of:
775 * Reservation Conflict, Busy,
776 * Command Terminated, CHECK
777 */
778 break;
779
780 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
781 sc->result = DID_SOFT_ERROR << 16;
782 break;
783
784 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
785 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
786 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
787 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
788 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
789 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
790 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
792 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
793 default:
794 /*
795 * What to do?
796 */
797 sc->result = DID_SOFT_ERROR << 16;
798 break;
799
800 } /* switch(status) */
801
802 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
803 } /* end of address reply case */
804
805 /* Unmap the DMA buffers, if any. */
806 if (sc->use_sg) {
807 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
808 sc->use_sg, sc->sc_data_direction);
809 } else if (sc->request_bufflen) {
810 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
811 sc->request_bufflen, sc->sc_data_direction);
812 }
813
814 hd->ScsiLookup[req_idx] = NULL;
815
816 sc->scsi_done(sc); /* Issue the command callback */
817
818 /* Free Chain buffers */
819 mptscsih_freeChainBuffers(ioc, req_idx);
820 return 1;
821}
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823/*
824 * mptscsih_flush_running_cmds - For each command found, search
825 * Scsi_Host instance taskQ and reply to OS.
826 * Called only if recovering from a FW reload.
827 * @hd: Pointer to a SCSI HOST structure
828 *
829 * Returns: None.
830 *
831 * Must be called while new I/Os are being queued.
832 */
833static void
834mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
835{
836 MPT_ADAPTER *ioc = hd->ioc;
837 struct scsi_cmnd *SCpnt;
838 MPT_FRAME_HDR *mf;
839 int ii;
840 int max = ioc->req_depth;
841
842 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
843 for (ii= 0; ii < max; ii++) {
844 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
845
846 /* Command found.
847 */
848
849 /* Null ScsiLookup index
850 */
851 hd->ScsiLookup[ii] = NULL;
852
853 mf = MPT_INDEX_2_MFPTR(ioc, ii);
854 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
855 mf, SCpnt));
856
857 /* Set status, free OS resources (SG DMA buffers)
858 * Do OS callback
859 * Free driver resources (chain, msg buffers)
860 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400861 if (SCpnt->use_sg) {
862 pci_unmap_sg(ioc->pcidev,
863 (struct scatterlist *) SCpnt->request_buffer,
864 SCpnt->use_sg,
865 SCpnt->sc_data_direction);
866 } else if (SCpnt->request_bufflen) {
867 pci_unmap_single(ioc->pcidev,
868 SCpnt->SCp.dma_handle,
869 SCpnt->request_bufflen,
870 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 }
872 SCpnt->result = DID_RESET << 16;
873 SCpnt->host_scribble = NULL;
874
875 /* Free Chain buffers */
876 mptscsih_freeChainBuffers(ioc, ii);
877
878 /* Free Message frames */
879 mpt_free_msg_frame(ioc, mf);
880
881 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
882 }
883 }
884
885 return;
886}
887
888/*
889 * mptscsih_search_running_cmds - Delete any commands associated
890 * with the specified target and lun. Function called only
891 * when a lun is disable by mid-layer.
892 * Do NOT access the referenced scsi_cmnd structure or
893 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600894 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700895 * @hd: Pointer to a SCSI HOST structure
896 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 *
898 * Returns: None.
899 *
900 * Called from slave_destroy.
901 */
902static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700903mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904{
905 SCSIIORequest_t *mf = NULL;
906 int ii;
907 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600908 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700911 vdevice->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600914 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
917
918 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
919 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
920
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700921 if ((mf->TargetID != ((u8)vdevice->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 continue;
923
924 /* Cleanup
925 */
926 hd->ScsiLookup[ii] = NULL;
927 mptscsih_freeChainBuffers(hd->ioc, ii);
928 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600929 if (sc->use_sg) {
930 pci_unmap_sg(hd->ioc->pcidev,
931 (struct scatterlist *) sc->request_buffer,
932 sc->use_sg,
933 sc->sc_data_direction);
934 } else if (sc->request_bufflen) {
935 pci_unmap_single(hd->ioc->pcidev,
936 sc->SCp.dma_handle,
937 sc->request_bufflen,
938 sc->sc_data_direction);
939 }
940 sc->host_scribble = NULL;
941 sc->result = DID_NO_CONNECT << 16;
942 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 return;
946}
947
948/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
951/*
952 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
953 * from a SCSI target device.
954 * @sc: Pointer to scsi_cmnd structure
955 * @pScsiReply: Pointer to SCSIIOReply_t
956 * @pScsiReq: Pointer to original SCSI request
957 *
958 * This routine periodically reports QUEUE_FULL status returned from a
959 * SCSI target device. It reports this to the console via kernel
960 * printk() API call, not more than once every 10 seconds.
961 */
962static void
963mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
964{
965 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400968 if (sc->device == NULL)
969 return;
970 if (sc->device->host == NULL)
971 return;
972 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
973 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400975 if (time - hd->last_queue_full > 10 * HZ) {
976 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
977 hd->ioc->name, 0, sc->device->id, sc->device->lun));
978 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
983/*
984 * mptscsih_remove - Removed scsi devices
985 * @pdev: Pointer to pci_dev structure
986 *
987 *
988 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400989void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990mptscsih_remove(struct pci_dev *pdev)
991{
992 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
993 struct Scsi_Host *host = ioc->sh;
994 MPT_SCSI_HOST *hd;
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700995#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 int count;
997 unsigned long flags;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700998#endif
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400999 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001001 if(!host) {
1002 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006 scsi_remove_host(host);
1007
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001008 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1009 return;
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1012 /* Check DV thread active */
1013 count = 10 * HZ;
1014 spin_lock_irqsave(&dvtaskQ_lock, flags);
1015 if (dvtaskQ_active) {
1016 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
Nishanth Aravamudan65210182005-11-07 01:01:19 -08001017 while(dvtaskQ_active && --count)
1018 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 } else {
1020 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
1021 }
1022 if (!count)
1023 printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
1024#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
1025 else
1026 printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
1027#endif
1028#endif
1029
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001030 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001032 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 if (hd->ScsiLookup != NULL) {
1035 sz1 = hd->ioc->req_depth * sizeof(void *);
1036 kfree(hd->ScsiLookup);
1037 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001040 /*
1041 * Free pointer array.
1042 */
1043 kfree(hd->Targets);
1044 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001046 dprintk((MYIOC_s_INFO_FMT
1047 "Free'd ScsiLookup (%d) memory\n",
1048 hd->ioc->name, sz1));
1049
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001050 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001051
1052 /* NULL the Scsi_Host pointer
1053 */
1054 hd->ioc->sh = NULL;
1055
1056 scsi_host_put(host);
1057
1058 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001059
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060}
1061
1062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1063/*
1064 * mptscsih_shutdown - reboot notifier
1065 *
1066 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001067void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001068mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001070 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 struct Scsi_Host *host = ioc->sh;
1072 MPT_SCSI_HOST *hd;
1073
1074 if(!host)
1075 return;
1076
1077 hd = (MPT_SCSI_HOST *)host->hostdata;
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079}
1080
1081#ifdef CONFIG_PM
1082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1083/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001084 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 *
1086 *
1087 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001088int
Pavel Machek8d189f72005-04-16 15:25:28 -07001089mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001091 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001092 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
1094
1095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1096/*
1097 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1098 *
1099 *
1100 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001101int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102mptscsih_resume(struct pci_dev *pdev)
1103{
1104 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1105 struct Scsi_Host *host = ioc->sh;
1106 MPT_SCSI_HOST *hd;
1107
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001108 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if(!host)
1111 return 0;
1112
1113 hd = (MPT_SCSI_HOST *)host->hostdata;
1114 if(!hd)
1115 return 0;
1116
1117#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1118 {
1119 unsigned long lflags;
1120 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1121 if (!dvtaskQ_active) {
1122 dvtaskQ_active = 1;
1123 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001124 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001126 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 } else {
1128 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1129 }
1130 }
1131#endif
1132 return 0;
1133}
1134
1135#endif
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1138/**
1139 * mptscsih_info - Return information about MPT adapter
1140 * @SChost: Pointer to Scsi_Host structure
1141 *
1142 * (linux scsi_host_template.info routine)
1143 *
1144 * Returns pointer to buffer where information was written.
1145 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001146const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147mptscsih_info(struct Scsi_Host *SChost)
1148{
1149 MPT_SCSI_HOST *h;
1150 int size = 0;
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155 if (h->info_kbuf == NULL)
1156 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1157 return h->info_kbuf;
1158 h->info_kbuf[0] = '\0';
1159
1160 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1161 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001164 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
1166
1167struct info_str {
1168 char *buffer;
1169 int length;
1170 int offset;
1171 int pos;
1172};
1173
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001174static void
1175mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
1177 if (info->pos + len > info->length)
1178 len = info->length - info->pos;
1179
1180 if (info->pos + len < info->offset) {
1181 info->pos += len;
1182 return;
1183 }
1184
1185 if (info->pos < info->offset) {
1186 data += (info->offset - info->pos);
1187 len -= (info->offset - info->pos);
1188 }
1189
1190 if (len > 0) {
1191 memcpy(info->buffer + info->pos, data, len);
1192 info->pos += len;
1193 }
1194}
1195
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196static int
1197mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
1199 va_list args;
1200 char buf[81];
1201 int len;
1202
1203 va_start(args, fmt);
1204 len = vsprintf(buf, fmt, args);
1205 va_end(args);
1206
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001207 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 return len;
1209}
1210
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211static int
1212mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 struct info_str info;
1215
1216 info.buffer = pbuf;
1217 info.length = len;
1218 info.offset = offset;
1219 info.pos = 0;
1220
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001221 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1222 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1223 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1224 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1227}
1228
1229/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1230/**
1231 * mptscsih_proc_info - Return information about MPT adapter
1232 *
1233 * (linux scsi_host_template.info routine)
1234 *
1235 * buffer: if write, user data; if read, buffer for user
1236 * length: if write, return length;
1237 * offset: if write, 0; if read, the current offset into the buffer from
1238 * the previous read.
1239 * hostno: scsi host number
1240 * func: if write = 1; if read = 0
1241 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001242int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1244 int length, int func)
1245{
1246 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1247 MPT_ADAPTER *ioc = hd->ioc;
1248 int size = 0;
1249
1250 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001251 /*
1252 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 */
1254 } else {
1255 if (start)
1256 *start = buffer;
1257
1258 size = mptscsih_host_info(ioc, buffer, offset, length);
1259 }
1260
1261 return size;
1262}
1263
1264/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1265#define ADD_INDEX_LOG(req_ent) do { } while(0)
1266
1267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1268/**
1269 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1270 * @SCpnt: Pointer to scsi_cmnd structure
1271 * @done: Pointer SCSI mid-layer IO completion function
1272 *
1273 * (linux scsi_host_template.queuecommand routine)
1274 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1275 * from a linux scsi_cmnd request and send it to the IOC.
1276 *
1277 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1278 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001279int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1281{
1282 MPT_SCSI_HOST *hd;
1283 MPT_FRAME_HDR *mf;
1284 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001285 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 int lun;
1287 u32 datalen;
1288 u32 scsictl;
1289 u32 scsidir;
1290 u32 cmd_len;
1291 int my_idx;
1292 int ii;
1293
1294 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 lun = SCpnt->device->lun;
1296 SCpnt->scsi_done = done;
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1299 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1300
1301 if (hd->resetPending) {
1302 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1303 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1304 return SCSI_MLQUEUE_HOST_BUSY;
1305 }
1306
1307 /*
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, Eric Deanc7c82982005-11-16 18:54:25 -07001350 pScsiReq->TargetID = (u8) vdev->target_id;
1351 pScsiReq->Bus = vdev->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 pScsiReq->ChainOffset = 0;
1353 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1354 pScsiReq->CDBLength = SCpnt->cmd_len;
1355 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1356 pScsiReq->Reserved = 0;
1357 pScsiReq->MsgFlags = mpt_msg_flags();
1358 pScsiReq->LUN[0] = 0;
1359 pScsiReq->LUN[1] = lun;
1360 pScsiReq->LUN[2] = 0;
1361 pScsiReq->LUN[3] = 0;
1362 pScsiReq->LUN[4] = 0;
1363 pScsiReq->LUN[5] = 0;
1364 pScsiReq->LUN[6] = 0;
1365 pScsiReq->LUN[7] = 0;
1366 pScsiReq->Control = cpu_to_le32(scsictl);
1367
1368 /*
1369 * Write SCSI CDB into the message
1370 */
1371 cmd_len = SCpnt->cmd_len;
1372 for (ii=0; ii < cmd_len; ii++)
1373 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1374
1375 for (ii=cmd_len; ii < 16; ii++)
1376 pScsiReq->CDB[ii] = 0;
1377
1378 /* DataLength */
1379 pScsiReq->DataLength = cpu_to_le32(datalen);
1380
1381 /* SenseBuffer low address */
1382 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1383 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1384
1385 /* Now add the SG list
1386 * Always have a SGE even if null length.
1387 */
1388 if (datalen == 0) {
1389 /* Add a NULL SGE */
1390 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1391 (dma_addr_t) -1);
1392 } else {
1393 /* Add a 32 or 64 bit SGE */
1394 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1395 goto fail;
1396 }
1397
1398 hd->ScsiLookup[my_idx] = SCpnt;
1399 SCpnt->host_scribble = NULL;
1400
1401#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001402 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001403 int dvStatus = hd->ioc->spi_data.dvStatus[vdev->target_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 int issueCmd = 1;
1405
1406 if (dvStatus || hd->ioc->spi_data.forceDv) {
1407
1408 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1409 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1410 unsigned long lflags;
1411 /* Schedule DV if necessary */
1412 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1413 if (!dvtaskQ_active) {
1414 dvtaskQ_active = 1;
1415 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001416 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001418 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 } else {
1420 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1421 }
1422 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1423 }
1424
1425 /* Trying to do DV to this target, extend timeout.
1426 * Wait to issue until flag is clear
1427 */
1428 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1429 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1430 issueCmd = 0;
1431 }
1432
1433 /* Set the DV flags.
1434 */
1435 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001436 mptscsih_set_dvflags(hd, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438 if (!issueCmd)
1439 goto fail;
1440 }
1441 }
1442#endif
1443
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001444 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1446 hd->ioc->name, SCpnt, mf, my_idx));
1447 DBG_DUMP_REQUEST_FRAME(mf)
1448 return 0;
1449
1450 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001451 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1453 mpt_free_msg_frame(hd->ioc, mf);
1454 return SCSI_MLQUEUE_HOST_BUSY;
1455}
1456
1457/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1458/*
1459 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1460 * with a SCSI IO request
1461 * @hd: Pointer to the MPT_SCSI_HOST instance
1462 * @req_idx: Index of the SCSI IO request frame.
1463 *
1464 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1465 * No return.
1466 */
1467static void
1468mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1469{
1470 MPT_FRAME_HDR *chain;
1471 unsigned long flags;
1472 int chain_idx;
1473 int next;
1474
1475 /* Get the first chain index and reset
1476 * tracker state.
1477 */
1478 chain_idx = ioc->ReqToChain[req_idx];
1479 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1480
1481 while (chain_idx != MPT_HOST_NO_CHAIN) {
1482
1483 /* Save the next chain buffer index */
1484 next = ioc->ChainToChain[chain_idx];
1485
1486 /* Free this chain buffer and reset
1487 * tracker
1488 */
1489 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1490
1491 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1492 + (chain_idx * ioc->req_sz));
1493
1494 spin_lock_irqsave(&ioc->FreeQlock, flags);
1495 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1496 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1497
1498 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1499 ioc->name, chain_idx));
1500
1501 /* handle next */
1502 chain_idx = next;
1503 }
1504 return;
1505}
1506
1507/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1508/*
1509 * Reset Handling
1510 */
1511
1512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1513/*
1514 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1515 * Fall through to mpt_HardResetHandler if: not operational, too many
1516 * failed TM requests or handshake failure.
1517 *
1518 * @ioc: Pointer to MPT_ADAPTER structure
1519 * @type: Task Management type
1520 * @target: Logical Target ID for reset (if appropriate)
1521 * @lun: Logical Unit for reset (if appropriate)
1522 * @ctx2abort: Context for the task to be aborted (if appropriate)
1523 *
1524 * Remark: Currently invoked from a non-interrupt thread (_bh).
1525 *
1526 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1527 * will be active.
1528 *
1529 * Returns 0 for SUCCESS or -1 if FAILED.
1530 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001531int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1533{
1534 MPT_ADAPTER *ioc;
1535 int rc = -1;
1536 int doTask = 1;
1537 u32 ioc_raw_state;
1538 unsigned long flags;
1539
1540 /* If FW is being reloaded currently, return success to
1541 * the calling function.
1542 */
1543 if (hd == NULL)
1544 return 0;
1545
1546 ioc = hd->ioc;
1547 if (ioc == NULL) {
1548 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1549 return FAILED;
1550 }
1551 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1552
1553 // SJR - CHECKME - Can we avoid this here?
1554 // (mpt_HardResetHandler has this check...)
1555 spin_lock_irqsave(&ioc->diagLock, flags);
1556 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1557 spin_unlock_irqrestore(&ioc->diagLock, flags);
1558 return FAILED;
1559 }
1560 spin_unlock_irqrestore(&ioc->diagLock, flags);
1561
1562 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1563 * If we time out and not bus reset, then we return a FAILED status to the caller.
1564 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1565 * successful. Otherwise, reload the FW.
1566 */
1567 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1568 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001569 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 "Timed out waiting for last TM (%d) to complete! \n",
1571 hd->ioc->name, hd->tmPending));
1572 return FAILED;
1573 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001574 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 "Timed out waiting for last TM (%d) to complete! \n",
1576 hd->ioc->name, hd->tmPending));
1577 return FAILED;
1578 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001579 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 "Timed out waiting for last TM (%d) to complete! \n",
1581 hd->ioc->name, hd->tmPending));
1582 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1583 return FAILED;
1584
1585 doTask = 0;
1586 }
1587 } else {
1588 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1589 hd->tmPending |= (1 << type);
1590 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1591 }
1592
1593 /* Is operational?
1594 */
1595 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1596
1597#ifdef MPT_DEBUG_RESET
1598 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1599 printk(MYIOC_s_WARN_FMT
1600 "TM Handler: IOC Not operational(0x%x)!\n",
1601 hd->ioc->name, ioc_raw_state);
1602 }
1603#endif
1604
1605 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1606 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1607
1608 /* Isse the Task Mgmt request.
1609 */
1610 if (hd->hard_resets < -1)
1611 hd->hard_resets++;
1612 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1613 if (rc) {
1614 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1615 } else {
1616 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1617 }
1618 }
1619
1620 /* Only fall through to the HRH if this is a bus reset
1621 */
1622 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1623 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1624 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1625 hd->ioc->name));
1626 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1627 }
1628
1629 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1630
1631 return rc;
1632}
1633
1634
1635/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1636/*
1637 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1638 * @hd: Pointer to MPT_SCSI_HOST structure
1639 * @type: Task Management type
1640 * @target: Logical Target ID for reset (if appropriate)
1641 * @lun: Logical Unit for reset (if appropriate)
1642 * @ctx2abort: Context for the task to be aborted (if appropriate)
1643 *
1644 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1645 * or a non-interrupt thread. In the former, must not call schedule().
1646 *
1647 * Not all fields are meaningfull for all task types.
1648 *
1649 * Returns 0 for SUCCESS, -999 for "no msg frames",
1650 * else other non-zero value returned.
1651 */
1652static int
1653mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1654{
1655 MPT_FRAME_HDR *mf;
1656 SCSITaskMgmt_t *pScsiTm;
1657 int ii;
1658 int retval;
1659
1660 /* Return Fail to calling function if no message frames available.
1661 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001662 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1664 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001665 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 }
1667 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1668 hd->ioc->name, mf));
1669
1670 /* Format the Request
1671 */
1672 pScsiTm = (SCSITaskMgmt_t *) mf;
1673 pScsiTm->TargetID = target;
1674 pScsiTm->Bus = channel;
1675 pScsiTm->ChainOffset = 0;
1676 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1677
1678 pScsiTm->Reserved = 0;
1679 pScsiTm->TaskType = type;
1680 pScsiTm->Reserved1 = 0;
1681 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1682 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1683
1684 for (ii= 0; ii < 8; ii++) {
1685 pScsiTm->LUN[ii] = 0;
1686 }
1687 pScsiTm->LUN[1] = lun;
1688
1689 for (ii=0; ii < 7; ii++)
1690 pScsiTm->Reserved2[ii] = 0;
1691
1692 pScsiTm->TaskMsgContext = ctx2abort;
1693
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001694 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1695 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1698
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001699 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1701 CAN_SLEEP)) != 0) {
1702 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1703 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1704 hd->ioc, mf));
1705 mpt_free_msg_frame(hd->ioc, mf);
1706 return retval;
1707 }
1708
1709 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1710 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1711 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1712 hd->ioc, mf));
1713 mpt_free_msg_frame(hd->ioc, mf);
1714 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1715 hd->ioc->name));
1716 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1717 }
1718
1719 return retval;
1720}
1721
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001722static int
1723mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1724{
1725 switch (ioc->bus_type) {
1726 case FC:
1727 return 40;
1728 case SAS:
1729 return 10;
1730 case SPI:
1731 default:
1732 return 2;
1733 }
1734}
1735
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1737/**
1738 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1739 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1740 *
1741 * (linux scsi_host_template.eh_abort_handler routine)
1742 *
1743 * Returns SUCCESS or FAILED.
1744 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001745int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746mptscsih_abort(struct scsi_cmnd * SCpnt)
1747{
1748 MPT_SCSI_HOST *hd;
1749 MPT_ADAPTER *ioc;
1750 MPT_FRAME_HDR *mf;
1751 u32 ctx2abort;
1752 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001753 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001754 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 /* If we can't locate our host adapter structure, return FAILED status.
1757 */
1758 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1759 SCpnt->result = DID_RESET << 16;
1760 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001761 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 "Can't locate host! (sc=%p)\n",
1763 SCpnt));
1764 return FAILED;
1765 }
1766
1767 ioc = hd->ioc;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001768 if (hd->resetPending) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 return FAILED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772 if (hd->timeouts < -1)
1773 hd->timeouts++;
1774
1775 /* Find this command
1776 */
1777 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001778 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 * Do OS callback.
1780 */
1781 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001782 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 "Command not in the active list! (sc=%p)\n",
1784 hd->ioc->name, SCpnt));
1785 return SUCCESS;
1786 }
1787
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001788 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1789 hd->ioc->name, SCpnt);
1790 scsi_print_command(SCpnt);
1791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1793 * (the IO to be ABORT'd)
1794 *
1795 * NOTE: Since we do not byteswap MsgContext, we do not
1796 * swap it here either. It is an opaque cookie to
1797 * the controller, so it does not matter. -DaveM
1798 */
1799 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1800 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1801
1802 hd->abortSCpnt = SCpnt;
1803
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001804 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001805 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001806 vdev->bus_id, vdev->target_id, vdev->lun,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001807 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001809 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1810 hd->ioc->name,
1811 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001813 if (retval == 0)
1814 return SUCCESS;
1815
1816 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 hd->tmPending = 0;
1818 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001820 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821}
1822
1823/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1824/**
1825 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1826 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1827 *
1828 * (linux scsi_host_template.eh_dev_reset_handler routine)
1829 *
1830 * Returns SUCCESS or FAILED.
1831 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001832int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1834{
1835 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001836 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001837 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838
1839 /* If we can't locate our host adapter structure, return FAILED status.
1840 */
1841 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 "Can't locate host! (sc=%p)\n",
1844 SCpnt));
1845 return FAILED;
1846 }
1847
1848 if (hd->resetPending)
1849 return FAILED;
1850
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001851 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001853 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001855 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001856 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001857 vdev->bus_id, vdev->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001858 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001859
1860 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1861 hd->ioc->name,
1862 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1863
1864 if (retval == 0)
1865 return SUCCESS;
1866
1867 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 hd->tmPending = 0;
1869 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001871 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872}
1873
1874/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1875/**
1876 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1877 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1878 *
1879 * (linux scsi_host_template.eh_bus_reset_handler routine)
1880 *
1881 * Returns SUCCESS or FAILED.
1882 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001883int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1885{
1886 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001887 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001888 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 /* If we can't locate our host adapter structure, return FAILED status.
1891 */
1892 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001893 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 "Can't locate host! (sc=%p)\n",
1895 SCpnt ) );
1896 return FAILED;
1897 }
1898
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001899 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001901 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903 if (hd->timeouts < -1)
1904 hd->timeouts++;
1905
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001906 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001907 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001908 vdev->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001910 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1911 hd->ioc->name,
1912 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1913
1914 if (retval == 0)
1915 return SUCCESS;
1916
1917 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 hd->tmPending = 0;
1919 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001921 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922}
1923
1924/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1925/**
1926 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1927 * new_eh variant
1928 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1929 *
1930 * (linux scsi_host_template.eh_host_reset_handler routine)
1931 *
1932 * Returns SUCCESS or FAILED.
1933 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001934int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1936{
1937 MPT_SCSI_HOST * hd;
1938 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
1940 /* If we can't locate the host to reset, then we failed. */
1941 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001942 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 "Can't locate host! (sc=%p)\n",
1944 SCpnt ) );
1945 return FAILED;
1946 }
1947
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001948 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 hd->ioc->name, SCpnt);
1950
1951 /* If our attempts to reset the host failed, then return a failed
1952 * status. The host will be taken off line by the SCSI mid-layer.
1953 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1955 status = FAILED;
1956 } else {
1957 /* Make sure TM pending is cleared and TM state is set to
1958 * NONE.
1959 */
1960 hd->tmPending = 0;
1961 hd->tmState = TM_STATE_NONE;
1962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001964 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 "Status = %s\n",
1966 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1967
1968 return status;
1969}
1970
1971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1972/**
1973 * mptscsih_tm_pending_wait - wait for pending task management request to
1974 * complete.
1975 * @hd: Pointer to MPT host structure.
1976 *
1977 * Returns {SUCCESS,FAILED}.
1978 */
1979static int
1980mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1981{
1982 unsigned long flags;
1983 int loop_count = 4 * 10; /* Wait 10 seconds */
1984 int status = FAILED;
1985
1986 do {
1987 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1988 if (hd->tmState == TM_STATE_NONE) {
1989 hd->tmState = TM_STATE_IN_PROGRESS;
1990 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001992 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 break;
1994 }
1995 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1996 msleep(250);
1997 } while (--loop_count);
1998
1999 return status;
2000}
2001
2002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2003/**
2004 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2005 * @hd: Pointer to MPT host structure.
2006 *
2007 * Returns {SUCCESS,FAILED}.
2008 */
2009static int
2010mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2011{
2012 unsigned long flags;
2013 int loop_count = 4 * timeout;
2014 int status = FAILED;
2015
2016 do {
2017 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2018 if(hd->tmPending == 0) {
2019 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002020 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 break;
2022 }
2023 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2024 msleep_interruptible(250);
2025 } while (--loop_count);
2026
2027 return status;
2028}
2029
2030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002031static void
2032mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2033{
2034 char *desc;
2035
2036 switch (response_code) {
2037 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2038 desc = "The task completed.";
2039 break;
2040 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2041 desc = "The IOC received an invalid frame status.";
2042 break;
2043 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2044 desc = "The task type is not supported.";
2045 break;
2046 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2047 desc = "The requested task failed.";
2048 break;
2049 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2050 desc = "The task completed successfully.";
2051 break;
2052 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2053 desc = "The LUN request is invalid.";
2054 break;
2055 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2056 desc = "The task is in the IOC queue and has not been sent to target.";
2057 break;
2058 default:
2059 desc = "unknown";
2060 break;
2061 }
2062 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2063 ioc->name, response_code, desc);
2064}
2065
2066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067/**
2068 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2069 * @ioc: Pointer to MPT_ADAPTER structure
2070 * @mf: Pointer to SCSI task mgmt request frame
2071 * @mr: Pointer to SCSI task mgmt reply frame
2072 *
2073 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2074 * of any SCSI task management request.
2075 * This routine is registered with the MPT (base) driver at driver
2076 * load/init time via the mpt_register() API call.
2077 *
2078 * Returns 1 indicating alloc'd request frame ptr should be freed.
2079 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002080int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2082{
2083 SCSITaskMgmtReply_t *pScsiTmReply;
2084 SCSITaskMgmt_t *pScsiTmReq;
2085 MPT_SCSI_HOST *hd;
2086 unsigned long flags;
2087 u16 iocstatus;
2088 u8 tmType;
2089
2090 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2091 ioc->name, mf, mr));
2092 if (ioc->sh) {
2093 /* Depending on the thread, a timer is activated for
2094 * the TM request. Delete this timer on completion of TM.
2095 * Decrement count of outstanding TM requests.
2096 */
2097 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2098 } else {
2099 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2100 ioc->name));
2101 return 1;
2102 }
2103
2104 if (mr == NULL) {
2105 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2106 ioc->name, mf));
2107 return 1;
2108 } else {
2109 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2110 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2111
2112 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2113 tmType = pScsiTmReq->TaskType;
2114
Moore, Eric9f63bb72006-01-16 18:53:26 -07002115 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2116 pScsiTmReply->ResponseCode)
2117 mptscsih_taskmgmt_response_code(ioc,
2118 pScsiTmReply->ResponseCode);
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2121 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2122 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2123
2124 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2125 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2126 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2127 /* Error? (anything non-zero?) */
2128 if (iocstatus) {
2129
2130 /* clear flags and continue.
2131 */
2132 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2133 hd->abortSCpnt = NULL;
2134
2135 /* If an internal command is present
2136 * or the TM failed - reload the FW.
2137 * FC FW may respond FAILED to an ABORT
2138 */
2139 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2140 if ((hd->cmdPtr) ||
2141 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2142 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2143 printk((KERN_WARNING
2144 " Firmware Reload FAILED!!\n"));
2145 }
2146 }
2147 }
2148 } else {
2149 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2150
2151 hd->abortSCpnt = NULL;
2152
2153 }
2154 }
2155
2156 spin_lock_irqsave(&ioc->FreeQlock, flags);
2157 hd->tmPending = 0;
2158 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2159 hd->tmState = TM_STATE_NONE;
2160
2161 return 1;
2162}
2163
2164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2165/*
2166 * This is anyones guess quite frankly.
2167 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002168int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2170 sector_t capacity, int geom[])
2171{
2172 int heads;
2173 int sectors;
2174 sector_t cylinders;
2175 ulong dummy;
2176
2177 heads = 64;
2178 sectors = 32;
2179
2180 dummy = heads * sectors;
2181 cylinders = capacity;
2182 sector_div(cylinders,dummy);
2183
2184 /*
2185 * Handle extended translation size for logical drives
2186 * > 1Gb
2187 */
2188 if ((ulong)capacity >= 0x200000) {
2189 heads = 255;
2190 sectors = 63;
2191 dummy = heads * sectors;
2192 cylinders = capacity;
2193 sector_div(cylinders,dummy);
2194 }
2195
2196 /* return result */
2197 geom[0] = heads;
2198 geom[1] = sectors;
2199 geom[2] = cylinders;
2200
2201 dprintk((KERN_NOTICE
2202 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2203 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2204
2205 return 0;
2206}
2207
2208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2209/*
2210 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002211 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002214int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002215mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002217 VirtTarget *vtarget;
2218
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002219 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002220 if (!vtarget)
2221 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002222 starget->hostdata = vtarget;
2223 return 0;
2224}
2225
2226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2227/*
2228 * OS entry point to allow host driver to alloc memory
2229 * for each scsi device. Called once per device the bus scan.
2230 * Return non-zero if allocation fails.
2231 */
2232int
2233mptscsih_slave_alloc(struct scsi_device *sdev)
2234{
2235 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002237 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002239 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002241 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (!vdev) {
2243 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2244 hd->ioc->name, sizeof(VirtDevice));
2245 return -ENOMEM;
2246 }
2247
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 vdev->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002249 vdev->target_id = sdev->id;
2250 vdev->bus_id = sdev->channel;
2251 vdev->lun = sdev->lun;
2252 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002254 starget = scsi_target(sdev);
2255 vtarget = starget->hostdata;
2256 vdev->vtarget = vtarget;
2257
2258 if (vtarget->num_luns == 0) {
2259 hd->Targets[sdev->id] = vtarget;
2260 vtarget->ioc_id = hd->ioc->id;
2261 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2262 vtarget->target_id = sdev->id;
2263 vtarget->bus_id = sdev->channel;
2264 if (hd->ioc->bus_type == SPI) {
2265 if (hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2266 vtarget->raidVolume = 1;
2267 ddvtprintk((KERN_INFO
2268 "RAID Volume @ id %d\n", sdev->id));
2269 }
2270 } else {
2271 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2272 }
2273 }
2274 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 return 0;
2276}
2277
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278/*
2279 * OS entry point to allow for host driver to free allocated memory
2280 * Called if no device present or device being unloaded
2281 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002282void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002283mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002285 if (starget->hostdata)
2286 kfree(starget->hostdata);
2287 starget->hostdata = NULL;
2288}
2289
2290/*
2291 * OS entry point to allow for host driver to free allocated memory
2292 * Called if no device present or device being unloaded
2293 */
2294void
2295mptscsih_slave_destroy(struct scsi_device *sdev)
2296{
2297 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002299 VirtTarget *vtarget;
2300 VirtDevice *vdevice;
2301 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002303 starget = scsi_target(sdev);
2304 vtarget = starget->hostdata;
2305 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002307 mptscsih_search_running_cmds(hd, vdevice);
2308 vtarget->luns[0] &= ~(1 << vdevice->lun);
2309 vtarget->num_luns--;
2310 if (vtarget->num_luns == 0) {
Moore, Erica69ac322006-01-17 17:06:26 -07002311 mptscsih_negotiate_to_asyn_narrow(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002312 if (hd->ioc->bus_type == SPI) {
2313 if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
2314 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2315 } else {
2316 hd->ioc->spi_data.dvStatus[vtarget->target_id] =
2317 MPT_SCSICFG_NEGOTIATE;
2318 if (!hd->negoNvram) {
2319 hd->ioc->spi_data.dvStatus[vtarget->target_id] |=
2320 MPT_SCSICFG_DV_NOT_DONE;
2321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 }
2323 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002326 mptscsih_synchronize_cache(hd, vdevice);
2327 kfree(vdevice);
2328 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329}
2330
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2332/*
2333 * mptscsih_change_queue_depth - This function will set a devices queue depth
2334 * @sdev: per scsi_device pointer
2335 * @qdepth: requested queue depth
2336 *
2337 * Adding support for new 'change_queue_depth' api.
2338*/
2339int
2340mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002342 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2343 VirtTarget *vtarget;
2344 struct scsi_target *starget;
2345 int max_depth;
2346 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002348 starget = scsi_target(sdev);
2349 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002350
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002351 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002352 if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2353 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 max_depth = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002355 else if (((vtarget->inq_data[0] & 0x1f) == 0x00) &&
2356 (vtarget->minSyncFactor <= MPT_ULTRA160 ))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2358 else
2359 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2360 } else {
2361 /* error case - No Inq. Data */
2362 max_depth = 1;
2363 }
2364 } else
2365 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2366
2367 if (qdepth > max_depth)
2368 qdepth = max_depth;
2369 if (qdepth == 1)
2370 tagged = 0;
2371 else
2372 tagged = MSG_SIMPLE_TAG;
2373
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002374 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2375 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376}
2377
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378/*
2379 * OS entry point to adjust the queue_depths on a per-device basis.
2380 * Called once per device the bus scan. Use it to force the queue_depth
2381 * member to 1 if a device does not support Q tags.
2382 * Return non-zero if fails.
2383 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002384int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002385mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002387 struct Scsi_Host *sh = sdev->host;
2388 VirtTarget *vtarget;
2389 VirtDevice *vdevice;
2390 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002394 starget = scsi_target(sdev);
2395 vtarget = starget->hostdata;
2396 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398 dsprintk((MYIOC_s_INFO_FMT
2399 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002400 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2401 if (hd->ioc->bus_type == SPI)
2402 dsprintk((MYIOC_s_INFO_FMT
2403 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2404 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2405 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002409 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 goto slave_configure_exit;
2411 }
2412
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002413 vdevice->configured_lun=1;
2414 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2415 indexed_lun = (vdevice->lun % 32);
2416 vtarget->luns[lun_index] |= (1 << indexed_lun);
2417 mptscsih_initTarget(hd, vtarget, sdev->lun, sdev->inquiry,
2418 sdev->inquiry_len );
2419 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
2421 dsprintk((MYIOC_s_INFO_FMT
2422 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002423 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002425 if (hd->ioc->bus_type == SPI)
2426 dsprintk((MYIOC_s_INFO_FMT
2427 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2428 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2429 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431slave_configure_exit:
2432
2433 dsprintk((MYIOC_s_INFO_FMT
2434 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002435 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2436 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 return 0;
2439}
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2442/*
2443 * Private routines...
2444 */
2445
2446/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2447/* Utility function to copy sense data from the scsi_cmnd buffer
2448 * to the FC and SCSI target structures.
2449 *
2450 */
2451static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002452mptscsih_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 -07002453{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002454 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 SCSIIORequest_t *pReq;
2456 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
2458 /* Get target structure
2459 */
2460 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002461 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
2463 if (sense_count) {
2464 u8 *sense_data;
2465 int req_index;
2466
2467 /* Copy the sense received into the scsi command block. */
2468 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2469 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2470 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2471
2472 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2473 */
2474 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002475 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 int idx;
2477 MPT_ADAPTER *ioc = hd->ioc;
2478
2479 idx = ioc->eventContext % ioc->eventLogSize;
2480 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2481 ioc->events[idx].eventContext = ioc->eventContext;
2482
2483 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2484 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002485 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2488
2489 ioc->eventContext++;
2490 }
2491 }
2492 } else {
2493 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2494 hd->ioc->name));
2495 }
2496}
2497
2498static u32
2499SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2500{
2501 MPT_SCSI_HOST *hd;
2502 int i;
2503
2504 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2505
2506 for (i = 0; i < hd->ioc->req_depth; i++) {
2507 if (hd->ScsiLookup[i] == sc) {
2508 return i;
2509 }
2510 }
2511
2512 return -1;
2513}
2514
2515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002516int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2518{
2519 MPT_SCSI_HOST *hd;
2520 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002521 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 dtmprintk((KERN_WARNING MYNAM
2524 ": IOC %s_reset routed to SCSI host driver!\n",
2525 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2526 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2527
2528 /* If a FW reload request arrives after base installed but
2529 * before all scsi hosts have been attached, then an alt_ioc
2530 * may have a NULL sh pointer.
2531 */
2532 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2533 return 0;
2534 else
2535 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2536
2537 if (reset_phase == MPT_IOC_SETUP_RESET) {
2538 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2539
2540 /* Clean Up:
2541 * 1. Set Hard Reset Pending Flag
2542 * All new commands go to doneQ
2543 */
2544 hd->resetPending = 1;
2545
2546 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2547 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2548
2549 /* 2. Flush running commands
2550 * Clean ScsiLookup (and associated memory)
2551 * AND clean mytaskQ
2552 */
2553
2554 /* 2b. Reply to OS all known outstanding I/O commands.
2555 */
2556 mptscsih_flush_running_cmds(hd);
2557
2558 /* 2c. If there was an internal command that
2559 * has not completed, configuration or io request,
2560 * free these resources.
2561 */
2562 if (hd->cmdPtr) {
2563 del_timer(&hd->timer);
2564 mpt_free_msg_frame(ioc, hd->cmdPtr);
2565 }
2566
2567 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2568
2569 } else {
2570 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2571
2572 /* Once a FW reload begins, all new OS commands are
2573 * redirected to the doneQ w/ a reset status.
2574 * Init all control structures.
2575 */
2576
2577 /* ScsiLookup initialization
2578 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002579 for (ii=0; ii < hd->ioc->req_depth; ii++)
2580 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582 /* 2. Chain Buffer initialization
2583 */
2584
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002585 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002587 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2589 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2590 }
2591
2592 /* 5. Enable new commands to be posted
2593 */
2594 spin_lock_irqsave(&ioc->FreeQlock, flags);
2595 hd->tmPending = 0;
2596 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2597 hd->resetPending = 0;
2598 hd->tmState = TM_STATE_NONE;
2599
2600 /* 6. If there was an internal command,
2601 * wake this process up.
2602 */
2603 if (hd->cmdPtr) {
2604 /*
2605 * Wake up the original calling thread
2606 */
2607 hd->pLocal = &hd->localReply;
2608 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002609 hd->scandv_wait_done = 1;
2610 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 hd->cmdPtr = NULL;
2612 }
2613
Michael Reed05e8ec12006-01-13 14:31:54 -06002614 /* 7. SPI: Set flag to force DV and re-read IOC Page 3
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002616 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2618 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2619 }
2620
Michael Reed05e8ec12006-01-13 14:31:54 -06002621 /* 7. FC: Rescan for blocked rports which might have returned.
2622 */
2623 else if (ioc->bus_type == FC) {
2624 int work_count;
2625 unsigned long flags;
2626
2627 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2628 work_count = ++ioc->fc_rescan_work_count;
2629 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2630 if (work_count == 1)
2631 schedule_work(&ioc->fc_rescan_work);
2632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2634
2635 }
2636
2637 return 1; /* currently means nothing really */
2638}
2639
2640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002641int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2643{
2644 MPT_SCSI_HOST *hd;
2645 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
Michael Reed05e8ec12006-01-13 14:31:54 -06002646 int work_count;
2647 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
2649 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2650 ioc->name, event));
2651
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002652 if (ioc->sh == NULL ||
2653 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2654 return 1;
2655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 switch (event) {
2657 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2658 /* FIXME! */
2659 break;
2660 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2661 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002662 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002663 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 break;
2665 case MPI_EVENT_LOGOUT: /* 09 */
2666 /* FIXME! */
2667 break;
2668
Michael Reed05e8ec12006-01-13 14:31:54 -06002669 case MPI_EVENT_RESCAN: /* 06 */
2670 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2671 work_count = ++ioc->fc_rescan_work_count;
2672 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2673 if (work_count == 1)
2674 schedule_work(&ioc->fc_rescan_work);
2675 break;
2676
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 /*
2678 * CHECKME! Don't think we need to do
2679 * anything for these, but...
2680 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2682 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2683 /*
2684 * CHECKME! Falling thru...
2685 */
2686 break;
2687
2688 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002689 {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07002690#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002691 pMpiEventDataRaid_t pRaidEventData =
2692 (pMpiEventDataRaid_t) pEvReply->Data;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002693 /* Domain Validation Needed */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002694 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002695 pRaidEventData->ReasonCode ==
2696 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2697 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002699 break;
2700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 case MPI_EVENT_NONE: /* 00 */
2703 case MPI_EVENT_LOG_DATA: /* 01 */
2704 case MPI_EVENT_STATE_CHANGE: /* 02 */
2705 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2706 default:
2707 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2708 break;
2709 }
2710
2711 return 1; /* currently means nothing really */
2712}
2713
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2715/*
2716 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2717 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002718 * @vtarget: per target private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 * @lun: SCSI LUN id
2720 * @data: Pointer to data
2721 * @dlen: Number of INQUIRY bytes
2722 *
2723 * NOTE: It's only SAFE to call this routine if data points to
2724 * sane & valid STANDARD INQUIRY data!
2725 *
2726 * Allocate and initialize memory for this target.
2727 * Save inquiry data.
2728 *
2729 */
2730static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002731mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002733 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 char data_56;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002735 int inq_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002738 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740 /*
2741 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2742 * (i.e. The targer is capable of supporting the specified peripheral device type
2743 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002744 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 * capable of supporting a physical device on this logical unit). This is to work
2746 * around a bug in th emid-layer in some distributions in which the mid-layer will
2747 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2748 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002749 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002751
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 /* Is LUN supported? If so, upper 2 bits will be 0
2753 * in first byte of inquiry data.
2754 */
2755 if (data[0] & 0xe0)
2756 return;
2757
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002758 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002761 if (data)
2762 vtarget->type = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002764 if (hd->ioc->bus_type != SPI)
2765 return;
2766
2767 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2768 /* Treat all Processors as SAF-TE if
2769 * command line option is set */
2770 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2771 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
2772 }else if ((data[0] == TYPE_PROCESSOR) &&
2773 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2774 if ( dlen > 49 ) {
2775 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2776 if ( data[44] == 'S' &&
2777 data[45] == 'A' &&
2778 data[46] == 'F' &&
2779 data[47] == '-' &&
2780 data[48] == 'T' &&
2781 data[49] == 'E' ) {
2782 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2783 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 }
2785 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002786 }
2787 if (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2788 inq_len = dlen < 8 ? dlen : 8;
2789 memcpy (vtarget->inq_data, data, inq_len);
2790 /* If have not done DV, set the DV flag.
2791 */
2792 pSpi = &hd->ioc->spi_data;
2793 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2794 if (pSpi->dvStatus[vtarget->target_id] & MPT_SCSICFG_DV_NOT_DONE)
2795 pSpi->dvStatus[vtarget->target_id] |= MPT_SCSICFG_NEED_DV;
2796 }
2797 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002799 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2800 if (dlen > 56) {
2801 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2802 /* Update the target capabilities
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002804 data_56 = data[56];
2805 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002807 }
2808 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
2809 } else {
2810 /* Initial Inquiry may not request enough data bytes to
2811 * obtain byte 57. DV will; if target doesn't return
2812 * at least 57 bytes, data[56] will be zero. */
2813 if (dlen > 56) {
2814 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2815 /* Update the target capabilities
2816 */
2817 data_56 = data[56];
2818 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
2819 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 }
2821 }
2822 }
2823}
2824
2825/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2826/*
2827 * Update the target negotiation parameters based on the
2828 * the Inquiry data, adapter capabilities, and NVRAM settings.
2829 *
2830 */
2831static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002832mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, char byte56)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002834 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 int id = (int) target->target_id;
2836 int nvram;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002837 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 int ii;
2839 u8 width = MPT_NARROW;
2840 u8 factor = MPT_ASYNC;
2841 u8 offset = 0;
2842 u8 version, nfactor;
2843 u8 noQas = 1;
2844
2845 target->negoFlags = pspi_data->noQas;
2846
2847 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2848 * support. If available, default QAS to off and allow enabling.
2849 * If not available, default QAS to on, turn off for non-disks.
2850 */
2851
2852 /* Set flags based on Inquiry data
2853 */
2854 version = target->inq_data[2] & 0x07;
2855 if (version < 2) {
2856 width = 0;
2857 factor = MPT_ULTRA2;
2858 offset = pspi_data->maxSyncOffset;
2859 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2860 } else {
2861 if (target->inq_data[7] & 0x20) {
2862 width = 1;
2863 }
2864
2865 if (target->inq_data[7] & 0x10) {
2866 factor = pspi_data->minSyncFactor;
2867 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2868 /* bits 2 & 3 show Clocking support */
2869 if ((byte56 & 0x0C) == 0)
2870 factor = MPT_ULTRA2;
2871 else {
2872 if ((byte56 & 0x03) == 0)
2873 factor = MPT_ULTRA160;
2874 else {
2875 factor = MPT_ULTRA320;
2876 if (byte56 & 0x02)
2877 {
2878 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2879 noQas = 0;
2880 }
2881 if (target->inq_data[0] == TYPE_TAPE) {
2882 if (byte56 & 0x01)
2883 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2884 }
2885 }
2886 }
2887 } else {
2888 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2889 noQas = 0;
2890 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002891
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 offset = pspi_data->maxSyncOffset;
2893
2894 /* If RAID, never disable QAS
2895 * else if non RAID, do not disable
2896 * QAS if bit 1 is set
2897 * bit 1 QAS support, non-raid only
2898 * bit 0 IU support
2899 */
2900 if (target->raidVolume == 1) {
2901 noQas = 0;
2902 }
2903 } else {
2904 factor = MPT_ASYNC;
2905 offset = 0;
2906 }
2907 }
2908
2909 if ( (target->inq_data[7] & 0x02) == 0) {
2910 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2911 }
2912
2913 /* Update tflags based on NVRAM settings. (SCSI only)
2914 */
2915 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2916 nvram = pspi_data->nvram[id];
2917 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2918
2919 if (width)
2920 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2921
2922 if (offset > 0) {
2923 /* Ensure factor is set to the
2924 * maximum of: adapter, nvram, inquiry
2925 */
2926 if (nfactor) {
2927 if (nfactor < pspi_data->minSyncFactor )
2928 nfactor = pspi_data->minSyncFactor;
2929
2930 factor = max(factor, nfactor);
2931 if (factor == MPT_ASYNC)
2932 offset = 0;
2933 } else {
2934 offset = 0;
2935 factor = MPT_ASYNC;
2936 }
2937 } else {
2938 factor = MPT_ASYNC;
2939 }
2940 }
2941
2942 /* Make sure data is consistent
2943 */
2944 if ((!width) && (factor < MPT_ULTRA2)) {
2945 factor = MPT_ULTRA2;
2946 }
2947
2948 /* Save the data to the target structure.
2949 */
2950 target->minSyncFactor = factor;
2951 target->maxOffset = offset;
2952 target->maxWidth = width;
2953
2954 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2955
2956 /* Disable unused features.
2957 */
2958 if (!width)
2959 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2960
2961 if (!offset)
2962 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2963
2964 if ( factor > MPT_ULTRA320 )
2965 noQas = 0;
2966
2967 /* GEM, processor WORKAROUND
2968 */
2969 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2970 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2971 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2972 } else {
2973 if (noQas && (pspi_data->noQas == 0)) {
2974 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2975 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2976
2977 /* Disable QAS in a mixed configuration case
2978 */
2979
2980 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2981 for (ii = 0; ii < id; ii++) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002982 if ( (vtarget = hd->Targets[ii]) ) {
2983 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2984 mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 }
2987 }
2988 }
2989
2990 /* Write SDP1 on this I/O to this target */
2991 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2992 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2993 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2994 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2995 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2996 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2997 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2998 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2999 }
3000}
3001
3002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003/*
3004 * If no Target, bus reset on 1st I/O. Set the flag to
3005 * prevent any future negotiations to this device.
3006 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003007static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003008mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003010 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003012 if ((vdev = sc->device->hostdata) != NULL)
3013 hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return;
3015}
3016
3017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3018/*
3019 * SCSI Config Page functionality ...
3020 */
3021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3022/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
3023 * based on width, factor and offset parameters.
3024 * @width: bus width
3025 * @factor: sync factor
3026 * @offset: sync offset
3027 * @requestedPtr: pointer to requested values (updated)
3028 * @configurationPtr: pointer to configuration values (updated)
3029 * @flags: flags to block WDTR or SDTR negotiation
3030 *
3031 * Return: None.
3032 *
3033 * Remark: Called by writeSDP1 and _dv_params
3034 */
3035static void
3036mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3037{
3038 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3039 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3040
3041 *configurationPtr = 0;
3042 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3043 *requestedPtr |= (offset << 16) | (factor << 8);
3044
3045 if (width && offset && !nowide && !nosync) {
3046 if (factor < MPT_ULTRA160) {
3047 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3048 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3049 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3050 if (flags & MPT_TAPE_NEGO_IDP)
3051 *requestedPtr |= 0x08000000;
3052 } else if (factor < MPT_ULTRA2) {
3053 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3054 }
3055 }
3056
3057 if (nowide)
3058 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3059
3060 if (nosync)
3061 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3062
3063 return;
3064}
3065
3066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3067/* mptscsih_writeSDP1 - write SCSI Device Page 1
3068 * @hd: Pointer to a SCSI Host Strucutre
3069 * @portnum: IOC port number
3070 * @target_id: writeSDP1 for single ID
3071 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3072 *
3073 * Return: -EFAULT if read of config page header fails
3074 * or 0 if success.
3075 *
3076 * Remark: If a target has been found, the settings from the
3077 * target structure are used, else the device is set
3078 * to async/narrow.
3079 *
3080 * Remark: Called during init and after a FW reload.
3081 * Remark: We do not wait for a return, write pages sequentially.
3082 */
3083static int
3084mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3085{
3086 MPT_ADAPTER *ioc = hd->ioc;
3087 Config_t *pReq;
3088 SCSIDevicePage1_t *pData;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003089 VirtTarget *vtarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 MPT_FRAME_HDR *mf;
3091 dma_addr_t dataDma;
3092 u16 req_idx;
3093 u32 frameOffset;
3094 u32 requested, configuration, flagsLength;
3095 int ii, nvram;
3096 int id = 0, maxid = 0;
3097 u8 width;
3098 u8 factor;
3099 u8 offset;
3100 u8 bus = 0;
3101 u8 negoFlags;
3102 u8 maxwidth, maxoffset, maxfactor;
3103
3104 if (ioc->spi_data.sdp1length == 0)
3105 return 0;
3106
3107 if (flags & MPT_SCSICFG_ALL_IDS) {
3108 id = 0;
3109 maxid = ioc->sh->max_id - 1;
3110 } else if (ioc->sh) {
3111 id = target_id;
3112 maxid = min_t(int, id, ioc->sh->max_id - 1);
3113 }
3114
3115 for (; id <= maxid; id++) {
3116
3117 if (id == ioc->pfacts[portnum].PortSCSIID)
3118 continue;
3119
3120 /* Use NVRAM to get adapter and target maximums
3121 * Data over-riden by target structure information, if present
3122 */
3123 maxwidth = ioc->spi_data.maxBusWidth;
3124 maxoffset = ioc->spi_data.maxSyncOffset;
3125 maxfactor = ioc->spi_data.minSyncFactor;
3126 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3127 nvram = ioc->spi_data.nvram[id];
3128
3129 if (maxwidth)
3130 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3131
3132 if (maxoffset > 0) {
3133 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3134 if (maxfactor == 0) {
3135 /* Key for async */
3136 maxfactor = MPT_ASYNC;
3137 maxoffset = 0;
3138 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3139 maxfactor = ioc->spi_data.minSyncFactor;
3140 }
3141 } else
3142 maxfactor = MPT_ASYNC;
3143 }
3144
3145 /* Set the negotiation flags.
3146 */
3147 negoFlags = ioc->spi_data.noQas;
3148 if (!maxwidth)
3149 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3150
3151 if (!maxoffset)
3152 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3153
3154 if (flags & MPT_SCSICFG_USE_NVRAM) {
3155 width = maxwidth;
3156 factor = maxfactor;
3157 offset = maxoffset;
3158 } else {
3159 width = 0;
3160 factor = MPT_ASYNC;
3161 offset = 0;
3162 //negoFlags = 0;
3163 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3164 }
3165
3166 /* If id is not a raid volume, get the updated
3167 * transmission settings from the target structure.
3168 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003169 if (hd->Targets && (vtarget = hd->Targets[id]) && !vtarget->raidVolume) {
3170 width = vtarget->maxWidth;
3171 factor = vtarget->minSyncFactor;
3172 offset = vtarget->maxOffset;
3173 negoFlags = vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003175
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3177 /* Force to async and narrow if DV has not been executed
3178 * for this ID
3179 */
3180 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3181 width = 0;
3182 factor = MPT_ASYNC;
3183 offset = 0;
3184 }
3185#endif
3186
3187 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003188 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190 mptscsih_setDevicePage1Flags(width, factor, offset,
3191 &requested, &configuration, negoFlags);
3192 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3193 target_id, width, factor, offset, negoFlags, requested, configuration));
3194
3195 /* Get a MF for this command.
3196 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003197 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003198 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3199 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 return -EAGAIN;
3201 }
3202
3203 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3204 hd->ioc->name, mf, id, requested, configuration));
3205
3206
3207 /* Set the request and the data pointers.
3208 * Request takes: 36 bytes (32 bit SGE)
3209 * SCSI Device Page 1 requires 16 bytes
3210 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3211 * and MF size >= 64 bytes.
3212 * Place data at end of MF.
3213 */
3214 pReq = (Config_t *)mf;
3215
3216 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3217 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3218
3219 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3220 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3221
3222 /* Complete the request frame (same for all requests).
3223 */
3224 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3225 pReq->Reserved = 0;
3226 pReq->ChainOffset = 0;
3227 pReq->Function = MPI_FUNCTION_CONFIG;
3228 pReq->ExtPageLength = 0;
3229 pReq->ExtPageType = 0;
3230 pReq->MsgFlags = 0;
3231 for (ii=0; ii < 8; ii++) {
3232 pReq->Reserved2[ii] = 0;
3233 }
3234 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3235 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3236 pReq->Header.PageNumber = 1;
3237 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3238 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3239
3240 /* Add a SGE to the config request.
3241 */
3242 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3243
3244 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3245
3246 /* Set up the common data portion
3247 */
3248 pData->Header.PageVersion = pReq->Header.PageVersion;
3249 pData->Header.PageLength = pReq->Header.PageLength;
3250 pData->Header.PageNumber = pReq->Header.PageNumber;
3251 pData->Header.PageType = pReq->Header.PageType;
3252 pData->RequestedParameters = cpu_to_le32(requested);
3253 pData->Reserved = 0;
3254 pData->Configuration = cpu_to_le32(configuration);
3255
3256 dprintk((MYIOC_s_INFO_FMT
3257 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3258 ioc->name, id, (id | (bus<<8)),
3259 requested, configuration));
3260
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003261 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 }
3263
3264 return 0;
3265}
3266
3267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3268/* mptscsih_writeIOCPage4 - write IOC Page 4
3269 * @hd: Pointer to a SCSI Host Structure
3270 * @target_id: write IOC Page4 for this ID & Bus
3271 *
3272 * Return: -EAGAIN if unable to obtain a Message Frame
3273 * or 0 if success.
3274 *
3275 * Remark: We do not wait for a return, write pages sequentially.
3276 */
3277static int
3278mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3279{
3280 MPT_ADAPTER *ioc = hd->ioc;
3281 Config_t *pReq;
3282 IOCPage4_t *IOCPage4Ptr;
3283 MPT_FRAME_HDR *mf;
3284 dma_addr_t dataDma;
3285 u16 req_idx;
3286 u32 frameOffset;
3287 u32 flagsLength;
3288 int ii;
3289
3290 /* Get a MF for this command.
3291 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003292 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003293 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 ioc->name));
3295 return -EAGAIN;
3296 }
3297
3298 /* Set the request and the data pointers.
3299 * Place data at end of MF.
3300 */
3301 pReq = (Config_t *)mf;
3302
3303 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3304 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3305
3306 /* Complete the request frame (same for all requests).
3307 */
3308 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3309 pReq->Reserved = 0;
3310 pReq->ChainOffset = 0;
3311 pReq->Function = MPI_FUNCTION_CONFIG;
3312 pReq->ExtPageLength = 0;
3313 pReq->ExtPageType = 0;
3314 pReq->MsgFlags = 0;
3315 for (ii=0; ii < 8; ii++) {
3316 pReq->Reserved2[ii] = 0;
3317 }
3318
3319 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3320 dataDma = ioc->spi_data.IocPg4_dma;
3321 ii = IOCPage4Ptr->ActiveSEP++;
3322 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3323 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3324 pReq->Header = IOCPage4Ptr->Header;
3325 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3326
3327 /* Add a SGE to the config request.
3328 */
3329 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3330 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3331
3332 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3333
3334 dinitprintk((MYIOC_s_INFO_FMT
3335 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3336 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3337
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003338 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 return 0;
3341}
3342
3343/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3344/*
3345 * Bus Scan and Domain Validation functionality ...
3346 */
3347
3348/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3349/*
3350 * mptscsih_scandv_complete - Scan and DV callback routine registered
3351 * to Fustion MPT (base) driver.
3352 *
3353 * @ioc: Pointer to MPT_ADAPTER structure
3354 * @mf: Pointer to original MPT request frame
3355 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3356 *
3357 * This routine is called from mpt.c::mpt_interrupt() at the completion
3358 * of any SCSI IO request.
3359 * This routine is registered with the Fusion MPT (base) driver at driver
3360 * load/init time via the mpt_register() API call.
3361 *
3362 * Returns 1 indicating alloc'd request frame ptr should be freed.
3363 *
3364 * Remark: Sets a completion code and (possibly) saves sense data
3365 * in the IOC member localReply structure.
3366 * Used ONLY for DV and other internal commands.
3367 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003368int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3370{
3371 MPT_SCSI_HOST *hd;
3372 SCSIIORequest_t *pReq;
3373 int completionCode;
3374 u16 req_idx;
3375
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003376 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3377
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 if ((mf == NULL) ||
3379 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3380 printk(MYIOC_s_ERR_FMT
3381 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3382 ioc->name, mf?"BAD":"NULL", (void *) mf);
3383 goto wakeup;
3384 }
3385
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 del_timer(&hd->timer);
3387 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3388 hd->ScsiLookup[req_idx] = NULL;
3389 pReq = (SCSIIORequest_t *) mf;
3390
3391 if (mf != hd->cmdPtr) {
3392 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3393 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3394 }
3395 hd->cmdPtr = NULL;
3396
3397 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3398 hd->ioc->name, mf, mr, req_idx));
3399
3400 hd->pLocal = &hd->localReply;
3401 hd->pLocal->scsiStatus = 0;
3402
3403 /* If target struct exists, clear sense valid flag.
3404 */
3405 if (mr == NULL) {
3406 completionCode = MPT_SCANDV_GOOD;
3407 } else {
3408 SCSIIOReply_t *pReply;
3409 u16 status;
3410 u8 scsi_status;
3411
3412 pReply = (SCSIIOReply_t *) mr;
3413
3414 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3415 scsi_status = pReply->SCSIStatus;
3416
3417 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3418 status, pReply->SCSIState, scsi_status,
3419 le32_to_cpu(pReply->IOCLogInfo)));
3420
3421 switch(status) {
3422
3423 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3424 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3425 break;
3426
3427 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3428 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3429 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3430 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3431 completionCode = MPT_SCANDV_DID_RESET;
3432 break;
3433
3434 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3435 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3436 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3437 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3438 ConfigReply_t *pr = (ConfigReply_t *)mr;
3439 completionCode = MPT_SCANDV_GOOD;
3440 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3441 hd->pLocal->header.PageLength = pr->Header.PageLength;
3442 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3443 hd->pLocal->header.PageType = pr->Header.PageType;
3444
3445 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3446 /* If the RAID Volume request is successful,
3447 * return GOOD, else indicate that
3448 * some type of error occurred.
3449 */
3450 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003451 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 completionCode = MPT_SCANDV_GOOD;
3453 else
3454 completionCode = MPT_SCANDV_SOME_ERROR;
3455
3456 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3457 u8 *sense_data;
3458 int sz;
3459
3460 /* save sense data in global structure
3461 */
3462 completionCode = MPT_SCANDV_SENSE;
3463 hd->pLocal->scsiStatus = scsi_status;
3464 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3465 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3466
3467 sz = min_t(int, pReq->SenseBufferLength,
3468 SCSI_STD_SENSE_BYTES);
3469 memcpy(hd->pLocal->sense, sense_data, sz);
3470
3471 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3472 sense_data));
3473 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3474 if (pReq->CDB[0] == INQUIRY)
3475 completionCode = MPT_SCANDV_ISSUE_SENSE;
3476 else
3477 completionCode = MPT_SCANDV_DID_RESET;
3478 }
3479 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3480 completionCode = MPT_SCANDV_DID_RESET;
3481 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3482 completionCode = MPT_SCANDV_DID_RESET;
3483 else {
3484 completionCode = MPT_SCANDV_GOOD;
3485 hd->pLocal->scsiStatus = scsi_status;
3486 }
3487 break;
3488
3489 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3490 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3491 completionCode = MPT_SCANDV_DID_RESET;
3492 else
3493 completionCode = MPT_SCANDV_SOME_ERROR;
3494 break;
3495
3496 default:
3497 completionCode = MPT_SCANDV_SOME_ERROR;
3498 break;
3499
3500 } /* switch(status) */
3501
3502 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3503 completionCode));
3504 } /* end of address reply case */
3505
3506 hd->pLocal->completion = completionCode;
3507
3508 /* MF and RF are freed in mpt_interrupt
3509 */
3510wakeup:
3511 /* Free Chain buffers (will never chain) in scan or dv */
3512 //mptscsih_freeChainBuffers(ioc, req_idx);
3513
3514 /*
3515 * Wake up the original calling thread
3516 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003517 hd->scandv_wait_done = 1;
3518 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 return 1;
3521}
3522
3523/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3524/* mptscsih_timer_expired - Call back for timer process.
3525 * Used only for dv functionality.
3526 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3527 *
3528 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003529void
3530mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531{
3532 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3533
3534 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3535
3536 if (hd->cmdPtr) {
3537 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3538
3539 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3540 /* Desire to issue a task management request here.
3541 * TM requests MUST be single threaded.
3542 * If old eh code and no TM current, issue request.
3543 * If new eh code, do nothing. Wait for OS cmd timeout
3544 * for bus reset.
3545 */
3546 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3547 } else {
3548 /* Perform a FW reload */
3549 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3550 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3551 }
3552 }
3553 } else {
3554 /* This should NEVER happen */
3555 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3556 }
3557
3558 /* No more processing.
3559 * TM call will generate an interrupt for SCSI TM Management.
3560 * The FW will reply to all outstanding commands, callback will finish cleanup.
3561 * Hard reset clean-up will free all resources.
3562 */
3563 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3564
3565 return;
3566}
3567
3568#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3570/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3571 * @hd: Pointer to scsi host structure
3572 * @action: What do be done.
3573 * @id: Logical target id.
3574 * @bus: Target locations bus.
3575 *
3576 * Returns: < 0 on a fatal error
3577 * 0 on success
3578 *
3579 * Remark: Wait to return until reply processed by the ISR.
3580 */
3581static int
3582mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3583{
3584 MpiRaidActionRequest_t *pReq;
3585 MPT_FRAME_HDR *mf;
3586 int in_isr;
3587
3588 in_isr = in_interrupt();
3589 if (in_isr) {
3590 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3591 hd->ioc->name));
3592 return -EPERM;
3593 }
3594
3595 /* Get and Populate a free Frame
3596 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003597 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3599 hd->ioc->name));
3600 return -EAGAIN;
3601 }
3602 pReq = (MpiRaidActionRequest_t *)mf;
3603 pReq->Action = action;
3604 pReq->Reserved1 = 0;
3605 pReq->ChainOffset = 0;
3606 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3607 pReq->VolumeID = io->id;
3608 pReq->VolumeBus = io->bus;
3609 pReq->PhysDiskNum = io->physDiskNum;
3610 pReq->MsgFlags = 0;
3611 pReq->Reserved2 = 0;
3612 pReq->ActionDataWord = 0; /* Reserved for this action */
3613 //pReq->ActionDataSGE = 0;
3614
3615 mpt_add_sge((char *)&pReq->ActionDataSGE,
3616 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3617
3618 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3619 hd->ioc->name, action, io->id));
3620
3621 hd->pLocal = NULL;
3622 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003623 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624
3625 /* Save cmd pointer, for resource free if timeout or
3626 * FW reload occurs
3627 */
3628 hd->cmdPtr = mf;
3629
3630 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003631 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3632 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633
3634 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3635 return -1;
3636
3637 return 0;
3638}
3639#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3640
3641/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3642/**
3643 * mptscsih_do_cmd - Do internal command.
3644 * @hd: MPT_SCSI_HOST pointer
3645 * @io: INTERNAL_CMD pointer.
3646 *
3647 * Issue the specified internally generated command and do command
3648 * specific cleanup. For bus scan / DV only.
3649 * NOTES: If command is Inquiry and status is good,
3650 * initialize a target structure, save the data
3651 *
3652 * Remark: Single threaded access only.
3653 *
3654 * Return:
3655 * < 0 if an illegal command or no resources
3656 *
3657 * 0 if good
3658 *
3659 * > 0 if command complete but some type of completion error.
3660 */
3661static int
3662mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3663{
3664 MPT_FRAME_HDR *mf;
3665 SCSIIORequest_t *pScsiReq;
3666 SCSIIORequest_t ReqCopy;
3667 int my_idx, ii, dir;
3668 int rc, cmdTimeout;
3669 int in_isr;
3670 char cmdLen;
3671 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3672 char cmd = io->cmd;
3673
3674 in_isr = in_interrupt();
3675 if (in_isr) {
3676 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3677 hd->ioc->name));
3678 return -EPERM;
3679 }
3680
3681
3682 /* Set command specific information
3683 */
3684 switch (cmd) {
3685 case INQUIRY:
3686 cmdLen = 6;
3687 dir = MPI_SCSIIO_CONTROL_READ;
3688 CDB[0] = cmd;
3689 CDB[4] = io->size;
3690 cmdTimeout = 10;
3691 break;
3692
3693 case TEST_UNIT_READY:
3694 cmdLen = 6;
3695 dir = MPI_SCSIIO_CONTROL_READ;
3696 cmdTimeout = 10;
3697 break;
3698
3699 case START_STOP:
3700 cmdLen = 6;
3701 dir = MPI_SCSIIO_CONTROL_READ;
3702 CDB[0] = cmd;
3703 CDB[4] = 1; /*Spin up the disk */
3704 cmdTimeout = 15;
3705 break;
3706
3707 case REQUEST_SENSE:
3708 cmdLen = 6;
3709 CDB[0] = cmd;
3710 CDB[4] = io->size;
3711 dir = MPI_SCSIIO_CONTROL_READ;
3712 cmdTimeout = 10;
3713 break;
3714
3715 case READ_BUFFER:
3716 cmdLen = 10;
3717 dir = MPI_SCSIIO_CONTROL_READ;
3718 CDB[0] = cmd;
3719 if (io->flags & MPT_ICFLAG_ECHO) {
3720 CDB[1] = 0x0A;
3721 } else {
3722 CDB[1] = 0x02;
3723 }
3724
3725 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3726 CDB[1] |= 0x01;
3727 }
3728 CDB[6] = (io->size >> 16) & 0xFF;
3729 CDB[7] = (io->size >> 8) & 0xFF;
3730 CDB[8] = io->size & 0xFF;
3731 cmdTimeout = 10;
3732 break;
3733
3734 case WRITE_BUFFER:
3735 cmdLen = 10;
3736 dir = MPI_SCSIIO_CONTROL_WRITE;
3737 CDB[0] = cmd;
3738 if (io->flags & MPT_ICFLAG_ECHO) {
3739 CDB[1] = 0x0A;
3740 } else {
3741 CDB[1] = 0x02;
3742 }
3743 CDB[6] = (io->size >> 16) & 0xFF;
3744 CDB[7] = (io->size >> 8) & 0xFF;
3745 CDB[8] = io->size & 0xFF;
3746 cmdTimeout = 10;
3747 break;
3748
3749 case RESERVE:
3750 cmdLen = 6;
3751 dir = MPI_SCSIIO_CONTROL_READ;
3752 CDB[0] = cmd;
3753 cmdTimeout = 10;
3754 break;
3755
3756 case RELEASE:
3757 cmdLen = 6;
3758 dir = MPI_SCSIIO_CONTROL_READ;
3759 CDB[0] = cmd;
3760 cmdTimeout = 10;
3761 break;
3762
3763 case SYNCHRONIZE_CACHE:
3764 cmdLen = 10;
3765 dir = MPI_SCSIIO_CONTROL_READ;
3766 CDB[0] = cmd;
3767// CDB[1] = 0x02; /* set immediate bit */
3768 cmdTimeout = 10;
3769 break;
3770
3771 default:
3772 /* Error Case */
3773 return -EFAULT;
3774 }
3775
3776 /* Get and Populate a free Frame
3777 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003778 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3780 hd->ioc->name));
3781 return -EBUSY;
3782 }
3783
3784 pScsiReq = (SCSIIORequest_t *) mf;
3785
3786 /* Get the request index */
3787 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3788 ADD_INDEX_LOG(my_idx); /* for debug */
3789
3790 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3791 pScsiReq->TargetID = io->physDiskNum;
3792 pScsiReq->Bus = 0;
3793 pScsiReq->ChainOffset = 0;
3794 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3795 } else {
3796 pScsiReq->TargetID = io->id;
3797 pScsiReq->Bus = io->bus;
3798 pScsiReq->ChainOffset = 0;
3799 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3800 }
3801
3802 pScsiReq->CDBLength = cmdLen;
3803 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3804
3805 pScsiReq->Reserved = 0;
3806
3807 pScsiReq->MsgFlags = mpt_msg_flags();
3808 /* MsgContext set in mpt_get_msg_fram call */
3809
3810 for (ii=0; ii < 8; ii++)
3811 pScsiReq->LUN[ii] = 0;
3812 pScsiReq->LUN[1] = io->lun;
3813
3814 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3815 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3816 else
3817 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3818
3819 if (cmd == REQUEST_SENSE) {
3820 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3821 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3822 hd->ioc->name, cmd));
3823 }
3824
3825 for (ii=0; ii < 16; ii++)
3826 pScsiReq->CDB[ii] = CDB[ii];
3827
3828 pScsiReq->DataLength = cpu_to_le32(io->size);
3829 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3830 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3831
3832 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3833 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3834
3835 if (dir == MPI_SCSIIO_CONTROL_READ) {
3836 mpt_add_sge((char *) &pScsiReq->SGL,
3837 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3838 io->data_dma);
3839 } else {
3840 mpt_add_sge((char *) &pScsiReq->SGL,
3841 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3842 io->data_dma);
3843 }
3844
3845 /* The ISR will free the request frame, but we need
3846 * the information to initialize the target. Duplicate.
3847 */
3848 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3849
3850 /* Issue this command after:
3851 * finish init
3852 * add timer
3853 * Wait until the reply has been received
3854 * ScsiScanDvCtx callback function will
3855 * set hd->pLocal;
3856 * set scandv_wait_done and call wake_up
3857 */
3858 hd->pLocal = NULL;
3859 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003860 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
3862 /* Save cmd pointer, for resource free if timeout or
3863 * FW reload occurs
3864 */
3865 hd->cmdPtr = mf;
3866
3867 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003868 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3869 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
3871 if (hd->pLocal) {
3872 rc = hd->pLocal->completion;
3873 hd->pLocal->skip = 0;
3874
3875 /* Always set fatal error codes in some cases.
3876 */
3877 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3878 rc = -ENXIO;
3879 else if (rc == MPT_SCANDV_SOME_ERROR)
3880 rc = -rc;
3881 } else {
3882 rc = -EFAULT;
3883 /* This should never happen. */
3884 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3885 hd->ioc->name));
3886 }
3887
3888 return rc;
3889}
3890
3891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3892/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003893 * mptscsih_negotiate_to_asyn_narrow - Restore devices to default state
3894 * @hd: Pointer to a SCSI HOST structure
3895 * @vtarget: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 *
3897 * Uses the ISR, but with special processing.
3898 * MUST be single-threaded.
3899 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003901static void
Moore, Erica69ac322006-01-17 17:06:26 -07003902mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903{
Moore, Erica69ac322006-01-17 17:06:26 -07003904 VirtTarget *vtarget = vdevice->vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 MPT_ADAPTER *ioc= hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003906 SCSIDevicePage1_t *pcfg1Data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 CONFIGPARMS cfg;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003908 dma_addr_t cfg1_dma_addr;
3909 ConfigPageHeader_t header;
3910 int id;
3911 int requested, configuration, data,i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 u8 flags, factor;
3913
Moore, Erica69ac322006-01-17 17:06:26 -07003914 if ((ioc->bus_type != SPI) ||
3915 (!vdevice->configured_lun))
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003916 return;
3917
3918 if (!ioc->spi_data.sdp1length)
3919 return;
3920
3921 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3922 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3923
3924 if (pcfg1Data == NULL)
3925 return;
3926
3927 header.PageVersion = ioc->spi_data.sdp1version;
3928 header.PageLength = ioc->spi_data.sdp1length;
3929 header.PageNumber = 1;
3930 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3931 cfg.cfghdr.hdr = &header;
3932 cfg.physAddr = cfg1_dma_addr;
3933 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3934 cfg.dir = 1;
3935 cfg.timeout = 0;
3936
3937 if (vtarget->raidVolume && ioc->raid_data.pIocPg3) {
3938 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3939 id = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID;
3940 flags = hd->ioc->spi_data.noQas;
3941 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3942 data = hd->ioc->spi_data.nvram[id];
3943 if (data & MPT_NVRAM_WIDE_DISABLE)
3944 flags |= MPT_TARGET_NO_NEGO_WIDE;
3945 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
3946 if ((factor == 0) || (factor == MPT_ASYNC))
3947 flags |= MPT_TARGET_NO_NEGO_SYNC;
3948 }
3949 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3950 &configuration, flags);
Moore, Erica69ac322006-01-17 17:06:26 -07003951 dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003952 "offset=0 negoFlags=%x request=%x config=%x\n",
3953 id, flags, requested, configuration));
3954 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3955 pcfg1Data->Reserved = 0;
3956 pcfg1Data->Configuration = cpu_to_le32(configuration);
3957 cfg.pageAddr = (vtarget->bus_id<<8) | id;
3958 mpt_config(hd->ioc, &cfg);
3959 }
3960 } else {
3961 flags = vtarget->negoFlags;
3962 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3963 &configuration, flags);
Moore, Erica69ac322006-01-17 17:06:26 -07003964 dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003965 "offset=0 negoFlags=%x request=%x config=%x\n",
3966 vtarget->target_id, flags, requested, configuration));
3967 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3968 pcfg1Data->Reserved = 0;
3969 pcfg1Data->Configuration = cpu_to_le32(configuration);
3970 cfg.pageAddr = (vtarget->bus_id<<8) | vtarget->target_id;
3971 mpt_config(hd->ioc, &cfg);
3972 }
3973
3974 if (pcfg1Data)
3975 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr);
3976}
3977
3978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3979/**
3980 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3981 * @hd: Pointer to a SCSI HOST structure
3982 * @vtarget: per device private data
3983 * @lun: lun
3984 *
3985 * Uses the ISR, but with special processing.
3986 * MUST be single-threaded.
3987 *
3988 */
3989static void
3990mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3991{
3992 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993
3994 /* Following parameters will not change
3995 * in this routine.
3996 */
3997 iocmd.cmd = SYNCHRONIZE_CACHE;
3998 iocmd.flags = 0;
3999 iocmd.physDiskNum = -1;
4000 iocmd.data = NULL;
4001 iocmd.data_dma = -1;
4002 iocmd.size = 0;
4003 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004004 iocmd.bus = vdevice->bus_id;
4005 iocmd.id = vdevice->target_id;
4006 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004008 if ((vdevice->vtarget->type & TYPE_DISK) &&
4009 (vdevice->configured_lun))
4010 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011}
4012
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07004013/* Search IOC page 3 to determine if this is hidden physical disk
4014 */
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07004015static int
4016mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
4017{
4018 int i;
4019
4020 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
4021 return 0;
4022
4023 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
4024 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
4025 return 1;
4026 }
4027
4028 return 0;
4029}
4030
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
4032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4033/**
4034 * mptscsih_domainValidation - Top level handler for domain validation.
4035 * @hd: Pointer to MPT_SCSI_HOST structure.
4036 *
4037 * Uses the ISR, but with special processing.
4038 * Called from schedule, should not be in interrupt mode.
4039 * While thread alive, do dv for all devices needing dv
4040 *
4041 * Return: None.
4042 */
4043static void
4044mptscsih_domainValidation(void *arg)
4045{
4046 MPT_SCSI_HOST *hd;
4047 MPT_ADAPTER *ioc;
4048 unsigned long flags;
4049 int id, maxid, dvStatus, did;
4050 int ii, isPhysDisk;
4051
4052 spin_lock_irqsave(&dvtaskQ_lock, flags);
4053 dvtaskQ_active = 1;
4054 if (dvtaskQ_release) {
4055 dvtaskQ_active = 0;
4056 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4057 return;
4058 }
4059 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4060
4061 /* For this ioc, loop through all devices and do dv to each device.
4062 * When complete with this ioc, search through the ioc list, and
4063 * for each scsi ioc found, do dv for all devices. Exit when no
4064 * device needs dv.
4065 */
4066 did = 1;
4067 while (did) {
4068 did = 0;
4069 list_for_each_entry(ioc, &ioc_list, list) {
4070 spin_lock_irqsave(&dvtaskQ_lock, flags);
4071 if (dvtaskQ_release) {
4072 dvtaskQ_active = 0;
4073 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4074 return;
4075 }
4076 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4077
4078 msleep(250);
4079
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004080 /* DV only to SPI adapters */
4081 if (ioc->bus_type != SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 continue;
4083
4084 /* Make sure everything looks ok */
4085 if (ioc->sh == NULL)
4086 continue;
4087
4088 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4089 if (hd == NULL)
4090 continue;
4091
4092 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4093 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004094 if (ioc->raid_data.pIocPg3) {
4095 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4096 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097
4098 while (numPDisk) {
4099 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4100 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4101
4102 pPDisk++;
4103 numPDisk--;
4104 }
4105 }
4106 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4107 }
4108
4109 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4110
4111 for (id = 0; id < maxid; id++) {
4112 spin_lock_irqsave(&dvtaskQ_lock, flags);
4113 if (dvtaskQ_release) {
4114 dvtaskQ_active = 0;
4115 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4116 return;
4117 }
4118 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4119 dvStatus = hd->ioc->spi_data.dvStatus[id];
4120
4121 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4122 did++;
4123 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4124 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4125
4126 msleep(250);
4127
4128 /* If hidden phys disk, block IO's to all
4129 * raid volumes
4130 * else, process normally
4131 */
4132 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4133 if (isPhysDisk) {
4134 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004135 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4137 }
4138 }
4139 }
4140
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004141 if(mpt_alt_ioc_wait(hd->ioc)!=0) {
4142 ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
4143 hd->ioc->name));
4144 continue;
4145 }
4146
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 if (mptscsih_doDv(hd, 0, id) == 1) {
4148 /* Untagged device was busy, try again
4149 */
4150 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4151 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4152 } else {
4153 /* DV is complete. Clear flags.
4154 */
4155 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4156 }
4157
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004158 spin_lock(&hd->ioc->initializing_hba_lock);
4159 hd->ioc->initializing_hba_lock_flag=0;
4160 spin_unlock(&hd->ioc->initializing_hba_lock);
4161
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 if (isPhysDisk) {
4163 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004164 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4166 }
4167 }
4168 }
4169
4170 if (hd->ioc->spi_data.noQas)
4171 mptscsih_qas_check(hd, id);
4172 }
4173 }
4174 }
4175 }
4176
4177 spin_lock_irqsave(&dvtaskQ_lock, flags);
4178 dvtaskQ_active = 0;
4179 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4180
4181 return;
4182}
4183
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184/* Write SDP1 if no QAS has been enabled
4185 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004186static void
4187mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004189 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 int ii;
4191
4192 if (hd->Targets == NULL)
4193 return;
4194
4195 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4196 if (ii == id)
4197 continue;
4198
4199 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4200 continue;
4201
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004202 vtarget = hd->Targets[ii];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004204 if ((vtarget != NULL) && (!vtarget->raidVolume)) {
4205 if ((vtarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4206 vtarget->negoFlags |= hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4208 mptscsih_writeSDP1(hd, 0, ii, 0);
4209 }
4210 } else {
4211 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4212 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4213 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4214 }
4215 }
4216 }
4217 return;
4218}
4219
4220
4221
4222#define MPT_GET_NVRAM_VALS 0x01
4223#define MPT_UPDATE_MAX 0x02
4224#define MPT_SET_MAX 0x04
4225#define MPT_SET_MIN 0x08
4226#define MPT_FALLBACK 0x10
4227#define MPT_SAVE 0x20
4228
4229/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4230/**
4231 * mptscsih_doDv - Perform domain validation to a target.
4232 * @hd: Pointer to MPT_SCSI_HOST structure.
4233 * @portnum: IOC port number.
4234 * @target: Physical ID of this target
4235 *
4236 * Uses the ISR, but with special processing.
4237 * MUST be single-threaded.
4238 * Test will exit if target is at async & narrow.
4239 *
4240 * Return: None.
4241 */
4242static int
4243mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4244{
4245 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004246 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 SCSIDevicePage1_t *pcfg1Data;
4248 SCSIDevicePage0_t *pcfg0Data;
4249 u8 *pbuf1;
4250 u8 *pbuf2;
4251 u8 *pDvBuf;
4252 dma_addr_t dvbuf_dma = -1;
4253 dma_addr_t buf1_dma = -1;
4254 dma_addr_t buf2_dma = -1;
4255 dma_addr_t cfg1_dma_addr = -1;
4256 dma_addr_t cfg0_dma_addr = -1;
4257 ConfigPageHeader_t header1;
4258 ConfigPageHeader_t header0;
4259 DVPARAMETERS dv;
4260 INTERNAL_CMD iocmd;
4261 CONFIGPARMS cfg;
4262 int dv_alloc = 0;
4263 int rc, sz = 0;
4264 int bufsize = 0;
4265 int dataBufSize = 0;
4266 int echoBufSize = 0;
4267 int notDone;
4268 int patt;
4269 int repeat;
4270 int retcode = 0;
4271 int nfactor = MPT_ULTRA320;
4272 char firstPass = 1;
4273 char doFallback = 0;
4274 char readPage0;
4275 char bus, lun;
4276 char inq0 = 0;
4277
4278 if (ioc->spi_data.sdp1length == 0)
4279 return 0;
4280
4281 if (ioc->spi_data.sdp0length == 0)
4282 return 0;
4283
4284 /* If multiple buses are used, require that the initiator
4285 * id be the same on all buses.
4286 */
4287 if (id == ioc->pfacts[0].PortSCSIID)
4288 return 0;
4289
4290 lun = 0;
4291 bus = (u8) bus_number;
4292 ddvtprintk((MYIOC_s_NOTE_FMT
4293 "DV started: bus=%d, id=%d dv @ %p\n",
4294 ioc->name, bus, id, &dv));
4295
4296 /* Prep DV structure
4297 */
4298 memset (&dv, 0, sizeof(DVPARAMETERS));
4299 dv.id = id;
4300
4301 /* Populate tmax with the current maximum
4302 * transfer parameters for this target.
4303 * Exit if narrow and async.
4304 */
4305 dv.cmd = MPT_GET_NVRAM_VALS;
4306 mptscsih_dv_parms(hd, &dv, NULL);
4307
4308 /* Prep SCSI IO structure
4309 */
4310 iocmd.id = id;
4311 iocmd.bus = bus;
4312 iocmd.lun = lun;
4313 iocmd.flags = 0;
4314 iocmd.physDiskNum = -1;
4315 iocmd.rsvd = iocmd.rsvd2 = 0;
4316
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004317 vtarget = hd->Targets[id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
4319 /* Use tagged commands if possible.
4320 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004321 if (vtarget) {
4322 if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4324 else {
4325 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4326 return 0;
4327
4328 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4329 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4330 return 0;
4331 }
4332 }
4333
4334 /* Prep cfg structure
4335 */
4336 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004337 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
4339 /* Prep SDP0 header
4340 */
4341 header0.PageVersion = ioc->spi_data.sdp0version;
4342 header0.PageLength = ioc->spi_data.sdp0length;
4343 header0.PageNumber = 0;
4344 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4345
4346 /* Prep SDP1 header
4347 */
4348 header1.PageVersion = ioc->spi_data.sdp1version;
4349 header1.PageLength = ioc->spi_data.sdp1length;
4350 header1.PageNumber = 1;
4351 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4352
4353 if (header0.PageLength & 1)
4354 dv_alloc = (header0.PageLength * 4) + 4;
4355
4356 dv_alloc += (2048 + (header1.PageLength * 4));
4357
4358 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4359 if (pDvBuf == NULL)
4360 return 0;
4361
4362 sz = 0;
4363 pbuf1 = (u8 *)pDvBuf;
4364 buf1_dma = dvbuf_dma;
4365 sz +=1024;
4366
4367 pbuf2 = (u8 *) (pDvBuf + sz);
4368 buf2_dma = dvbuf_dma + sz;
4369 sz +=1024;
4370
4371 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4372 cfg0_dma_addr = dvbuf_dma + sz;
4373 sz += header0.PageLength * 4;
4374
4375 /* 8-byte alignment
4376 */
4377 if (header0.PageLength & 1)
4378 sz += 4;
4379
4380 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4381 cfg1_dma_addr = dvbuf_dma + sz;
4382
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004383 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 */
4385 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004386 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4388 /* Set the factor from nvram */
4389 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4390 if (nfactor < pspi_data->minSyncFactor )
4391 nfactor = pspi_data->minSyncFactor;
4392
4393 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4394 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4395
4396 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4397 ioc->name, bus, id, lun));
4398
4399 dv.cmd = MPT_SET_MAX;
4400 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004401 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402
4403 /* Save the final negotiated settings to
4404 * SCSI device page 1.
4405 */
4406 cfg.physAddr = cfg1_dma_addr;
4407 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4408 cfg.dir = 1;
4409 mpt_config(hd->ioc, &cfg);
4410 goto target_done;
4411 }
4412 }
4413 }
4414
4415 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004416 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 /* Search IOC page 3 for matching id
4418 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004419 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4420 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
4422 while (numPDisk) {
4423 if (pPDisk->PhysDiskID == id) {
4424 /* match */
4425 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4426 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4427
4428 /* Quiesce the IM
4429 */
4430 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4431 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4432 goto target_done;
4433 }
4434 break;
4435 }
4436 pPDisk++;
4437 numPDisk--;
4438 }
4439 }
4440
4441 /* RAID Volume ID's may double for a physical device. If RAID but
4442 * not a physical ID as well, skip DV.
4443 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004444 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 goto target_done;
4446
4447
4448 /* Basic Test.
4449 * Async & Narrow - Inquiry
4450 * Async & Narrow - Inquiry
4451 * Maximum transfer rate - Inquiry
4452 * Compare buffers:
4453 * If compare, test complete.
4454 * If miscompare and first pass, repeat
4455 * If miscompare and not first pass, fall back and repeat
4456 */
4457 hd->pLocal = NULL;
4458 readPage0 = 0;
4459 sz = SCSI_MAX_INQUIRY_BYTES;
4460 rc = MPT_SCANDV_GOOD;
4461 while (1) {
4462 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4463 retcode = 0;
4464 dv.cmd = MPT_SET_MIN;
4465 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4466
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004467 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 cfg.physAddr = cfg1_dma_addr;
4469 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4470 cfg.dir = 1;
4471 if (mpt_config(hd->ioc, &cfg) != 0)
4472 goto target_done;
4473
4474 /* Wide - narrow - wide workaround case
4475 */
4476 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4477 /* Send an untagged command to reset disk Qs corrupted
4478 * when a parity error occurs on a Request Sense.
4479 */
4480 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4481 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4482 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4483
4484 iocmd.cmd = REQUEST_SENSE;
4485 iocmd.data_dma = buf1_dma;
4486 iocmd.data = pbuf1;
4487 iocmd.size = 0x12;
4488 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4489 goto target_done;
4490 else {
4491 if (hd->pLocal == NULL)
4492 goto target_done;
4493 rc = hd->pLocal->completion;
4494 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4495 dv.max.width = 0;
4496 doFallback = 0;
4497 } else
4498 goto target_done;
4499 }
4500 } else
4501 goto target_done;
4502 }
4503
4504 iocmd.cmd = INQUIRY;
4505 iocmd.data_dma = buf1_dma;
4506 iocmd.data = pbuf1;
4507 iocmd.size = sz;
4508 memset(pbuf1, 0x00, sz);
4509 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4510 goto target_done;
4511 else {
4512 if (hd->pLocal == NULL)
4513 goto target_done;
4514 rc = hd->pLocal->completion;
4515 if (rc == MPT_SCANDV_GOOD) {
4516 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4517 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4518 retcode = 1;
4519 else
4520 retcode = 0;
4521
4522 goto target_done;
4523 }
4524 } else if (rc == MPT_SCANDV_SENSE) {
4525 ;
4526 } else {
4527 /* If first command doesn't complete
4528 * with a good status or with a check condition,
4529 * exit.
4530 */
4531 goto target_done;
4532 }
4533 }
4534
4535 /* Reset the size for disks
4536 */
4537 inq0 = (*pbuf1) & 0x1F;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004538 if ((inq0 == 0) && vtarget && !vtarget->raidVolume) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 sz = 0x40;
4540 iocmd.size = sz;
4541 }
4542
4543 /* Another GEM workaround. Check peripheral device type,
4544 * if PROCESSOR, quit DV.
4545 */
4546 if (inq0 == TYPE_PROCESSOR) {
4547 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004548 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 lun,
4550 pbuf1,
4551 sz);
4552 goto target_done;
4553 }
4554
4555 if (inq0 > 0x08)
4556 goto target_done;
4557
4558 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4559 goto target_done;
4560
4561 if (sz == 0x40) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004562 if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A)
4563 && (vtarget->minSyncFactor > 0x09)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 if ((pbuf1[56] & 0x04) == 0)
4565 ;
4566 else if ((pbuf1[56] & 0x01) == 1) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004567 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4569 } else {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004570 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4572 }
4573
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004574 dv.max.factor = vtarget->minSyncFactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575
4576 if ((pbuf1[56] & 0x02) == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004577 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004579 ddvprintk((MYIOC_s_NOTE_FMT
4580 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 ioc->name, id, pbuf1[56]));
4582 }
4583 }
4584 }
4585
4586 if (doFallback)
4587 dv.cmd = MPT_FALLBACK;
4588 else
4589 dv.cmd = MPT_SET_MAX;
4590
4591 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4592 if (mpt_config(hd->ioc, &cfg) != 0)
4593 goto target_done;
4594
4595 if ((!dv.now.width) && (!dv.now.offset))
4596 goto target_done;
4597
4598 iocmd.cmd = INQUIRY;
4599 iocmd.data_dma = buf2_dma;
4600 iocmd.data = pbuf2;
4601 iocmd.size = sz;
4602 memset(pbuf2, 0x00, sz);
4603 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4604 goto target_done;
4605 else if (hd->pLocal == NULL)
4606 goto target_done;
4607 else {
4608 /* Save the return code.
4609 * If this is the first pass,
4610 * read SCSI Device Page 0
4611 * and update the target max parameters.
4612 */
4613 rc = hd->pLocal->completion;
4614 doFallback = 0;
4615 if (rc == MPT_SCANDV_GOOD) {
4616 if (!readPage0) {
4617 u32 sdp0_info;
4618 u32 sdp0_nego;
4619
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004620 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 cfg.physAddr = cfg0_dma_addr;
4622 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4623 cfg.dir = 0;
4624
4625 if (mpt_config(hd->ioc, &cfg) != 0)
4626 goto target_done;
4627
4628 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4629 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4630
4631 /* Quantum and Fujitsu workarounds.
4632 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4633 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4634 * Resetart with a request for U160.
4635 */
4636 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4637 doFallback = 1;
4638 } else {
4639 dv.cmd = MPT_UPDATE_MAX;
4640 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4641 /* Update the SCSI device page 1 area
4642 */
4643 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4644 readPage0 = 1;
4645 }
4646 }
4647
4648 /* Quantum workaround. Restart this test will the fallback
4649 * flag set.
4650 */
4651 if (doFallback == 0) {
4652 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4653 if (!firstPass)
4654 doFallback = 1;
4655 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004656 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4658 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4659 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004660 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 lun,
4662 pbuf1,
4663 sz);
4664 break; /* test complete */
4665 }
4666 }
4667
4668
4669 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4670 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004671 else if ((rc == MPT_SCANDV_DID_RESET) ||
4672 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 (rc == MPT_SCANDV_FALLBACK))
4674 doFallback = 1; /* set fallback flag */
4675 else
4676 goto target_done;
4677
4678 firstPass = 0;
4679 }
4680 }
4681 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4682
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004683 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 goto target_done;
4685
4686 inq0 = (*pbuf1) & 0x1F;
4687
4688 /* Continue only for disks
4689 */
4690 if (inq0 != 0)
4691 goto target_done;
4692
4693 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4694 goto target_done;
4695
4696 /* Start the Enhanced Test.
4697 * 0) issue TUR to clear out check conditions
4698 * 1) read capacity of echo (regular) buffer
4699 * 2) reserve device
4700 * 3) do write-read-compare data pattern test
4701 * 4) release
4702 * 5) update nego parms to target struct
4703 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004704 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 cfg.physAddr = cfg1_dma_addr;
4706 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4707 cfg.dir = 1;
4708
4709 iocmd.cmd = TEST_UNIT_READY;
4710 iocmd.data_dma = -1;
4711 iocmd.data = NULL;
4712 iocmd.size = 0;
4713 notDone = 1;
4714 while (notDone) {
4715 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4716 goto target_done;
4717
4718 if (hd->pLocal == NULL)
4719 goto target_done;
4720
4721 rc = hd->pLocal->completion;
4722 if (rc == MPT_SCANDV_GOOD)
4723 notDone = 0;
4724 else if (rc == MPT_SCANDV_SENSE) {
4725 u8 skey = hd->pLocal->sense[2] & 0x0F;
4726 u8 asc = hd->pLocal->sense[12];
4727 u8 ascq = hd->pLocal->sense[13];
4728 ddvprintk((MYIOC_s_INFO_FMT
4729 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4730 ioc->name, skey, asc, ascq));
4731
4732 if (skey == UNIT_ATTENTION)
4733 notDone++; /* repeat */
4734 else if ((skey == NOT_READY) &&
4735 (asc == 0x04)&&(ascq == 0x01)) {
4736 /* wait then repeat */
4737 mdelay (2000);
4738 notDone++;
4739 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4740 /* no medium, try read test anyway */
4741 notDone = 0;
4742 } else {
4743 /* All other errors are fatal.
4744 */
4745 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4746 ioc->name));
4747 goto target_done;
4748 }
4749 } else
4750 goto target_done;
4751 }
4752
4753 iocmd.cmd = READ_BUFFER;
4754 iocmd.data_dma = buf1_dma;
4755 iocmd.data = pbuf1;
4756 iocmd.size = 4;
4757 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4758
4759 dataBufSize = 0;
4760 echoBufSize = 0;
4761 for (patt = 0; patt < 2; patt++) {
4762 if (patt == 0)
4763 iocmd.flags |= MPT_ICFLAG_ECHO;
4764 else
4765 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4766
4767 notDone = 1;
4768 while (notDone) {
4769 bufsize = 0;
4770
4771 /* If not ready after 8 trials,
4772 * give up on this device.
4773 */
4774 if (notDone > 8)
4775 goto target_done;
4776
4777 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4778 goto target_done;
4779 else if (hd->pLocal == NULL)
4780 goto target_done;
4781 else {
4782 rc = hd->pLocal->completion;
4783 ddvprintk(("ReadBuffer Comp Code %d", rc));
4784 ddvprintk((" buff: %0x %0x %0x %0x\n",
4785 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4786
4787 if (rc == MPT_SCANDV_GOOD) {
4788 notDone = 0;
4789 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4790 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004791 if (pbuf1[0] & 0x01)
4792 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 } else {
4794 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4795 }
4796 } else if (rc == MPT_SCANDV_SENSE) {
4797 u8 skey = hd->pLocal->sense[2] & 0x0F;
4798 u8 asc = hd->pLocal->sense[12];
4799 u8 ascq = hd->pLocal->sense[13];
4800 ddvprintk((MYIOC_s_INFO_FMT
4801 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4802 ioc->name, skey, asc, ascq));
4803 if (skey == ILLEGAL_REQUEST) {
4804 notDone = 0;
4805 } else if (skey == UNIT_ATTENTION) {
4806 notDone++; /* repeat */
4807 } else if ((skey == NOT_READY) &&
4808 (asc == 0x04)&&(ascq == 0x01)) {
4809 /* wait then repeat */
4810 mdelay (2000);
4811 notDone++;
4812 } else {
4813 /* All other errors are fatal.
4814 */
4815 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4816 ioc->name));
4817 goto target_done;
4818 }
4819 } else {
4820 /* All other errors are fatal
4821 */
4822 goto target_done;
4823 }
4824 }
4825 }
4826
4827 if (iocmd.flags & MPT_ICFLAG_ECHO)
4828 echoBufSize = bufsize;
4829 else
4830 dataBufSize = bufsize;
4831 }
4832 sz = 0;
4833 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4834
4835 /* Use echo buffers if possible,
4836 * Exit if both buffers are 0.
4837 */
4838 if (echoBufSize > 0) {
4839 iocmd.flags |= MPT_ICFLAG_ECHO;
4840 if (dataBufSize > 0)
4841 bufsize = min(echoBufSize, dataBufSize);
4842 else
4843 bufsize = echoBufSize;
4844 } else if (dataBufSize == 0)
4845 goto target_done;
4846
4847 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4848 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4849
4850 /* Data buffers for write-read-compare test max 1K.
4851 */
4852 sz = min(bufsize, 1024);
4853
4854 /* --- loop ----
4855 * On first pass, always issue a reserve.
4856 * On additional loops, only if a reset has occurred.
4857 * iocmd.flags indicates if echo or regular buffer
4858 */
4859 for (patt = 0; patt < 4; patt++) {
4860 ddvprintk(("Pattern %d\n", patt));
4861 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4862 iocmd.cmd = TEST_UNIT_READY;
4863 iocmd.data_dma = -1;
4864 iocmd.data = NULL;
4865 iocmd.size = 0;
4866 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4867 goto target_done;
4868
4869 iocmd.cmd = RELEASE;
4870 iocmd.data_dma = -1;
4871 iocmd.data = NULL;
4872 iocmd.size = 0;
4873 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4874 goto target_done;
4875 else if (hd->pLocal == NULL)
4876 goto target_done;
4877 else {
4878 rc = hd->pLocal->completion;
4879 ddvprintk(("Release rc %d\n", rc));
4880 if (rc == MPT_SCANDV_GOOD)
4881 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4882 else
4883 goto target_done;
4884 }
4885 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4886 }
4887 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4888
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004889 if (iocmd.flags & MPT_ICFLAG_EBOS)
4890 goto skip_Reserve;
4891
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 repeat = 5;
4893 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4894 iocmd.cmd = RESERVE;
4895 iocmd.data_dma = -1;
4896 iocmd.data = NULL;
4897 iocmd.size = 0;
4898 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4899 goto target_done;
4900 else if (hd->pLocal == NULL)
4901 goto target_done;
4902 else {
4903 rc = hd->pLocal->completion;
4904 if (rc == MPT_SCANDV_GOOD) {
4905 iocmd.flags |= MPT_ICFLAG_RESERVED;
4906 } else if (rc == MPT_SCANDV_SENSE) {
4907 /* Wait if coming ready
4908 */
4909 u8 skey = hd->pLocal->sense[2] & 0x0F;
4910 u8 asc = hd->pLocal->sense[12];
4911 u8 ascq = hd->pLocal->sense[13];
4912 ddvprintk((MYIOC_s_INFO_FMT
4913 "DV: Reserve Failed: ", ioc->name));
4914 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4915 skey, asc, ascq));
4916
4917 if ((skey == NOT_READY) && (asc == 0x04)&&
4918 (ascq == 0x01)) {
4919 /* wait then repeat */
4920 mdelay (2000);
4921 notDone++;
4922 } else {
4923 ddvprintk((MYIOC_s_INFO_FMT
4924 "DV: Reserved Failed.", ioc->name));
4925 goto target_done;
4926 }
4927 } else {
4928 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4929 ioc->name));
4930 goto target_done;
4931 }
4932 }
4933 }
4934
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004935skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4937 iocmd.cmd = WRITE_BUFFER;
4938 iocmd.data_dma = buf1_dma;
4939 iocmd.data = pbuf1;
4940 iocmd.size = sz;
4941 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4942 goto target_done;
4943 else if (hd->pLocal == NULL)
4944 goto target_done;
4945 else {
4946 rc = hd->pLocal->completion;
4947 if (rc == MPT_SCANDV_GOOD)
4948 ; /* Issue read buffer */
4949 else if (rc == MPT_SCANDV_DID_RESET) {
4950 /* If using echo buffers, reset to data buffers.
4951 * Else do Fallback and restart
4952 * this test (re-issue reserve
4953 * because of bus reset).
4954 */
4955 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4956 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4957 } else {
4958 dv.cmd = MPT_FALLBACK;
4959 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4960
4961 if (mpt_config(hd->ioc, &cfg) != 0)
4962 goto target_done;
4963
4964 if ((!dv.now.width) && (!dv.now.offset))
4965 goto target_done;
4966 }
4967
4968 iocmd.flags |= MPT_ICFLAG_DID_RESET;
4969 patt = -1;
4970 continue;
4971 } else if (rc == MPT_SCANDV_SENSE) {
4972 /* Restart data test if UA, else quit.
4973 */
4974 u8 skey = hd->pLocal->sense[2] & 0x0F;
4975 ddvprintk((MYIOC_s_INFO_FMT
4976 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
4977 hd->pLocal->sense[12], hd->pLocal->sense[13]));
4978 if (skey == UNIT_ATTENTION) {
4979 patt = -1;
4980 continue;
4981 } else if (skey == ILLEGAL_REQUEST) {
4982 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4983 if (dataBufSize >= bufsize) {
4984 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4985 patt = -1;
4986 continue;
4987 }
4988 }
4989 goto target_done;
4990 }
4991 else
4992 goto target_done;
4993 } else {
4994 /* fatal error */
4995 goto target_done;
4996 }
4997 }
4998
4999 iocmd.cmd = READ_BUFFER;
5000 iocmd.data_dma = buf2_dma;
5001 iocmd.data = pbuf2;
5002 iocmd.size = sz;
5003 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5004 goto target_done;
5005 else if (hd->pLocal == NULL)
5006 goto target_done;
5007 else {
5008 rc = hd->pLocal->completion;
5009 if (rc == MPT_SCANDV_GOOD) {
5010 /* If buffers compare,
5011 * go to next pattern,
5012 * else, do a fallback and restart
5013 * data transfer test.
5014 */
5015 if (memcmp (pbuf1, pbuf2, sz) == 0) {
5016 ; /* goto next pattern */
5017 } else {
5018 /* Miscompare with Echo buffer, go to data buffer,
5019 * if that buffer exists.
5020 * Miscompare with Data buffer, check first 4 bytes,
5021 * some devices return capacity. Exit in this case.
5022 */
5023 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5024 if (dataBufSize >= bufsize)
5025 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5026 else
5027 goto target_done;
5028 } else {
5029 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
5030 /* Argh. Device returning wrong data.
5031 * Quit DV for this device.
5032 */
5033 goto target_done;
5034 }
5035
5036 /* Had an actual miscompare. Slow down.*/
5037 dv.cmd = MPT_FALLBACK;
5038 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5039
5040 if (mpt_config(hd->ioc, &cfg) != 0)
5041 goto target_done;
5042
5043 if ((!dv.now.width) && (!dv.now.offset))
5044 goto target_done;
5045 }
5046
5047 patt = -1;
5048 continue;
5049 }
5050 } else if (rc == MPT_SCANDV_DID_RESET) {
5051 /* Do Fallback and restart
5052 * this test (re-issue reserve
5053 * because of bus reset).
5054 */
5055 dv.cmd = MPT_FALLBACK;
5056 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5057
5058 if (mpt_config(hd->ioc, &cfg) != 0)
5059 goto target_done;
5060
5061 if ((!dv.now.width) && (!dv.now.offset))
5062 goto target_done;
5063
5064 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5065 patt = -1;
5066 continue;
5067 } else if (rc == MPT_SCANDV_SENSE) {
5068 /* Restart data test if UA, else quit.
5069 */
5070 u8 skey = hd->pLocal->sense[2] & 0x0F;
5071 ddvprintk((MYIOC_s_INFO_FMT
5072 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5073 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5074 if (skey == UNIT_ATTENTION) {
5075 patt = -1;
5076 continue;
5077 }
5078 else
5079 goto target_done;
5080 } else {
5081 /* fatal error */
5082 goto target_done;
5083 }
5084 }
5085
5086 } /* --- end of patt loop ---- */
5087
5088target_done:
5089 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5090 iocmd.cmd = RELEASE;
5091 iocmd.data_dma = -1;
5092 iocmd.data = NULL;
5093 iocmd.size = 0;
5094 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5095 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5096 ioc->name, id);
5097 else if (hd->pLocal) {
5098 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5099 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5100 } else {
5101 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5102 ioc->name, id);
5103 }
5104 }
5105
5106
5107 /* Set if cfg1_dma_addr contents is valid
5108 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005109 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 /* If disk, not U320, disable QAS
5111 */
5112 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5113 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005114 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5116 }
5117
5118 dv.cmd = MPT_SAVE;
5119 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5120
5121 /* Double writes to SDP1 can cause problems,
5122 * skip save of the final negotiated settings to
5123 * SCSI device page 1.
5124 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005125 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 cfg.physAddr = cfg1_dma_addr;
5127 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5128 cfg.dir = 1;
5129 mpt_config(hd->ioc, &cfg);
5130 */
5131 }
5132
5133 /* If this is a RAID Passthrough, enable internal IOs
5134 */
5135 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5136 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5137 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5138 }
5139
5140 /* Done with the DV scan of the current target
5141 */
5142 if (pDvBuf)
5143 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5144
5145 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5146 ioc->name, id));
5147
5148 return retcode;
5149}
5150
5151/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5152/* mptscsih_dv_parms - perform a variety of operations on the
5153 * parameters used for negotiation.
5154 * @hd: Pointer to a SCSI host.
5155 * @dv: Pointer to a structure that contains the maximum and current
5156 * negotiated parameters.
5157 */
5158static void
5159mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5160{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005161 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 SCSIDevicePage0_t *pPage0;
5163 SCSIDevicePage1_t *pPage1;
5164 int val = 0, data, configuration;
5165 u8 width = 0;
5166 u8 offset = 0;
5167 u8 factor = 0;
5168 u8 negoFlags = 0;
5169 u8 cmd = dv->cmd;
5170 u8 id = dv->id;
5171
5172 switch (cmd) {
5173 case MPT_GET_NVRAM_VALS:
5174 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5175 hd->ioc->name));
5176 /* Get the NVRAM values and save in tmax
5177 * If not an LVD bus, the adapter minSyncFactor has been
5178 * already throttled back.
5179 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005180 negoFlags = hd->ioc->spi_data.noQas;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005181 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume) {
5182 width = vtarget->maxWidth;
5183 offset = vtarget->maxOffset;
5184 factor = vtarget->minSyncFactor;
5185 negoFlags |= vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 } else {
5187 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5188 data = hd->ioc->spi_data.nvram[id];
5189 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5190 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5191 factor = MPT_ASYNC;
5192 else {
5193 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5194 if ((factor == 0) || (factor == MPT_ASYNC)){
5195 factor = MPT_ASYNC;
5196 offset = 0;
5197 }
5198 }
5199 } else {
5200 width = MPT_NARROW;
5201 offset = 0;
5202 factor = MPT_ASYNC;
5203 }
5204
5205 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 if (!width)
5207 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5208
5209 if (!offset)
5210 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5211 }
5212
5213 /* limit by adapter capabilities */
5214 width = min(width, hd->ioc->spi_data.maxBusWidth);
5215 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5216 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5217
5218 /* Check Consistency */
5219 if (offset && (factor < MPT_ULTRA2) && !width)
5220 factor = MPT_ULTRA2;
5221
5222 dv->max.width = width;
5223 dv->max.offset = offset;
5224 dv->max.factor = factor;
5225 dv->max.flags = negoFlags;
5226 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5227 id, width, factor, offset, negoFlags));
5228 break;
5229
5230 case MPT_UPDATE_MAX:
5231 ddvprintk((MYIOC_s_NOTE_FMT
5232 "Updating with SDP0 Data: ", hd->ioc->name));
5233 /* Update tmax values with those from Device Page 0.*/
5234 pPage0 = (SCSIDevicePage0_t *) pPage;
5235 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005236 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5238 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5239 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5240 }
5241
5242 dv->now.width = dv->max.width;
5243 dv->now.offset = dv->max.offset;
5244 dv->now.factor = dv->max.factor;
5245 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5246 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5247 break;
5248
5249 case MPT_SET_MAX:
5250 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5251 hd->ioc->name));
5252 /* Set current to the max values. Update the config page.*/
5253 dv->now.width = dv->max.width;
5254 dv->now.offset = dv->max.offset;
5255 dv->now.factor = dv->max.factor;
5256 dv->now.flags = dv->max.flags;
5257
5258 pPage1 = (SCSIDevicePage1_t *)pPage;
5259 if (pPage1) {
5260 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5261 dv->now.offset, &val, &configuration, dv->now.flags);
5262 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5263 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005264 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005266 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 }
5268
Christoph Hellwig637fa992005-08-18 16:25:44 +02005269 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5271 break;
5272
5273 case MPT_SET_MIN:
5274 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5275 hd->ioc->name));
5276 /* Set page to asynchronous and narrow
5277 * Do not update now, breaks fallback routine. */
5278 width = MPT_NARROW;
5279 offset = 0;
5280 factor = MPT_ASYNC;
5281 negoFlags = dv->max.flags;
5282
5283 pPage1 = (SCSIDevicePage1_t *)pPage;
5284 if (pPage1) {
5285 mptscsih_setDevicePage1Flags (width, factor,
5286 offset, &val, &configuration, negoFlags);
5287 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5288 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005289 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005291 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 }
5293 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5294 id, width, factor, offset, val, configuration, negoFlags));
5295 break;
5296
5297 case MPT_FALLBACK:
5298 ddvprintk((MYIOC_s_NOTE_FMT
5299 "Fallback: Start: offset %d, factor %x, width %d \n",
5300 hd->ioc->name, dv->now.offset,
5301 dv->now.factor, dv->now.width));
5302 width = dv->now.width;
5303 offset = dv->now.offset;
5304 factor = dv->now.factor;
5305 if ((offset) && (dv->max.width)) {
5306 if (factor < MPT_ULTRA160)
5307 factor = MPT_ULTRA160;
5308 else if (factor < MPT_ULTRA2) {
5309 factor = MPT_ULTRA2;
5310 width = MPT_WIDE;
5311 } else if ((factor == MPT_ULTRA2) && width) {
5312 factor = MPT_ULTRA2;
5313 width = MPT_NARROW;
5314 } else if (factor < MPT_ULTRA) {
5315 factor = MPT_ULTRA;
5316 width = MPT_WIDE;
5317 } else if ((factor == MPT_ULTRA) && width) {
5318 width = MPT_NARROW;
5319 } else if (factor < MPT_FAST) {
5320 factor = MPT_FAST;
5321 width = MPT_WIDE;
5322 } else if ((factor == MPT_FAST) && width) {
5323 factor = MPT_FAST;
5324 width = MPT_NARROW;
5325 } else if (factor < MPT_SCSI) {
5326 factor = MPT_SCSI;
5327 width = MPT_WIDE;
5328 } else if ((factor == MPT_SCSI) && width) {
5329 factor = MPT_SCSI;
5330 width = MPT_NARROW;
5331 } else {
5332 factor = MPT_ASYNC;
5333 offset = 0;
5334 }
5335
5336 } else if (offset) {
5337 width = MPT_NARROW;
5338 if (factor < MPT_ULTRA)
5339 factor = MPT_ULTRA;
5340 else if (factor < MPT_FAST)
5341 factor = MPT_FAST;
5342 else if (factor < MPT_SCSI)
5343 factor = MPT_SCSI;
5344 else {
5345 factor = MPT_ASYNC;
5346 offset = 0;
5347 }
5348
5349 } else {
5350 width = MPT_NARROW;
5351 factor = MPT_ASYNC;
5352 }
5353 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5354 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5355
5356 dv->now.width = width;
5357 dv->now.offset = offset;
5358 dv->now.factor = factor;
5359 dv->now.flags = dv->max.flags;
5360
5361 pPage1 = (SCSIDevicePage1_t *)pPage;
5362 if (pPage1) {
5363 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5364 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005365 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 id, width, offset, factor, dv->now.flags, val, configuration));
5367
Christoph Hellwig637fa992005-08-18 16:25:44 +02005368 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005370 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 }
5372
5373 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5374 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5375 break;
5376
5377 case MPT_SAVE:
5378 ddvprintk((MYIOC_s_NOTE_FMT
5379 "Saving to Target structure: ", hd->ioc->name));
5380 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5381 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5382
5383 /* Save these values to target structures
5384 * or overwrite nvram (phys disks only).
5385 */
5386
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005387 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume ) {
5388 vtarget->maxWidth = dv->now.width;
5389 vtarget->maxOffset = dv->now.offset;
5390 vtarget->minSyncFactor = dv->now.factor;
5391 vtarget->negoFlags = dv->now.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 } else {
5393 /* Preserv all flags, use
5394 * read-modify-write algorithm
5395 */
5396 if (hd->ioc->spi_data.nvram) {
5397 data = hd->ioc->spi_data.nvram[id];
5398
5399 if (dv->now.width)
5400 data &= ~MPT_NVRAM_WIDE_DISABLE;
5401 else
5402 data |= MPT_NVRAM_WIDE_DISABLE;
5403
5404 if (!dv->now.offset)
5405 factor = MPT_ASYNC;
5406
5407 data &= ~MPT_NVRAM_SYNC_MASK;
5408 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5409
5410 hd->ioc->spi_data.nvram[id] = data;
5411 }
5412 }
5413 break;
5414 }
5415}
5416
5417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5418/* mptscsih_fillbuf - fill a buffer with a special data pattern
5419 * cleanup. For bus scan only.
5420 *
5421 * @buffer: Pointer to data buffer to be filled.
5422 * @size: Number of bytes to fill
5423 * @index: Pattern index
5424 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5425 */
5426static void
5427mptscsih_fillbuf(char *buffer, int size, int index, int width)
5428{
5429 char *ptr = buffer;
5430 int ii;
5431 char byte;
5432 short val;
5433
5434 switch (index) {
5435 case 0:
5436
5437 if (width) {
5438 /* Pattern: 0000 FFFF 0000 FFFF
5439 */
5440 for (ii=0; ii < size; ii++, ptr++) {
5441 if (ii & 0x02)
5442 *ptr = 0xFF;
5443 else
5444 *ptr = 0x00;
5445 }
5446 } else {
5447 /* Pattern: 00 FF 00 FF
5448 */
5449 for (ii=0; ii < size; ii++, ptr++) {
5450 if (ii & 0x01)
5451 *ptr = 0xFF;
5452 else
5453 *ptr = 0x00;
5454 }
5455 }
5456 break;
5457
5458 case 1:
5459 if (width) {
5460 /* Pattern: 5555 AAAA 5555 AAAA 5555
5461 */
5462 for (ii=0; ii < size; ii++, ptr++) {
5463 if (ii & 0x02)
5464 *ptr = 0xAA;
5465 else
5466 *ptr = 0x55;
5467 }
5468 } else {
5469 /* Pattern: 55 AA 55 AA 55
5470 */
5471 for (ii=0; ii < size; ii++, ptr++) {
5472 if (ii & 0x01)
5473 *ptr = 0xAA;
5474 else
5475 *ptr = 0x55;
5476 }
5477 }
5478 break;
5479
5480 case 2:
5481 /* Pattern: 00 01 02 03 04 05
5482 * ... FE FF 00 01..
5483 */
5484 for (ii=0; ii < size; ii++, ptr++)
5485 *ptr = (char) ii;
5486 break;
5487
5488 case 3:
5489 if (width) {
5490 /* Wide Pattern: FFFE 0001 FFFD 0002
5491 * ... 4000 DFFF 8000 EFFF
5492 */
5493 byte = 0;
5494 for (ii=0; ii < size/2; ii++) {
5495 /* Create the base pattern
5496 */
5497 val = (1 << byte);
5498 /* every 64 (0x40) bytes flip the pattern
5499 * since we fill 2 bytes / iteration,
5500 * test for ii = 0x20
5501 */
5502 if (ii & 0x20)
5503 val = ~(val);
5504
5505 if (ii & 0x01) {
5506 *ptr = (char)( (val & 0xFF00) >> 8);
5507 ptr++;
5508 *ptr = (char)(val & 0xFF);
5509 byte++;
5510 byte &= 0x0F;
5511 } else {
5512 val = ~val;
5513 *ptr = (char)( (val & 0xFF00) >> 8);
5514 ptr++;
5515 *ptr = (char)(val & 0xFF);
5516 }
5517
5518 ptr++;
5519 }
5520 } else {
5521 /* Narrow Pattern: FE 01 FD 02 FB 04
5522 * .. 7F 80 01 FE 02 FD ... 80 7F
5523 */
5524 byte = 0;
5525 for (ii=0; ii < size; ii++, ptr++) {
5526 /* Base pattern - first 32 bytes
5527 */
5528 if (ii & 0x01) {
5529 *ptr = (1 << byte);
5530 byte++;
5531 byte &= 0x07;
5532 } else {
5533 *ptr = (char) (~(1 << byte));
5534 }
5535
5536 /* Flip the pattern every 32 bytes
5537 */
5538 if (ii & 0x20)
5539 *ptr = ~(*ptr);
5540 }
5541 }
5542 break;
5543 }
5544}
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005545
5546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5547/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
5548 * Else set the NEED_DV flag after Read Capacity Issued (disks)
5549 * or Mode Sense (cdroms).
5550 *
5551 * Tapes, initTarget will set this flag on completion of Inquiry command.
5552 * Called only if DV_NOT_DONE flag is set
5553 */
5554static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005555mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005556{
5557 MPT_ADAPTER *ioc = hd->ioc;
5558 u8 cmd;
5559 SpiCfgData *pSpi;
5560
5561 ddvtprintk((MYIOC_s_NOTE_FMT
5562 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005563 hd->ioc->name, sc->device->id, sc->device->lun , hd->negoNvram, sc->cmnd[0]));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005564
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005565 if ((sc->device->lun != 0) || (hd->negoNvram != 0))
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005566 return;
5567
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005568 cmd = sc->cmnd[0];
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005569
5570 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
5571 pSpi = &ioc->spi_data;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005572 if ((ioc->raid_data.isRaid & (1 << sc->device->id)) && ioc->raid_data.pIocPg3) {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005573 /* Set NEED_DV for all hidden disks
5574 */
5575 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5576 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5577
5578 while (numPDisk) {
5579 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
5580 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
5581 pPDisk++;
5582 numPDisk--;
5583 }
5584 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005585 pSpi->dvStatus[sc->device->id] |= MPT_SCSICFG_NEED_DV;
5586 ddvtprintk(("NEED_DV set for visible disk id %d\n", sc->device->id));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005587 }
5588}
5589
5590/* mptscsih_raid_set_dv_flags()
5591 *
5592 * New or replaced disk. Set DV flag and schedule DV.
5593 */
5594static void
5595mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
5596{
5597 MPT_ADAPTER *ioc = hd->ioc;
5598 SpiCfgData *pSpi = &ioc->spi_data;
5599 Ioc3PhysDisk_t *pPDisk;
5600 int numPDisk;
5601
5602 if (hd->negoNvram != 0)
5603 return;
5604
5605 ddvtprintk(("DV requested for phys disk id %d\n", id));
5606 if (ioc->raid_data.pIocPg3) {
5607 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5608 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5609 while (numPDisk) {
5610 if (id == pPDisk->PhysDiskNum) {
5611 pSpi->dvStatus[pPDisk->PhysDiskID] =
5612 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
5613 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
5614 ddvtprintk(("NEED_DV set for phys disk id %d\n",
5615 pPDisk->PhysDiskID));
5616 break;
5617 }
5618 pPDisk++;
5619 numPDisk--;
5620 }
5621
5622 if (numPDisk == 0) {
5623 /* The physical disk that needs DV was not found
5624 * in the stored IOC Page 3. The driver must reload
5625 * this page. DV routine will set the NEED_DV flag for
5626 * all phys disks that have DV_NOT_DONE set.
5627 */
5628 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
5629 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
5630 }
5631 }
5632}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5634
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005635EXPORT_SYMBOL(mptscsih_remove);
5636EXPORT_SYMBOL(mptscsih_shutdown);
5637#ifdef CONFIG_PM
5638EXPORT_SYMBOL(mptscsih_suspend);
5639EXPORT_SYMBOL(mptscsih_resume);
5640#endif
5641EXPORT_SYMBOL(mptscsih_proc_info);
5642EXPORT_SYMBOL(mptscsih_info);
5643EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005644EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005645EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005646EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005647EXPORT_SYMBOL(mptscsih_slave_destroy);
5648EXPORT_SYMBOL(mptscsih_slave_configure);
5649EXPORT_SYMBOL(mptscsih_abort);
5650EXPORT_SYMBOL(mptscsih_dev_reset);
5651EXPORT_SYMBOL(mptscsih_bus_reset);
5652EXPORT_SYMBOL(mptscsih_host_reset);
5653EXPORT_SYMBOL(mptscsih_bios_param);
5654EXPORT_SYMBOL(mptscsih_io_done);
5655EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5656EXPORT_SYMBOL(mptscsih_scandv_complete);
5657EXPORT_SYMBOL(mptscsih_event_process);
5658EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005659EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005660EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06005661EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005663/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/