blob: 05789e50546491df632331c58b6b5ff3e867f4fa [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;
Moore, Eric2254c862006-01-17 17:06:29 -0700563 u16 req_idx, req_idx_MR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
565 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
566
567 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700568 req_idx_MR = (mr != NULL) ?
569 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
570 if ((req_idx != req_idx_MR) ||
571 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
572 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
573 ioc->name);
574 printk (MYIOC_s_ERR_FMT
575 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
576 ioc->name, req_idx, req_idx_MR, mf, mr,
577 hd->ScsiLookup[req_idx_MR]);
578 return 0;
579 }
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 sc = hd->ScsiLookup[req_idx];
582 if (sc == NULL) {
583 MPIHeader_t *hdr = (MPIHeader_t *)mf;
584
585 /* Remark: writeSDP1 will use the ScsiDoneCtx
586 * If a SCSI I/O cmd, device disabled by OS and
587 * completion done. Cannot touch sc struct. Just free mem.
588 */
589 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
590 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
591 ioc->name);
592
593 mptscsih_freeChainBuffers(ioc, req_idx);
594 return 1;
595 }
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 sc->result = DID_OK << 16; /* Set default reply as OK */
598 pScsiReq = (SCSIIORequest_t *) mf;
599 pScsiReply = (SCSIIOReply_t *) mr;
600
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200601 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
602 dmfprintk((MYIOC_s_INFO_FMT
603 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
604 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
605 }else{
606 dmfprintk((MYIOC_s_INFO_FMT
607 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
608 ioc->name, mf, mr, sc, req_idx));
609 }
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 if (pScsiReply == NULL) {
612 /* special context reply handling */
613 ;
614 } else {
615 u32 xfer_cnt;
616 u16 status;
617 u8 scsi_state, scsi_status;
618
619 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
620 scsi_state = pScsiReply->SCSIState;
621 scsi_status = pScsiReply->SCSIStatus;
622 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
623 sc->resid = sc->request_bufflen - xfer_cnt;
624
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600625 /*
626 * if we get a data underrun indication, yet no data was
627 * transferred and the SCSI status indicates that the
628 * command was never started, change the data underrun
629 * to success
630 */
631 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
632 (scsi_status == MPI_SCSI_STATUS_BUSY ||
633 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
634 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
635 status = MPI_IOCSTATUS_SUCCESS;
636 }
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
639 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
640 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700641 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600642 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sc->request_bufflen, xfer_cnt));
644
645 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400646 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 /*
649 * Look for + dump FCP ResponseInfo[]!
650 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600651 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
652 pScsiReply->ResponseInfo) {
653 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
654 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700655 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 le32_to_cpu(pScsiReply->ResponseInfo));
657 }
658
659 switch(status) {
660 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
661 /* CHECKME!
662 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
663 * But not: DID_BUS_BUSY lest one risk
664 * killing interrupt handler:-(
665 */
666 sc->result = SAM_STAT_BUSY;
667 break;
668
669 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
670 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
671 sc->result = DID_BAD_TARGET << 16;
672 break;
673
674 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
675 /* Spoof to SCSI Selection Timeout! */
676 sc->result = DID_NO_CONNECT << 16;
677
678 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
679 hd->sel_timeout[pScsiReq->TargetID]++;
680 break;
681
682 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
683 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
684 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
685 /* Linux handles an unsolicited DID_RESET better
686 * than an unsolicited DID_ABORT.
687 */
688 sc->result = DID_RESET << 16;
689
690 /* GEM Workaround. */
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700691 if (ioc->bus_type == SPI)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700692 mptscsih_no_negotiate(hd, sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 break;
694
695 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600696 sc->resid = sc->request_bufflen - xfer_cnt;
697 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
698 sc->result=DID_SOFT_ERROR << 16;
699 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600701 dreplyprintk((KERN_NOTICE
702 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
706 /*
707 * Do upfront check for valid SenseData and give it
708 * precedence!
709 */
710 sc->result = (DID_OK << 16) | scsi_status;
711 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
712 /* Have already saved the status and sense data
713 */
714 ;
715 } else {
716 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600717 if (scsi_status == SAM_STAT_BUSY)
718 sc->result = SAM_STAT_BUSY;
719 else
720 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
723 /* What to do?
724 */
725 sc->result = DID_SOFT_ERROR << 16;
726 }
727 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
728 /* Not real sure here either... */
729 sc->result = DID_RESET << 16;
730 }
731 }
732
733 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
734 sc->underflow));
735 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
736 /* Report Queue Full
737 */
738 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
739 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 break;
742
Moore, Eric7e551472006-01-16 18:53:21 -0700743 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
744 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
746 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600747 if (scsi_status == MPI_SCSI_STATUS_BUSY)
748 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
749 else
750 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (scsi_state == 0) {
752 ;
753 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
754 /*
755 * If running against circa 200003dd 909 MPT f/w,
756 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
757 * (QUEUE_FULL) returned from device! --> get 0x0000?128
758 * and with SenseBytes set to 0.
759 */
760 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
761 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
762
763 }
764 else if (scsi_state &
765 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
766 ) {
767 /*
768 * What to do?
769 */
770 sc->result = DID_SOFT_ERROR << 16;
771 }
772 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
773 /* Not real sure here either... */
774 sc->result = DID_RESET << 16;
775 }
776 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
777 /* Device Inq. data indicates that it supports
778 * QTags, but rejects QTag messages.
779 * This command completed OK.
780 *
781 * Not real sure here either so do nothing... */
782 }
783
784 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
785 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
786
787 /* Add handling of:
788 * Reservation Conflict, Busy,
789 * Command Terminated, CHECK
790 */
791 break;
792
793 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
794 sc->result = DID_SOFT_ERROR << 16;
795 break;
796
797 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
798 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
799 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
800 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
801 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
802 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
803 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
805 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
806 default:
807 /*
808 * What to do?
809 */
810 sc->result = DID_SOFT_ERROR << 16;
811 break;
812
813 } /* switch(status) */
814
815 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
816 } /* end of address reply case */
817
818 /* Unmap the DMA buffers, if any. */
819 if (sc->use_sg) {
820 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
821 sc->use_sg, sc->sc_data_direction);
822 } else if (sc->request_bufflen) {
823 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
824 sc->request_bufflen, sc->sc_data_direction);
825 }
826
827 hd->ScsiLookup[req_idx] = NULL;
828
829 sc->scsi_done(sc); /* Issue the command callback */
830
831 /* Free Chain buffers */
832 mptscsih_freeChainBuffers(ioc, req_idx);
833 return 1;
834}
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836/*
837 * mptscsih_flush_running_cmds - For each command found, search
838 * Scsi_Host instance taskQ and reply to OS.
839 * Called only if recovering from a FW reload.
840 * @hd: Pointer to a SCSI HOST structure
841 *
842 * Returns: None.
843 *
844 * Must be called while new I/Os are being queued.
845 */
846static void
847mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
848{
849 MPT_ADAPTER *ioc = hd->ioc;
850 struct scsi_cmnd *SCpnt;
851 MPT_FRAME_HDR *mf;
852 int ii;
853 int max = ioc->req_depth;
854
855 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
856 for (ii= 0; ii < max; ii++) {
857 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
858
859 /* Command found.
860 */
861
862 /* Null ScsiLookup index
863 */
864 hd->ScsiLookup[ii] = NULL;
865
866 mf = MPT_INDEX_2_MFPTR(ioc, ii);
867 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
868 mf, SCpnt));
869
870 /* Set status, free OS resources (SG DMA buffers)
871 * Do OS callback
872 * Free driver resources (chain, msg buffers)
873 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400874 if (SCpnt->use_sg) {
875 pci_unmap_sg(ioc->pcidev,
876 (struct scatterlist *) SCpnt->request_buffer,
877 SCpnt->use_sg,
878 SCpnt->sc_data_direction);
879 } else if (SCpnt->request_bufflen) {
880 pci_unmap_single(ioc->pcidev,
881 SCpnt->SCp.dma_handle,
882 SCpnt->request_bufflen,
883 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885 SCpnt->result = DID_RESET << 16;
886 SCpnt->host_scribble = NULL;
887
888 /* Free Chain buffers */
889 mptscsih_freeChainBuffers(ioc, ii);
890
891 /* Free Message frames */
892 mpt_free_msg_frame(ioc, mf);
893
894 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
895 }
896 }
897
898 return;
899}
900
901/*
902 * mptscsih_search_running_cmds - Delete any commands associated
903 * with the specified target and lun. Function called only
904 * when a lun is disable by mid-layer.
905 * Do NOT access the referenced scsi_cmnd structure or
906 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600907 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700908 * @hd: Pointer to a SCSI HOST structure
909 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 *
911 * Returns: None.
912 *
913 * Called from slave_destroy.
914 */
915static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700916mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917{
918 SCSIIORequest_t *mf = NULL;
919 int ii;
920 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600921 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700924 vdevice->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600927 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
930
931 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
932 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
933
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700934 if ((mf->TargetID != ((u8)vdevice->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 continue;
936
937 /* Cleanup
938 */
939 hd->ScsiLookup[ii] = NULL;
940 mptscsih_freeChainBuffers(hd->ioc, ii);
941 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600942 if (sc->use_sg) {
943 pci_unmap_sg(hd->ioc->pcidev,
944 (struct scatterlist *) sc->request_buffer,
945 sc->use_sg,
946 sc->sc_data_direction);
947 } else if (sc->request_bufflen) {
948 pci_unmap_single(hd->ioc->pcidev,
949 sc->SCp.dma_handle,
950 sc->request_bufflen,
951 sc->sc_data_direction);
952 }
953 sc->host_scribble = NULL;
954 sc->result = DID_NO_CONNECT << 16;
955 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 return;
959}
960
961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
964/*
965 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
966 * from a SCSI target device.
967 * @sc: Pointer to scsi_cmnd structure
968 * @pScsiReply: Pointer to SCSIIOReply_t
969 * @pScsiReq: Pointer to original SCSI request
970 *
971 * This routine periodically reports QUEUE_FULL status returned from a
972 * SCSI target device. It reports this to the console via kernel
973 * printk() API call, not more than once every 10 seconds.
974 */
975static void
976mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
977{
978 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400981 if (sc->device == NULL)
982 return;
983 if (sc->device->host == NULL)
984 return;
985 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
986 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400988 if (time - hd->last_queue_full > 10 * HZ) {
989 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
990 hd->ioc->name, 0, sc->device->id, sc->device->lun));
991 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993}
994
995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
996/*
997 * mptscsih_remove - Removed scsi devices
998 * @pdev: Pointer to pci_dev structure
999 *
1000 *
1001 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001002void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003mptscsih_remove(struct pci_dev *pdev)
1004{
1005 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1006 struct Scsi_Host *host = ioc->sh;
1007 MPT_SCSI_HOST *hd;
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07001008#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 int count;
1010 unsigned long flags;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001011#endif
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001012 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001014 if(!host) {
1015 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019 scsi_remove_host(host);
1020
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001021 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1022 return;
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1025 /* Check DV thread active */
1026 count = 10 * HZ;
1027 spin_lock_irqsave(&dvtaskQ_lock, flags);
1028 if (dvtaskQ_active) {
1029 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
Nishanth Aravamudan65210182005-11-07 01:01:19 -08001030 while(dvtaskQ_active && --count)
1031 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 } else {
1033 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
1034 }
1035 if (!count)
1036 printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
1037#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
1038 else
1039 printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
1040#endif
1041#endif
1042
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001043 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001045 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001047 if (hd->ScsiLookup != NULL) {
1048 sz1 = hd->ioc->req_depth * sizeof(void *);
1049 kfree(hd->ScsiLookup);
1050 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001053 /*
1054 * Free pointer array.
1055 */
1056 kfree(hd->Targets);
1057 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001059 dprintk((MYIOC_s_INFO_FMT
1060 "Free'd ScsiLookup (%d) memory\n",
1061 hd->ioc->name, sz1));
1062
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001063 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001064
1065 /* NULL the Scsi_Host pointer
1066 */
1067 hd->ioc->sh = NULL;
1068
1069 scsi_host_put(host);
1070
1071 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073}
1074
1075/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1076/*
1077 * mptscsih_shutdown - reboot notifier
1078 *
1079 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001080void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001081mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001083 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 struct Scsi_Host *host = ioc->sh;
1085 MPT_SCSI_HOST *hd;
1086
1087 if(!host)
1088 return;
1089
1090 hd = (MPT_SCSI_HOST *)host->hostdata;
1091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
1094#ifdef CONFIG_PM
1095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1096/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001097 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 *
1099 *
1100 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001101int
Pavel Machek8d189f72005-04-16 15:25:28 -07001102mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001104 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001105 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
1108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1109/*
1110 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1111 *
1112 *
1113 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001114int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115mptscsih_resume(struct pci_dev *pdev)
1116{
1117 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1118 struct Scsi_Host *host = ioc->sh;
1119 MPT_SCSI_HOST *hd;
1120
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001121 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if(!host)
1124 return 0;
1125
1126 hd = (MPT_SCSI_HOST *)host->hostdata;
1127 if(!hd)
1128 return 0;
1129
1130#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1131 {
1132 unsigned long lflags;
1133 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1134 if (!dvtaskQ_active) {
1135 dvtaskQ_active = 1;
1136 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001137 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001139 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 } else {
1141 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1142 }
1143 }
1144#endif
1145 return 0;
1146}
1147
1148#endif
1149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1151/**
1152 * mptscsih_info - Return information about MPT adapter
1153 * @SChost: Pointer to Scsi_Host structure
1154 *
1155 * (linux scsi_host_template.info routine)
1156 *
1157 * Returns pointer to buffer where information was written.
1158 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160mptscsih_info(struct Scsi_Host *SChost)
1161{
1162 MPT_SCSI_HOST *h;
1163 int size = 0;
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001168 if (h->info_kbuf == NULL)
1169 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1170 return h->info_kbuf;
1171 h->info_kbuf[0] = '\0';
1172
1173 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1174 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001177 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180struct info_str {
1181 char *buffer;
1182 int length;
1183 int offset;
1184 int pos;
1185};
1186
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001187static void
1188mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189{
1190 if (info->pos + len > info->length)
1191 len = info->length - info->pos;
1192
1193 if (info->pos + len < info->offset) {
1194 info->pos += len;
1195 return;
1196 }
1197
1198 if (info->pos < info->offset) {
1199 data += (info->offset - info->pos);
1200 len -= (info->offset - info->pos);
1201 }
1202
1203 if (len > 0) {
1204 memcpy(info->buffer + info->pos, data, len);
1205 info->pos += len;
1206 }
1207}
1208
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001209static int
1210mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
1212 va_list args;
1213 char buf[81];
1214 int len;
1215
1216 va_start(args, fmt);
1217 len = vsprintf(buf, fmt, args);
1218 va_end(args);
1219
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001220 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 return len;
1222}
1223
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001224static int
1225mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
1227 struct info_str info;
1228
1229 info.buffer = pbuf;
1230 info.length = len;
1231 info.offset = offset;
1232 info.pos = 0;
1233
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1235 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1236 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1237 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1240}
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mptscsih_proc_info - Return information about MPT adapter
1245 *
1246 * (linux scsi_host_template.info routine)
1247 *
1248 * buffer: if write, user data; if read, buffer for user
1249 * length: if write, return length;
1250 * offset: if write, 0; if read, the current offset into the buffer from
1251 * the previous read.
1252 * hostno: scsi host number
1253 * func: if write = 1; if read = 0
1254 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001255int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1257 int length, int func)
1258{
1259 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1260 MPT_ADAPTER *ioc = hd->ioc;
1261 int size = 0;
1262
1263 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001264 /*
1265 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 */
1267 } else {
1268 if (start)
1269 *start = buffer;
1270
1271 size = mptscsih_host_info(ioc, buffer, offset, length);
1272 }
1273
1274 return size;
1275}
1276
1277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1278#define ADD_INDEX_LOG(req_ent) do { } while(0)
1279
1280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1281/**
1282 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1283 * @SCpnt: Pointer to scsi_cmnd structure
1284 * @done: Pointer SCSI mid-layer IO completion function
1285 *
1286 * (linux scsi_host_template.queuecommand routine)
1287 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1288 * from a linux scsi_cmnd request and send it to the IOC.
1289 *
1290 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1291 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001292int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1294{
1295 MPT_SCSI_HOST *hd;
1296 MPT_FRAME_HDR *mf;
1297 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001298 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 int lun;
1300 u32 datalen;
1301 u32 scsictl;
1302 u32 scsidir;
1303 u32 cmd_len;
1304 int my_idx;
1305 int ii;
1306
1307 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 lun = SCpnt->device->lun;
1309 SCpnt->scsi_done = done;
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1312 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1313
1314 if (hd->resetPending) {
1315 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1316 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1317 return SCSI_MLQUEUE_HOST_BUSY;
1318 }
1319
1320 /*
1321 * Put together a MPT SCSI request...
1322 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001323 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1325 hd->ioc->name));
1326 return SCSI_MLQUEUE_HOST_BUSY;
1327 }
1328
1329 pScsiReq = (SCSIIORequest_t *) mf;
1330
1331 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1332
1333 ADD_INDEX_LOG(my_idx);
1334
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001335 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 * Seems we may receive a buffer (datalen>0) even when there
1337 * will be no data transfer! GRRRRR...
1338 */
1339 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1340 datalen = SCpnt->request_bufflen;
1341 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1342 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1343 datalen = SCpnt->request_bufflen;
1344 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1345 } else {
1346 datalen = 0;
1347 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1348 }
1349
1350 /* Default to untagged. Once a target structure has been allocated,
1351 * use the Inquiry data to determine if device supports tagged.
1352 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001353 if (vdev
1354 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 && (SCpnt->device->tagged_supported)) {
1356 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1357 } else {
1358 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1359 }
1360
1361 /* Use the above information to set up the message frame
1362 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001363 pScsiReq->TargetID = (u8) vdev->target_id;
1364 pScsiReq->Bus = vdev->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 pScsiReq->ChainOffset = 0;
1366 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1367 pScsiReq->CDBLength = SCpnt->cmd_len;
1368 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1369 pScsiReq->Reserved = 0;
1370 pScsiReq->MsgFlags = mpt_msg_flags();
1371 pScsiReq->LUN[0] = 0;
1372 pScsiReq->LUN[1] = lun;
1373 pScsiReq->LUN[2] = 0;
1374 pScsiReq->LUN[3] = 0;
1375 pScsiReq->LUN[4] = 0;
1376 pScsiReq->LUN[5] = 0;
1377 pScsiReq->LUN[6] = 0;
1378 pScsiReq->LUN[7] = 0;
1379 pScsiReq->Control = cpu_to_le32(scsictl);
1380
1381 /*
1382 * Write SCSI CDB into the message
1383 */
1384 cmd_len = SCpnt->cmd_len;
1385 for (ii=0; ii < cmd_len; ii++)
1386 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1387
1388 for (ii=cmd_len; ii < 16; ii++)
1389 pScsiReq->CDB[ii] = 0;
1390
1391 /* DataLength */
1392 pScsiReq->DataLength = cpu_to_le32(datalen);
1393
1394 /* SenseBuffer low address */
1395 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1396 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1397
1398 /* Now add the SG list
1399 * Always have a SGE even if null length.
1400 */
1401 if (datalen == 0) {
1402 /* Add a NULL SGE */
1403 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1404 (dma_addr_t) -1);
1405 } else {
1406 /* Add a 32 or 64 bit SGE */
1407 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1408 goto fail;
1409 }
1410
1411 hd->ScsiLookup[my_idx] = SCpnt;
1412 SCpnt->host_scribble = NULL;
1413
1414#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001415 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001416 int dvStatus = hd->ioc->spi_data.dvStatus[vdev->target_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 int issueCmd = 1;
1418
1419 if (dvStatus || hd->ioc->spi_data.forceDv) {
1420
1421 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1422 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1423 unsigned long lflags;
1424 /* Schedule DV if necessary */
1425 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1426 if (!dvtaskQ_active) {
1427 dvtaskQ_active = 1;
1428 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001429 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001431 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 } else {
1433 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1434 }
1435 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1436 }
1437
1438 /* Trying to do DV to this target, extend timeout.
1439 * Wait to issue until flag is clear
1440 */
1441 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1442 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1443 issueCmd = 0;
1444 }
1445
1446 /* Set the DV flags.
1447 */
1448 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001449 mptscsih_set_dvflags(hd, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451 if (!issueCmd)
1452 goto fail;
1453 }
1454 }
1455#endif
1456
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001457 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1459 hd->ioc->name, SCpnt, mf, my_idx));
1460 DBG_DUMP_REQUEST_FRAME(mf)
1461 return 0;
1462
1463 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001464 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1466 mpt_free_msg_frame(hd->ioc, mf);
1467 return SCSI_MLQUEUE_HOST_BUSY;
1468}
1469
1470/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1471/*
1472 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1473 * with a SCSI IO request
1474 * @hd: Pointer to the MPT_SCSI_HOST instance
1475 * @req_idx: Index of the SCSI IO request frame.
1476 *
1477 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1478 * No return.
1479 */
1480static void
1481mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1482{
1483 MPT_FRAME_HDR *chain;
1484 unsigned long flags;
1485 int chain_idx;
1486 int next;
1487
1488 /* Get the first chain index and reset
1489 * tracker state.
1490 */
1491 chain_idx = ioc->ReqToChain[req_idx];
1492 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1493
1494 while (chain_idx != MPT_HOST_NO_CHAIN) {
1495
1496 /* Save the next chain buffer index */
1497 next = ioc->ChainToChain[chain_idx];
1498
1499 /* Free this chain buffer and reset
1500 * tracker
1501 */
1502 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1503
1504 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1505 + (chain_idx * ioc->req_sz));
1506
1507 spin_lock_irqsave(&ioc->FreeQlock, flags);
1508 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1510
1511 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1512 ioc->name, chain_idx));
1513
1514 /* handle next */
1515 chain_idx = next;
1516 }
1517 return;
1518}
1519
1520/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1521/*
1522 * Reset Handling
1523 */
1524
1525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1526/*
1527 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1528 * Fall through to mpt_HardResetHandler if: not operational, too many
1529 * failed TM requests or handshake failure.
1530 *
1531 * @ioc: Pointer to MPT_ADAPTER structure
1532 * @type: Task Management type
1533 * @target: Logical Target ID for reset (if appropriate)
1534 * @lun: Logical Unit for reset (if appropriate)
1535 * @ctx2abort: Context for the task to be aborted (if appropriate)
1536 *
1537 * Remark: Currently invoked from a non-interrupt thread (_bh).
1538 *
1539 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1540 * will be active.
1541 *
1542 * Returns 0 for SUCCESS or -1 if FAILED.
1543 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001544int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1546{
1547 MPT_ADAPTER *ioc;
1548 int rc = -1;
1549 int doTask = 1;
1550 u32 ioc_raw_state;
1551 unsigned long flags;
1552
1553 /* If FW is being reloaded currently, return success to
1554 * the calling function.
1555 */
1556 if (hd == NULL)
1557 return 0;
1558
1559 ioc = hd->ioc;
1560 if (ioc == NULL) {
1561 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1562 return FAILED;
1563 }
1564 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1565
1566 // SJR - CHECKME - Can we avoid this here?
1567 // (mpt_HardResetHandler has this check...)
1568 spin_lock_irqsave(&ioc->diagLock, flags);
1569 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1570 spin_unlock_irqrestore(&ioc->diagLock, flags);
1571 return FAILED;
1572 }
1573 spin_unlock_irqrestore(&ioc->diagLock, flags);
1574
1575 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1576 * If we time out and not bus reset, then we return a FAILED status to the caller.
1577 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1578 * successful. Otherwise, reload the FW.
1579 */
1580 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1581 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001582 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 "Timed out waiting for last TM (%d) to complete! \n",
1584 hd->ioc->name, hd->tmPending));
1585 return FAILED;
1586 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001587 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 "Timed out waiting for last TM (%d) to complete! \n",
1589 hd->ioc->name, hd->tmPending));
1590 return FAILED;
1591 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001592 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 "Timed out waiting for last TM (%d) to complete! \n",
1594 hd->ioc->name, hd->tmPending));
1595 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1596 return FAILED;
1597
1598 doTask = 0;
1599 }
1600 } else {
1601 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1602 hd->tmPending |= (1 << type);
1603 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1604 }
1605
1606 /* Is operational?
1607 */
1608 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1609
1610#ifdef MPT_DEBUG_RESET
1611 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1612 printk(MYIOC_s_WARN_FMT
1613 "TM Handler: IOC Not operational(0x%x)!\n",
1614 hd->ioc->name, ioc_raw_state);
1615 }
1616#endif
1617
1618 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1619 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1620
1621 /* Isse the Task Mgmt request.
1622 */
1623 if (hd->hard_resets < -1)
1624 hd->hard_resets++;
1625 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1626 if (rc) {
1627 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1628 } else {
1629 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1630 }
1631 }
1632
1633 /* Only fall through to the HRH if this is a bus reset
1634 */
1635 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1636 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1637 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1638 hd->ioc->name));
1639 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1640 }
1641
1642 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1643
1644 return rc;
1645}
1646
1647
1648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1649/*
1650 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1651 * @hd: Pointer to MPT_SCSI_HOST structure
1652 * @type: Task Management type
1653 * @target: Logical Target ID for reset (if appropriate)
1654 * @lun: Logical Unit for reset (if appropriate)
1655 * @ctx2abort: Context for the task to be aborted (if appropriate)
1656 *
1657 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1658 * or a non-interrupt thread. In the former, must not call schedule().
1659 *
1660 * Not all fields are meaningfull for all task types.
1661 *
1662 * Returns 0 for SUCCESS, -999 for "no msg frames",
1663 * else other non-zero value returned.
1664 */
1665static int
1666mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1667{
1668 MPT_FRAME_HDR *mf;
1669 SCSITaskMgmt_t *pScsiTm;
1670 int ii;
1671 int retval;
1672
1673 /* Return Fail to calling function if no message frames available.
1674 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001675 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1677 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001678 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 }
1680 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1681 hd->ioc->name, mf));
1682
1683 /* Format the Request
1684 */
1685 pScsiTm = (SCSITaskMgmt_t *) mf;
1686 pScsiTm->TargetID = target;
1687 pScsiTm->Bus = channel;
1688 pScsiTm->ChainOffset = 0;
1689 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1690
1691 pScsiTm->Reserved = 0;
1692 pScsiTm->TaskType = type;
1693 pScsiTm->Reserved1 = 0;
1694 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1695 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1696
1697 for (ii= 0; ii < 8; ii++) {
1698 pScsiTm->LUN[ii] = 0;
1699 }
1700 pScsiTm->LUN[1] = lun;
1701
1702 for (ii=0; ii < 7; ii++)
1703 pScsiTm->Reserved2[ii] = 0;
1704
1705 pScsiTm->TaskMsgContext = ctx2abort;
1706
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001707 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1708 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
1710 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1711
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001712 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1714 CAN_SLEEP)) != 0) {
1715 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1716 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1717 hd->ioc, mf));
1718 mpt_free_msg_frame(hd->ioc, mf);
1719 return retval;
1720 }
1721
1722 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1723 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1724 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1725 hd->ioc, mf));
1726 mpt_free_msg_frame(hd->ioc, mf);
1727 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1728 hd->ioc->name));
1729 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1730 }
1731
1732 return retval;
1733}
1734
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001735static int
1736mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1737{
1738 switch (ioc->bus_type) {
1739 case FC:
1740 return 40;
1741 case SAS:
1742 return 10;
1743 case SPI:
1744 default:
1745 return 2;
1746 }
1747}
1748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1750/**
1751 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1752 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1753 *
1754 * (linux scsi_host_template.eh_abort_handler routine)
1755 *
1756 * Returns SUCCESS or FAILED.
1757 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001758int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759mptscsih_abort(struct scsi_cmnd * SCpnt)
1760{
1761 MPT_SCSI_HOST *hd;
1762 MPT_ADAPTER *ioc;
1763 MPT_FRAME_HDR *mf;
1764 u32 ctx2abort;
1765 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001766 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001767 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769 /* If we can't locate our host adapter structure, return FAILED status.
1770 */
1771 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1772 SCpnt->result = DID_RESET << 16;
1773 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001774 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 "Can't locate host! (sc=%p)\n",
1776 SCpnt));
1777 return FAILED;
1778 }
1779
1780 ioc = hd->ioc;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001781 if (hd->resetPending) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 return FAILED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 if (hd->timeouts < -1)
1786 hd->timeouts++;
1787
1788 /* Find this command
1789 */
1790 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001791 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 * Do OS callback.
1793 */
1794 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001795 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 "Command not in the active list! (sc=%p)\n",
1797 hd->ioc->name, SCpnt));
1798 return SUCCESS;
1799 }
1800
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001801 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1802 hd->ioc->name, SCpnt);
1803 scsi_print_command(SCpnt);
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1806 * (the IO to be ABORT'd)
1807 *
1808 * NOTE: Since we do not byteswap MsgContext, we do not
1809 * swap it here either. It is an opaque cookie to
1810 * the controller, so it does not matter. -DaveM
1811 */
1812 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1813 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1814
1815 hd->abortSCpnt = SCpnt;
1816
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001817 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001818 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001819 vdev->bus_id, vdev->target_id, vdev->lun,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001820 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001822 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1823 hd->ioc->name,
1824 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001826 if (retval == 0)
1827 return SUCCESS;
1828
1829 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 hd->tmPending = 0;
1831 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001833 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834}
1835
1836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1837/**
1838 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1839 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1840 *
1841 * (linux scsi_host_template.eh_dev_reset_handler routine)
1842 *
1843 * Returns SUCCESS or FAILED.
1844 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001845int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1847{
1848 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001849 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001850 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852 /* If we can't locate our host adapter structure, return FAILED status.
1853 */
1854 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001855 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 "Can't locate host! (sc=%p)\n",
1857 SCpnt));
1858 return FAILED;
1859 }
1860
1861 if (hd->resetPending)
1862 return FAILED;
1863
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001864 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001866 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001868 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001869 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001870 vdev->bus_id, vdev->target_id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001871 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001872
1873 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1874 hd->ioc->name,
1875 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1876
1877 if (retval == 0)
1878 return SUCCESS;
1879
1880 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 hd->tmPending = 0;
1882 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001884 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885}
1886
1887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1888/**
1889 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1890 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1891 *
1892 * (linux scsi_host_template.eh_bus_reset_handler routine)
1893 *
1894 * Returns SUCCESS or FAILED.
1895 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001896int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1898{
1899 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001900 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001901 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903 /* If we can't locate our host adapter structure, return FAILED status.
1904 */
1905 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001906 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 "Can't locate host! (sc=%p)\n",
1908 SCpnt ) );
1909 return FAILED;
1910 }
1911
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001912 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001914 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 if (hd->timeouts < -1)
1917 hd->timeouts++;
1918
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001919 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001920 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001921 vdev->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001923 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1924 hd->ioc->name,
1925 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1926
1927 if (retval == 0)
1928 return SUCCESS;
1929
1930 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 hd->tmPending = 0;
1932 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001934 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935}
1936
1937/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1938/**
1939 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1940 * new_eh variant
1941 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1942 *
1943 * (linux scsi_host_template.eh_host_reset_handler routine)
1944 *
1945 * Returns SUCCESS or FAILED.
1946 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001947int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1949{
1950 MPT_SCSI_HOST * hd;
1951 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
1953 /* If we can't locate the host to reset, then we failed. */
1954 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001955 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 "Can't locate host! (sc=%p)\n",
1957 SCpnt ) );
1958 return FAILED;
1959 }
1960
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001961 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 hd->ioc->name, SCpnt);
1963
1964 /* If our attempts to reset the host failed, then return a failed
1965 * status. The host will be taken off line by the SCSI mid-layer.
1966 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1968 status = FAILED;
1969 } else {
1970 /* Make sure TM pending is cleared and TM state is set to
1971 * NONE.
1972 */
1973 hd->tmPending = 0;
1974 hd->tmState = TM_STATE_NONE;
1975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001977 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 "Status = %s\n",
1979 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1980
1981 return status;
1982}
1983
1984/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1985/**
1986 * mptscsih_tm_pending_wait - wait for pending task management request to
1987 * complete.
1988 * @hd: Pointer to MPT host structure.
1989 *
1990 * Returns {SUCCESS,FAILED}.
1991 */
1992static int
1993mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1994{
1995 unsigned long flags;
1996 int loop_count = 4 * 10; /* Wait 10 seconds */
1997 int status = FAILED;
1998
1999 do {
2000 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2001 if (hd->tmState == TM_STATE_NONE) {
2002 hd->tmState = TM_STATE_IN_PROGRESS;
2003 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002005 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 break;
2007 }
2008 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2009 msleep(250);
2010 } while (--loop_count);
2011
2012 return status;
2013}
2014
2015/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2016/**
2017 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2018 * @hd: Pointer to MPT host structure.
2019 *
2020 * Returns {SUCCESS,FAILED}.
2021 */
2022static int
2023mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2024{
2025 unsigned long flags;
2026 int loop_count = 4 * timeout;
2027 int status = FAILED;
2028
2029 do {
2030 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2031 if(hd->tmPending == 0) {
2032 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002033 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 break;
2035 }
2036 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2037 msleep_interruptible(250);
2038 } while (--loop_count);
2039
2040 return status;
2041}
2042
2043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002044static void
2045mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2046{
2047 char *desc;
2048
2049 switch (response_code) {
2050 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2051 desc = "The task completed.";
2052 break;
2053 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2054 desc = "The IOC received an invalid frame status.";
2055 break;
2056 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2057 desc = "The task type is not supported.";
2058 break;
2059 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2060 desc = "The requested task failed.";
2061 break;
2062 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2063 desc = "The task completed successfully.";
2064 break;
2065 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2066 desc = "The LUN request is invalid.";
2067 break;
2068 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2069 desc = "The task is in the IOC queue and has not been sent to target.";
2070 break;
2071 default:
2072 desc = "unknown";
2073 break;
2074 }
2075 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2076 ioc->name, response_code, desc);
2077}
2078
2079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080/**
2081 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2082 * @ioc: Pointer to MPT_ADAPTER structure
2083 * @mf: Pointer to SCSI task mgmt request frame
2084 * @mr: Pointer to SCSI task mgmt reply frame
2085 *
2086 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2087 * of any SCSI task management request.
2088 * This routine is registered with the MPT (base) driver at driver
2089 * load/init time via the mpt_register() API call.
2090 *
2091 * Returns 1 indicating alloc'd request frame ptr should be freed.
2092 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002093int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2095{
2096 SCSITaskMgmtReply_t *pScsiTmReply;
2097 SCSITaskMgmt_t *pScsiTmReq;
2098 MPT_SCSI_HOST *hd;
2099 unsigned long flags;
2100 u16 iocstatus;
2101 u8 tmType;
2102
2103 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2104 ioc->name, mf, mr));
2105 if (ioc->sh) {
2106 /* Depending on the thread, a timer is activated for
2107 * the TM request. Delete this timer on completion of TM.
2108 * Decrement count of outstanding TM requests.
2109 */
2110 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2111 } else {
2112 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2113 ioc->name));
2114 return 1;
2115 }
2116
2117 if (mr == NULL) {
2118 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2119 ioc->name, mf));
2120 return 1;
2121 } else {
2122 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2123 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2124
2125 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2126 tmType = pScsiTmReq->TaskType;
2127
Moore, Eric9f63bb72006-01-16 18:53:26 -07002128 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2129 pScsiTmReply->ResponseCode)
2130 mptscsih_taskmgmt_response_code(ioc,
2131 pScsiTmReply->ResponseCode);
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2134 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2135 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2136
2137 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2138 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2139 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2140 /* Error? (anything non-zero?) */
2141 if (iocstatus) {
2142
2143 /* clear flags and continue.
2144 */
2145 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2146 hd->abortSCpnt = NULL;
2147
2148 /* If an internal command is present
2149 * or the TM failed - reload the FW.
2150 * FC FW may respond FAILED to an ABORT
2151 */
2152 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2153 if ((hd->cmdPtr) ||
2154 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2155 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2156 printk((KERN_WARNING
2157 " Firmware Reload FAILED!!\n"));
2158 }
2159 }
2160 }
2161 } else {
2162 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2163
2164 hd->abortSCpnt = NULL;
2165
2166 }
2167 }
2168
2169 spin_lock_irqsave(&ioc->FreeQlock, flags);
2170 hd->tmPending = 0;
2171 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2172 hd->tmState = TM_STATE_NONE;
2173
2174 return 1;
2175}
2176
2177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2178/*
2179 * This is anyones guess quite frankly.
2180 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002181int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2183 sector_t capacity, int geom[])
2184{
2185 int heads;
2186 int sectors;
2187 sector_t cylinders;
2188 ulong dummy;
2189
2190 heads = 64;
2191 sectors = 32;
2192
2193 dummy = heads * sectors;
2194 cylinders = capacity;
2195 sector_div(cylinders,dummy);
2196
2197 /*
2198 * Handle extended translation size for logical drives
2199 * > 1Gb
2200 */
2201 if ((ulong)capacity >= 0x200000) {
2202 heads = 255;
2203 sectors = 63;
2204 dummy = heads * sectors;
2205 cylinders = capacity;
2206 sector_div(cylinders,dummy);
2207 }
2208
2209 /* return result */
2210 geom[0] = heads;
2211 geom[1] = sectors;
2212 geom[2] = cylinders;
2213
2214 dprintk((KERN_NOTICE
2215 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2216 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2217
2218 return 0;
2219}
2220
2221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2222/*
2223 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002224 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002227int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002228mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002230 VirtTarget *vtarget;
2231
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002232 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002233 if (!vtarget)
2234 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002235 starget->hostdata = vtarget;
2236 return 0;
2237}
2238
2239/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2240/*
2241 * OS entry point to allow host driver to alloc memory
2242 * for each scsi device. Called once per device the bus scan.
2243 * Return non-zero if allocation fails.
2244 */
2245int
2246mptscsih_slave_alloc(struct scsi_device *sdev)
2247{
2248 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002250 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002252 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002254 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 if (!vdev) {
2256 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2257 hd->ioc->name, sizeof(VirtDevice));
2258 return -ENOMEM;
2259 }
2260
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 vdev->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002262 vdev->target_id = sdev->id;
2263 vdev->bus_id = sdev->channel;
2264 vdev->lun = sdev->lun;
2265 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002267 starget = scsi_target(sdev);
2268 vtarget = starget->hostdata;
2269 vdev->vtarget = vtarget;
2270
2271 if (vtarget->num_luns == 0) {
2272 hd->Targets[sdev->id] = vtarget;
2273 vtarget->ioc_id = hd->ioc->id;
2274 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2275 vtarget->target_id = sdev->id;
2276 vtarget->bus_id = sdev->channel;
2277 if (hd->ioc->bus_type == SPI) {
2278 if (hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2279 vtarget->raidVolume = 1;
2280 ddvtprintk((KERN_INFO
2281 "RAID Volume @ id %d\n", sdev->id));
2282 }
2283 } else {
2284 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2285 }
2286 }
2287 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 return 0;
2289}
2290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291/*
2292 * OS entry point to allow for host driver to free allocated memory
2293 * Called if no device present or device being unloaded
2294 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002295void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002296mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002298 if (starget->hostdata)
2299 kfree(starget->hostdata);
2300 starget->hostdata = NULL;
2301}
2302
2303/*
2304 * OS entry point to allow for host driver to free allocated memory
2305 * Called if no device present or device being unloaded
2306 */
2307void
2308mptscsih_slave_destroy(struct scsi_device *sdev)
2309{
2310 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002312 VirtTarget *vtarget;
2313 VirtDevice *vdevice;
2314 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002316 starget = scsi_target(sdev);
2317 vtarget = starget->hostdata;
2318 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002320 mptscsih_search_running_cmds(hd, vdevice);
2321 vtarget->luns[0] &= ~(1 << vdevice->lun);
2322 vtarget->num_luns--;
2323 if (vtarget->num_luns == 0) {
Moore, Erica69ac322006-01-17 17:06:26 -07002324 mptscsih_negotiate_to_asyn_narrow(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002325 if (hd->ioc->bus_type == SPI) {
2326 if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
2327 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2328 } else {
2329 hd->ioc->spi_data.dvStatus[vtarget->target_id] =
2330 MPT_SCSICFG_NEGOTIATE;
2331 if (!hd->negoNvram) {
2332 hd->ioc->spi_data.dvStatus[vtarget->target_id] |=
2333 MPT_SCSICFG_DV_NOT_DONE;
2334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
2336 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002337 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002339 mptscsih_synchronize_cache(hd, vdevice);
2340 kfree(vdevice);
2341 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342}
2343
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2345/*
2346 * mptscsih_change_queue_depth - This function will set a devices queue depth
2347 * @sdev: per scsi_device pointer
2348 * @qdepth: requested queue depth
2349 *
2350 * Adding support for new 'change_queue_depth' api.
2351*/
2352int
2353mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002355 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2356 VirtTarget *vtarget;
2357 struct scsi_target *starget;
2358 int max_depth;
2359 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002361 starget = scsi_target(sdev);
2362 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002363
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002364 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002365 if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2366 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 max_depth = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368 else if (((vtarget->inq_data[0] & 0x1f) == 0x00) &&
2369 (vtarget->minSyncFactor <= MPT_ULTRA160 ))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2371 else
2372 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2373 } else {
2374 /* error case - No Inq. Data */
2375 max_depth = 1;
2376 }
2377 } else
2378 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2379
2380 if (qdepth > max_depth)
2381 qdepth = max_depth;
2382 if (qdepth == 1)
2383 tagged = 0;
2384 else
2385 tagged = MSG_SIMPLE_TAG;
2386
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002387 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2388 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389}
2390
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391/*
2392 * OS entry point to adjust the queue_depths on a per-device basis.
2393 * Called once per device the bus scan. Use it to force the queue_depth
2394 * member to 1 if a device does not support Q tags.
2395 * Return non-zero if fails.
2396 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002397int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002398mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002400 struct Scsi_Host *sh = sdev->host;
2401 VirtTarget *vtarget;
2402 VirtDevice *vdevice;
2403 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 starget = scsi_target(sdev);
2408 vtarget = starget->hostdata;
2409 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
2411 dsprintk((MYIOC_s_INFO_FMT
2412 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002413 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2414 if (hd->ioc->bus_type == SPI)
2415 dsprintk((MYIOC_s_INFO_FMT
2416 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2417 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2418 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002420 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002422 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 goto slave_configure_exit;
2424 }
2425
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002426 vdevice->configured_lun=1;
2427 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2428 indexed_lun = (vdevice->lun % 32);
2429 vtarget->luns[lun_index] |= (1 << indexed_lun);
2430 mptscsih_initTarget(hd, vtarget, sdev->lun, sdev->inquiry,
2431 sdev->inquiry_len );
2432 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 dsprintk((MYIOC_s_INFO_FMT
2435 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002436 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002438 if (hd->ioc->bus_type == SPI)
2439 dsprintk((MYIOC_s_INFO_FMT
2440 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2441 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2442 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444slave_configure_exit:
2445
2446 dsprintk((MYIOC_s_INFO_FMT
2447 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002448 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2449 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 return 0;
2452}
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2455/*
2456 * Private routines...
2457 */
2458
2459/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2460/* Utility function to copy sense data from the scsi_cmnd buffer
2461 * to the FC and SCSI target structures.
2462 *
2463 */
2464static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002465mptscsih_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 -07002466{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002467 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 SCSIIORequest_t *pReq;
2469 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
2471 /* Get target structure
2472 */
2473 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002474 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
2476 if (sense_count) {
2477 u8 *sense_data;
2478 int req_index;
2479
2480 /* Copy the sense received into the scsi command block. */
2481 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2482 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2483 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2484
2485 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2486 */
2487 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002488 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 int idx;
2490 MPT_ADAPTER *ioc = hd->ioc;
2491
2492 idx = ioc->eventContext % ioc->eventLogSize;
2493 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2494 ioc->events[idx].eventContext = ioc->eventContext;
2495
2496 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2497 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002498 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
2500 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2501
2502 ioc->eventContext++;
2503 }
2504 }
2505 } else {
2506 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2507 hd->ioc->name));
2508 }
2509}
2510
2511static u32
2512SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2513{
2514 MPT_SCSI_HOST *hd;
2515 int i;
2516
2517 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2518
2519 for (i = 0; i < hd->ioc->req_depth; i++) {
2520 if (hd->ScsiLookup[i] == sc) {
2521 return i;
2522 }
2523 }
2524
2525 return -1;
2526}
2527
2528/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002529int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2531{
2532 MPT_SCSI_HOST *hd;
2533 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002534 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
2536 dtmprintk((KERN_WARNING MYNAM
2537 ": IOC %s_reset routed to SCSI host driver!\n",
2538 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2539 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2540
2541 /* If a FW reload request arrives after base installed but
2542 * before all scsi hosts have been attached, then an alt_ioc
2543 * may have a NULL sh pointer.
2544 */
2545 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2546 return 0;
2547 else
2548 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2549
2550 if (reset_phase == MPT_IOC_SETUP_RESET) {
2551 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2552
2553 /* Clean Up:
2554 * 1. Set Hard Reset Pending Flag
2555 * All new commands go to doneQ
2556 */
2557 hd->resetPending = 1;
2558
2559 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2560 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2561
2562 /* 2. Flush running commands
2563 * Clean ScsiLookup (and associated memory)
2564 * AND clean mytaskQ
2565 */
2566
2567 /* 2b. Reply to OS all known outstanding I/O commands.
2568 */
2569 mptscsih_flush_running_cmds(hd);
2570
2571 /* 2c. If there was an internal command that
2572 * has not completed, configuration or io request,
2573 * free these resources.
2574 */
2575 if (hd->cmdPtr) {
2576 del_timer(&hd->timer);
2577 mpt_free_msg_frame(ioc, hd->cmdPtr);
2578 }
2579
2580 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2581
2582 } else {
2583 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2584
2585 /* Once a FW reload begins, all new OS commands are
2586 * redirected to the doneQ w/ a reset status.
2587 * Init all control structures.
2588 */
2589
2590 /* ScsiLookup initialization
2591 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002592 for (ii=0; ii < hd->ioc->req_depth; ii++)
2593 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595 /* 2. Chain Buffer initialization
2596 */
2597
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002598 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002600 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2602 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2603 }
2604
2605 /* 5. Enable new commands to be posted
2606 */
2607 spin_lock_irqsave(&ioc->FreeQlock, flags);
2608 hd->tmPending = 0;
2609 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2610 hd->resetPending = 0;
2611 hd->tmState = TM_STATE_NONE;
2612
2613 /* 6. If there was an internal command,
2614 * wake this process up.
2615 */
2616 if (hd->cmdPtr) {
2617 /*
2618 * Wake up the original calling thread
2619 */
2620 hd->pLocal = &hd->localReply;
2621 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002622 hd->scandv_wait_done = 1;
2623 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 hd->cmdPtr = NULL;
2625 }
2626
Michael Reed05e8ec12006-01-13 14:31:54 -06002627 /* 7. SPI: Set flag to force DV and re-read IOC Page 3
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002629 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2631 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2632 }
2633
Michael Reed05e8ec12006-01-13 14:31:54 -06002634 /* 7. FC: Rescan for blocked rports which might have returned.
2635 */
2636 else if (ioc->bus_type == FC) {
2637 int work_count;
2638 unsigned long flags;
2639
2640 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2641 work_count = ++ioc->fc_rescan_work_count;
2642 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2643 if (work_count == 1)
2644 schedule_work(&ioc->fc_rescan_work);
2645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2647
2648 }
2649
2650 return 1; /* currently means nothing really */
2651}
2652
2653/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002654int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2656{
2657 MPT_SCSI_HOST *hd;
2658 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
Michael Reed05e8ec12006-01-13 14:31:54 -06002659 int work_count;
2660 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
2662 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2663 ioc->name, event));
2664
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002665 if (ioc->sh == NULL ||
2666 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2667 return 1;
2668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 switch (event) {
2670 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2671 /* FIXME! */
2672 break;
2673 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2674 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002675 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002676 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 break;
2678 case MPI_EVENT_LOGOUT: /* 09 */
2679 /* FIXME! */
2680 break;
2681
Michael Reed05e8ec12006-01-13 14:31:54 -06002682 case MPI_EVENT_RESCAN: /* 06 */
2683 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2684 work_count = ++ioc->fc_rescan_work_count;
2685 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2686 if (work_count == 1)
2687 schedule_work(&ioc->fc_rescan_work);
2688 break;
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 /*
2691 * CHECKME! Don't think we need to do
2692 * anything for these, but...
2693 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2695 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2696 /*
2697 * CHECKME! Falling thru...
2698 */
2699 break;
2700
2701 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002702 {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07002703#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002704 pMpiEventDataRaid_t pRaidEventData =
2705 (pMpiEventDataRaid_t) pEvReply->Data;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002706 /* Domain Validation Needed */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002707 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002708 pRaidEventData->ReasonCode ==
2709 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2710 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002712 break;
2713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 case MPI_EVENT_NONE: /* 00 */
2716 case MPI_EVENT_LOG_DATA: /* 01 */
2717 case MPI_EVENT_STATE_CHANGE: /* 02 */
2718 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2719 default:
2720 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2721 break;
2722 }
2723
2724 return 1; /* currently means nothing really */
2725}
2726
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2728/*
2729 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2730 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002731 * @vtarget: per target private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 * @lun: SCSI LUN id
2733 * @data: Pointer to data
2734 * @dlen: Number of INQUIRY bytes
2735 *
2736 * NOTE: It's only SAFE to call this routine if data points to
2737 * sane & valid STANDARD INQUIRY data!
2738 *
2739 * Allocate and initialize memory for this target.
2740 * Save inquiry data.
2741 *
2742 */
2743static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002744mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002746 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 char data_56;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002748 int inq_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
2750 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002751 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752
2753 /*
2754 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2755 * (i.e. The targer is capable of supporting the specified peripheral device type
2756 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002757 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 * capable of supporting a physical device on this logical unit). This is to work
2759 * around a bug in th emid-layer in some distributions in which the mid-layer will
2760 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2761 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002762 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 /* Is LUN supported? If so, upper 2 bits will be 0
2766 * in first byte of inquiry data.
2767 */
2768 if (data[0] & 0xe0)
2769 return;
2770
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002771 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002774 if (data)
2775 vtarget->type = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002777 if (hd->ioc->bus_type != SPI)
2778 return;
2779
2780 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2781 /* Treat all Processors as SAF-TE if
2782 * command line option is set */
2783 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2784 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
2785 }else if ((data[0] == TYPE_PROCESSOR) &&
2786 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2787 if ( dlen > 49 ) {
2788 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2789 if ( data[44] == 'S' &&
2790 data[45] == 'A' &&
2791 data[46] == 'F' &&
2792 data[47] == '-' &&
2793 data[48] == 'T' &&
2794 data[49] == 'E' ) {
2795 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2796 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 }
2798 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002799 }
2800 if (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2801 inq_len = dlen < 8 ? dlen : 8;
2802 memcpy (vtarget->inq_data, data, inq_len);
2803 /* If have not done DV, set the DV flag.
2804 */
2805 pSpi = &hd->ioc->spi_data;
2806 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2807 if (pSpi->dvStatus[vtarget->target_id] & MPT_SCSICFG_DV_NOT_DONE)
2808 pSpi->dvStatus[vtarget->target_id] |= MPT_SCSICFG_NEED_DV;
2809 }
2810 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002812 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2813 if (dlen > 56) {
2814 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2815 /* Update the target capabilities
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002817 data_56 = data[56];
2818 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002820 }
2821 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
2822 } else {
2823 /* Initial Inquiry may not request enough data bytes to
2824 * obtain byte 57. DV will; if target doesn't return
2825 * at least 57 bytes, data[56] will be zero. */
2826 if (dlen > 56) {
2827 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2828 /* Update the target capabilities
2829 */
2830 data_56 = data[56];
2831 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
2832 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 }
2834 }
2835 }
2836}
2837
2838/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2839/*
2840 * Update the target negotiation parameters based on the
2841 * the Inquiry data, adapter capabilities, and NVRAM settings.
2842 *
2843 */
2844static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002845mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, char byte56)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002847 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 int id = (int) target->target_id;
2849 int nvram;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002850 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 int ii;
2852 u8 width = MPT_NARROW;
2853 u8 factor = MPT_ASYNC;
2854 u8 offset = 0;
2855 u8 version, nfactor;
2856 u8 noQas = 1;
2857
2858 target->negoFlags = pspi_data->noQas;
2859
2860 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2861 * support. If available, default QAS to off and allow enabling.
2862 * If not available, default QAS to on, turn off for non-disks.
2863 */
2864
2865 /* Set flags based on Inquiry data
2866 */
2867 version = target->inq_data[2] & 0x07;
2868 if (version < 2) {
2869 width = 0;
2870 factor = MPT_ULTRA2;
2871 offset = pspi_data->maxSyncOffset;
2872 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2873 } else {
2874 if (target->inq_data[7] & 0x20) {
2875 width = 1;
2876 }
2877
2878 if (target->inq_data[7] & 0x10) {
2879 factor = pspi_data->minSyncFactor;
2880 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2881 /* bits 2 & 3 show Clocking support */
2882 if ((byte56 & 0x0C) == 0)
2883 factor = MPT_ULTRA2;
2884 else {
2885 if ((byte56 & 0x03) == 0)
2886 factor = MPT_ULTRA160;
2887 else {
2888 factor = MPT_ULTRA320;
2889 if (byte56 & 0x02)
2890 {
2891 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2892 noQas = 0;
2893 }
2894 if (target->inq_data[0] == TYPE_TAPE) {
2895 if (byte56 & 0x01)
2896 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2897 }
2898 }
2899 }
2900 } else {
2901 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2902 noQas = 0;
2903 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 offset = pspi_data->maxSyncOffset;
2906
2907 /* If RAID, never disable QAS
2908 * else if non RAID, do not disable
2909 * QAS if bit 1 is set
2910 * bit 1 QAS support, non-raid only
2911 * bit 0 IU support
2912 */
2913 if (target->raidVolume == 1) {
2914 noQas = 0;
2915 }
2916 } else {
2917 factor = MPT_ASYNC;
2918 offset = 0;
2919 }
2920 }
2921
2922 if ( (target->inq_data[7] & 0x02) == 0) {
2923 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2924 }
2925
2926 /* Update tflags based on NVRAM settings. (SCSI only)
2927 */
2928 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2929 nvram = pspi_data->nvram[id];
2930 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2931
2932 if (width)
2933 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2934
2935 if (offset > 0) {
2936 /* Ensure factor is set to the
2937 * maximum of: adapter, nvram, inquiry
2938 */
2939 if (nfactor) {
2940 if (nfactor < pspi_data->minSyncFactor )
2941 nfactor = pspi_data->minSyncFactor;
2942
2943 factor = max(factor, nfactor);
2944 if (factor == MPT_ASYNC)
2945 offset = 0;
2946 } else {
2947 offset = 0;
2948 factor = MPT_ASYNC;
2949 }
2950 } else {
2951 factor = MPT_ASYNC;
2952 }
2953 }
2954
2955 /* Make sure data is consistent
2956 */
2957 if ((!width) && (factor < MPT_ULTRA2)) {
2958 factor = MPT_ULTRA2;
2959 }
2960
2961 /* Save the data to the target structure.
2962 */
2963 target->minSyncFactor = factor;
2964 target->maxOffset = offset;
2965 target->maxWidth = width;
2966
2967 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2968
2969 /* Disable unused features.
2970 */
2971 if (!width)
2972 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2973
2974 if (!offset)
2975 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2976
2977 if ( factor > MPT_ULTRA320 )
2978 noQas = 0;
2979
2980 /* GEM, processor WORKAROUND
2981 */
2982 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2983 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2984 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2985 } else {
2986 if (noQas && (pspi_data->noQas == 0)) {
2987 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2988 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2989
2990 /* Disable QAS in a mixed configuration case
2991 */
2992
2993 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2994 for (ii = 0; ii < id; ii++) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002995 if ( (vtarget = hd->Targets[ii]) ) {
2996 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2997 mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 }
3000 }
3001 }
3002
3003 /* Write SDP1 on this I/O to this target */
3004 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
3005 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
3006 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
3007 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
3008 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
3009 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
3010 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
3011 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
3012 }
3013}
3014
3015/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016/*
3017 * If no Target, bus reset on 1st I/O. Set the flag to
3018 * prevent any future negotiations to this device.
3019 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003020static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003021mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003023 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003025 if ((vdev = sc->device->hostdata) != NULL)
3026 hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 return;
3028}
3029
3030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3031/*
3032 * SCSI Config Page functionality ...
3033 */
3034/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3035/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
3036 * based on width, factor and offset parameters.
3037 * @width: bus width
3038 * @factor: sync factor
3039 * @offset: sync offset
3040 * @requestedPtr: pointer to requested values (updated)
3041 * @configurationPtr: pointer to configuration values (updated)
3042 * @flags: flags to block WDTR or SDTR negotiation
3043 *
3044 * Return: None.
3045 *
3046 * Remark: Called by writeSDP1 and _dv_params
3047 */
3048static void
3049mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3050{
3051 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3052 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3053
3054 *configurationPtr = 0;
3055 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3056 *requestedPtr |= (offset << 16) | (factor << 8);
3057
3058 if (width && offset && !nowide && !nosync) {
3059 if (factor < MPT_ULTRA160) {
3060 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3061 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3062 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3063 if (flags & MPT_TAPE_NEGO_IDP)
3064 *requestedPtr |= 0x08000000;
3065 } else if (factor < MPT_ULTRA2) {
3066 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3067 }
3068 }
3069
3070 if (nowide)
3071 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3072
3073 if (nosync)
3074 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3075
3076 return;
3077}
3078
3079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3080/* mptscsih_writeSDP1 - write SCSI Device Page 1
3081 * @hd: Pointer to a SCSI Host Strucutre
3082 * @portnum: IOC port number
3083 * @target_id: writeSDP1 for single ID
3084 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3085 *
3086 * Return: -EFAULT if read of config page header fails
3087 * or 0 if success.
3088 *
3089 * Remark: If a target has been found, the settings from the
3090 * target structure are used, else the device is set
3091 * to async/narrow.
3092 *
3093 * Remark: Called during init and after a FW reload.
3094 * Remark: We do not wait for a return, write pages sequentially.
3095 */
3096static int
3097mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3098{
3099 MPT_ADAPTER *ioc = hd->ioc;
3100 Config_t *pReq;
3101 SCSIDevicePage1_t *pData;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003102 VirtTarget *vtarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 MPT_FRAME_HDR *mf;
3104 dma_addr_t dataDma;
3105 u16 req_idx;
3106 u32 frameOffset;
3107 u32 requested, configuration, flagsLength;
3108 int ii, nvram;
3109 int id = 0, maxid = 0;
3110 u8 width;
3111 u8 factor;
3112 u8 offset;
3113 u8 bus = 0;
3114 u8 negoFlags;
3115 u8 maxwidth, maxoffset, maxfactor;
3116
3117 if (ioc->spi_data.sdp1length == 0)
3118 return 0;
3119
3120 if (flags & MPT_SCSICFG_ALL_IDS) {
3121 id = 0;
3122 maxid = ioc->sh->max_id - 1;
3123 } else if (ioc->sh) {
3124 id = target_id;
3125 maxid = min_t(int, id, ioc->sh->max_id - 1);
3126 }
3127
3128 for (; id <= maxid; id++) {
3129
3130 if (id == ioc->pfacts[portnum].PortSCSIID)
3131 continue;
3132
3133 /* Use NVRAM to get adapter and target maximums
3134 * Data over-riden by target structure information, if present
3135 */
3136 maxwidth = ioc->spi_data.maxBusWidth;
3137 maxoffset = ioc->spi_data.maxSyncOffset;
3138 maxfactor = ioc->spi_data.minSyncFactor;
3139 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3140 nvram = ioc->spi_data.nvram[id];
3141
3142 if (maxwidth)
3143 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3144
3145 if (maxoffset > 0) {
3146 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3147 if (maxfactor == 0) {
3148 /* Key for async */
3149 maxfactor = MPT_ASYNC;
3150 maxoffset = 0;
3151 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3152 maxfactor = ioc->spi_data.minSyncFactor;
3153 }
3154 } else
3155 maxfactor = MPT_ASYNC;
3156 }
3157
3158 /* Set the negotiation flags.
3159 */
3160 negoFlags = ioc->spi_data.noQas;
3161 if (!maxwidth)
3162 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3163
3164 if (!maxoffset)
3165 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3166
3167 if (flags & MPT_SCSICFG_USE_NVRAM) {
3168 width = maxwidth;
3169 factor = maxfactor;
3170 offset = maxoffset;
3171 } else {
3172 width = 0;
3173 factor = MPT_ASYNC;
3174 offset = 0;
3175 //negoFlags = 0;
3176 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3177 }
3178
3179 /* If id is not a raid volume, get the updated
3180 * transmission settings from the target structure.
3181 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003182 if (hd->Targets && (vtarget = hd->Targets[id]) && !vtarget->raidVolume) {
3183 width = vtarget->maxWidth;
3184 factor = vtarget->minSyncFactor;
3185 offset = vtarget->maxOffset;
3186 negoFlags = vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003188
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3190 /* Force to async and narrow if DV has not been executed
3191 * for this ID
3192 */
3193 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3194 width = 0;
3195 factor = MPT_ASYNC;
3196 offset = 0;
3197 }
3198#endif
3199
3200 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003201 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
3203 mptscsih_setDevicePage1Flags(width, factor, offset,
3204 &requested, &configuration, negoFlags);
3205 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3206 target_id, width, factor, offset, negoFlags, requested, configuration));
3207
3208 /* Get a MF for this command.
3209 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003210 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003211 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3212 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 return -EAGAIN;
3214 }
3215
3216 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3217 hd->ioc->name, mf, id, requested, configuration));
3218
3219
3220 /* Set the request and the data pointers.
3221 * Request takes: 36 bytes (32 bit SGE)
3222 * SCSI Device Page 1 requires 16 bytes
3223 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3224 * and MF size >= 64 bytes.
3225 * Place data at end of MF.
3226 */
3227 pReq = (Config_t *)mf;
3228
3229 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3230 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3231
3232 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3233 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3234
3235 /* Complete the request frame (same for all requests).
3236 */
3237 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3238 pReq->Reserved = 0;
3239 pReq->ChainOffset = 0;
3240 pReq->Function = MPI_FUNCTION_CONFIG;
3241 pReq->ExtPageLength = 0;
3242 pReq->ExtPageType = 0;
3243 pReq->MsgFlags = 0;
3244 for (ii=0; ii < 8; ii++) {
3245 pReq->Reserved2[ii] = 0;
3246 }
3247 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3248 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3249 pReq->Header.PageNumber = 1;
3250 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3251 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3252
3253 /* Add a SGE to the config request.
3254 */
3255 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3256
3257 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3258
3259 /* Set up the common data portion
3260 */
3261 pData->Header.PageVersion = pReq->Header.PageVersion;
3262 pData->Header.PageLength = pReq->Header.PageLength;
3263 pData->Header.PageNumber = pReq->Header.PageNumber;
3264 pData->Header.PageType = pReq->Header.PageType;
3265 pData->RequestedParameters = cpu_to_le32(requested);
3266 pData->Reserved = 0;
3267 pData->Configuration = cpu_to_le32(configuration);
3268
3269 dprintk((MYIOC_s_INFO_FMT
3270 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3271 ioc->name, id, (id | (bus<<8)),
3272 requested, configuration));
3273
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003274 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 }
3276
3277 return 0;
3278}
3279
3280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3281/* mptscsih_writeIOCPage4 - write IOC Page 4
3282 * @hd: Pointer to a SCSI Host Structure
3283 * @target_id: write IOC Page4 for this ID & Bus
3284 *
3285 * Return: -EAGAIN if unable to obtain a Message Frame
3286 * or 0 if success.
3287 *
3288 * Remark: We do not wait for a return, write pages sequentially.
3289 */
3290static int
3291mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3292{
3293 MPT_ADAPTER *ioc = hd->ioc;
3294 Config_t *pReq;
3295 IOCPage4_t *IOCPage4Ptr;
3296 MPT_FRAME_HDR *mf;
3297 dma_addr_t dataDma;
3298 u16 req_idx;
3299 u32 frameOffset;
3300 u32 flagsLength;
3301 int ii;
3302
3303 /* Get a MF for this command.
3304 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003305 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003306 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 ioc->name));
3308 return -EAGAIN;
3309 }
3310
3311 /* Set the request and the data pointers.
3312 * Place data at end of MF.
3313 */
3314 pReq = (Config_t *)mf;
3315
3316 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3317 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3318
3319 /* Complete the request frame (same for all requests).
3320 */
3321 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3322 pReq->Reserved = 0;
3323 pReq->ChainOffset = 0;
3324 pReq->Function = MPI_FUNCTION_CONFIG;
3325 pReq->ExtPageLength = 0;
3326 pReq->ExtPageType = 0;
3327 pReq->MsgFlags = 0;
3328 for (ii=0; ii < 8; ii++) {
3329 pReq->Reserved2[ii] = 0;
3330 }
3331
3332 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3333 dataDma = ioc->spi_data.IocPg4_dma;
3334 ii = IOCPage4Ptr->ActiveSEP++;
3335 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3336 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3337 pReq->Header = IOCPage4Ptr->Header;
3338 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3339
3340 /* Add a SGE to the config request.
3341 */
3342 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3343 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3344
3345 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3346
3347 dinitprintk((MYIOC_s_INFO_FMT
3348 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3349 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3350
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003351 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
3353 return 0;
3354}
3355
3356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3357/*
3358 * Bus Scan and Domain Validation functionality ...
3359 */
3360
3361/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3362/*
3363 * mptscsih_scandv_complete - Scan and DV callback routine registered
3364 * to Fustion MPT (base) driver.
3365 *
3366 * @ioc: Pointer to MPT_ADAPTER structure
3367 * @mf: Pointer to original MPT request frame
3368 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3369 *
3370 * This routine is called from mpt.c::mpt_interrupt() at the completion
3371 * of any SCSI IO request.
3372 * This routine is registered with the Fusion MPT (base) driver at driver
3373 * load/init time via the mpt_register() API call.
3374 *
3375 * Returns 1 indicating alloc'd request frame ptr should be freed.
3376 *
3377 * Remark: Sets a completion code and (possibly) saves sense data
3378 * in the IOC member localReply structure.
3379 * Used ONLY for DV and other internal commands.
3380 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003381int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3383{
3384 MPT_SCSI_HOST *hd;
3385 SCSIIORequest_t *pReq;
3386 int completionCode;
3387 u16 req_idx;
3388
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003389 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3390
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 if ((mf == NULL) ||
3392 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3393 printk(MYIOC_s_ERR_FMT
3394 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3395 ioc->name, mf?"BAD":"NULL", (void *) mf);
3396 goto wakeup;
3397 }
3398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 del_timer(&hd->timer);
3400 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3401 hd->ScsiLookup[req_idx] = NULL;
3402 pReq = (SCSIIORequest_t *) mf;
3403
3404 if (mf != hd->cmdPtr) {
3405 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3406 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3407 }
3408 hd->cmdPtr = NULL;
3409
3410 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3411 hd->ioc->name, mf, mr, req_idx));
3412
3413 hd->pLocal = &hd->localReply;
3414 hd->pLocal->scsiStatus = 0;
3415
3416 /* If target struct exists, clear sense valid flag.
3417 */
3418 if (mr == NULL) {
3419 completionCode = MPT_SCANDV_GOOD;
3420 } else {
3421 SCSIIOReply_t *pReply;
3422 u16 status;
3423 u8 scsi_status;
3424
3425 pReply = (SCSIIOReply_t *) mr;
3426
3427 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3428 scsi_status = pReply->SCSIStatus;
3429
3430 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3431 status, pReply->SCSIState, scsi_status,
3432 le32_to_cpu(pReply->IOCLogInfo)));
3433
3434 switch(status) {
3435
3436 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3437 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3438 break;
3439
3440 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3441 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3442 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3443 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3444 completionCode = MPT_SCANDV_DID_RESET;
3445 break;
3446
3447 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3448 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3449 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3450 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3451 ConfigReply_t *pr = (ConfigReply_t *)mr;
3452 completionCode = MPT_SCANDV_GOOD;
3453 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3454 hd->pLocal->header.PageLength = pr->Header.PageLength;
3455 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3456 hd->pLocal->header.PageType = pr->Header.PageType;
3457
3458 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3459 /* If the RAID Volume request is successful,
3460 * return GOOD, else indicate that
3461 * some type of error occurred.
3462 */
3463 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003464 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 completionCode = MPT_SCANDV_GOOD;
3466 else
3467 completionCode = MPT_SCANDV_SOME_ERROR;
3468
3469 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3470 u8 *sense_data;
3471 int sz;
3472
3473 /* save sense data in global structure
3474 */
3475 completionCode = MPT_SCANDV_SENSE;
3476 hd->pLocal->scsiStatus = scsi_status;
3477 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3478 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3479
3480 sz = min_t(int, pReq->SenseBufferLength,
3481 SCSI_STD_SENSE_BYTES);
3482 memcpy(hd->pLocal->sense, sense_data, sz);
3483
3484 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3485 sense_data));
3486 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3487 if (pReq->CDB[0] == INQUIRY)
3488 completionCode = MPT_SCANDV_ISSUE_SENSE;
3489 else
3490 completionCode = MPT_SCANDV_DID_RESET;
3491 }
3492 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3493 completionCode = MPT_SCANDV_DID_RESET;
3494 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3495 completionCode = MPT_SCANDV_DID_RESET;
3496 else {
3497 completionCode = MPT_SCANDV_GOOD;
3498 hd->pLocal->scsiStatus = scsi_status;
3499 }
3500 break;
3501
3502 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3503 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3504 completionCode = MPT_SCANDV_DID_RESET;
3505 else
3506 completionCode = MPT_SCANDV_SOME_ERROR;
3507 break;
3508
3509 default:
3510 completionCode = MPT_SCANDV_SOME_ERROR;
3511 break;
3512
3513 } /* switch(status) */
3514
3515 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3516 completionCode));
3517 } /* end of address reply case */
3518
3519 hd->pLocal->completion = completionCode;
3520
3521 /* MF and RF are freed in mpt_interrupt
3522 */
3523wakeup:
3524 /* Free Chain buffers (will never chain) in scan or dv */
3525 //mptscsih_freeChainBuffers(ioc, req_idx);
3526
3527 /*
3528 * Wake up the original calling thread
3529 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003530 hd->scandv_wait_done = 1;
3531 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
3533 return 1;
3534}
3535
3536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3537/* mptscsih_timer_expired - Call back for timer process.
3538 * Used only for dv functionality.
3539 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3540 *
3541 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003542void
3543mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544{
3545 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3546
3547 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3548
3549 if (hd->cmdPtr) {
3550 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3551
3552 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3553 /* Desire to issue a task management request here.
3554 * TM requests MUST be single threaded.
3555 * If old eh code and no TM current, issue request.
3556 * If new eh code, do nothing. Wait for OS cmd timeout
3557 * for bus reset.
3558 */
3559 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3560 } else {
3561 /* Perform a FW reload */
3562 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3563 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3564 }
3565 }
3566 } else {
3567 /* This should NEVER happen */
3568 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3569 }
3570
3571 /* No more processing.
3572 * TM call will generate an interrupt for SCSI TM Management.
3573 * The FW will reply to all outstanding commands, callback will finish cleanup.
3574 * Hard reset clean-up will free all resources.
3575 */
3576 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3577
3578 return;
3579}
3580
3581#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3582/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3583/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3584 * @hd: Pointer to scsi host structure
3585 * @action: What do be done.
3586 * @id: Logical target id.
3587 * @bus: Target locations bus.
3588 *
3589 * Returns: < 0 on a fatal error
3590 * 0 on success
3591 *
3592 * Remark: Wait to return until reply processed by the ISR.
3593 */
3594static int
3595mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3596{
3597 MpiRaidActionRequest_t *pReq;
3598 MPT_FRAME_HDR *mf;
3599 int in_isr;
3600
3601 in_isr = in_interrupt();
3602 if (in_isr) {
3603 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3604 hd->ioc->name));
3605 return -EPERM;
3606 }
3607
3608 /* Get and Populate a free Frame
3609 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003610 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3612 hd->ioc->name));
3613 return -EAGAIN;
3614 }
3615 pReq = (MpiRaidActionRequest_t *)mf;
3616 pReq->Action = action;
3617 pReq->Reserved1 = 0;
3618 pReq->ChainOffset = 0;
3619 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3620 pReq->VolumeID = io->id;
3621 pReq->VolumeBus = io->bus;
3622 pReq->PhysDiskNum = io->physDiskNum;
3623 pReq->MsgFlags = 0;
3624 pReq->Reserved2 = 0;
3625 pReq->ActionDataWord = 0; /* Reserved for this action */
3626 //pReq->ActionDataSGE = 0;
3627
3628 mpt_add_sge((char *)&pReq->ActionDataSGE,
3629 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3630
3631 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3632 hd->ioc->name, action, io->id));
3633
3634 hd->pLocal = NULL;
3635 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003636 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637
3638 /* Save cmd pointer, for resource free if timeout or
3639 * FW reload occurs
3640 */
3641 hd->cmdPtr = mf;
3642
3643 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003644 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3645 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646
3647 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3648 return -1;
3649
3650 return 0;
3651}
3652#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3653
3654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3655/**
3656 * mptscsih_do_cmd - Do internal command.
3657 * @hd: MPT_SCSI_HOST pointer
3658 * @io: INTERNAL_CMD pointer.
3659 *
3660 * Issue the specified internally generated command and do command
3661 * specific cleanup. For bus scan / DV only.
3662 * NOTES: If command is Inquiry and status is good,
3663 * initialize a target structure, save the data
3664 *
3665 * Remark: Single threaded access only.
3666 *
3667 * Return:
3668 * < 0 if an illegal command or no resources
3669 *
3670 * 0 if good
3671 *
3672 * > 0 if command complete but some type of completion error.
3673 */
3674static int
3675mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3676{
3677 MPT_FRAME_HDR *mf;
3678 SCSIIORequest_t *pScsiReq;
3679 SCSIIORequest_t ReqCopy;
3680 int my_idx, ii, dir;
3681 int rc, cmdTimeout;
3682 int in_isr;
3683 char cmdLen;
3684 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3685 char cmd = io->cmd;
3686
3687 in_isr = in_interrupt();
3688 if (in_isr) {
3689 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3690 hd->ioc->name));
3691 return -EPERM;
3692 }
3693
3694
3695 /* Set command specific information
3696 */
3697 switch (cmd) {
3698 case INQUIRY:
3699 cmdLen = 6;
3700 dir = MPI_SCSIIO_CONTROL_READ;
3701 CDB[0] = cmd;
3702 CDB[4] = io->size;
3703 cmdTimeout = 10;
3704 break;
3705
3706 case TEST_UNIT_READY:
3707 cmdLen = 6;
3708 dir = MPI_SCSIIO_CONTROL_READ;
3709 cmdTimeout = 10;
3710 break;
3711
3712 case START_STOP:
3713 cmdLen = 6;
3714 dir = MPI_SCSIIO_CONTROL_READ;
3715 CDB[0] = cmd;
3716 CDB[4] = 1; /*Spin up the disk */
3717 cmdTimeout = 15;
3718 break;
3719
3720 case REQUEST_SENSE:
3721 cmdLen = 6;
3722 CDB[0] = cmd;
3723 CDB[4] = io->size;
3724 dir = MPI_SCSIIO_CONTROL_READ;
3725 cmdTimeout = 10;
3726 break;
3727
3728 case READ_BUFFER:
3729 cmdLen = 10;
3730 dir = MPI_SCSIIO_CONTROL_READ;
3731 CDB[0] = cmd;
3732 if (io->flags & MPT_ICFLAG_ECHO) {
3733 CDB[1] = 0x0A;
3734 } else {
3735 CDB[1] = 0x02;
3736 }
3737
3738 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3739 CDB[1] |= 0x01;
3740 }
3741 CDB[6] = (io->size >> 16) & 0xFF;
3742 CDB[7] = (io->size >> 8) & 0xFF;
3743 CDB[8] = io->size & 0xFF;
3744 cmdTimeout = 10;
3745 break;
3746
3747 case WRITE_BUFFER:
3748 cmdLen = 10;
3749 dir = MPI_SCSIIO_CONTROL_WRITE;
3750 CDB[0] = cmd;
3751 if (io->flags & MPT_ICFLAG_ECHO) {
3752 CDB[1] = 0x0A;
3753 } else {
3754 CDB[1] = 0x02;
3755 }
3756 CDB[6] = (io->size >> 16) & 0xFF;
3757 CDB[7] = (io->size >> 8) & 0xFF;
3758 CDB[8] = io->size & 0xFF;
3759 cmdTimeout = 10;
3760 break;
3761
3762 case RESERVE:
3763 cmdLen = 6;
3764 dir = MPI_SCSIIO_CONTROL_READ;
3765 CDB[0] = cmd;
3766 cmdTimeout = 10;
3767 break;
3768
3769 case RELEASE:
3770 cmdLen = 6;
3771 dir = MPI_SCSIIO_CONTROL_READ;
3772 CDB[0] = cmd;
3773 cmdTimeout = 10;
3774 break;
3775
3776 case SYNCHRONIZE_CACHE:
3777 cmdLen = 10;
3778 dir = MPI_SCSIIO_CONTROL_READ;
3779 CDB[0] = cmd;
3780// CDB[1] = 0x02; /* set immediate bit */
3781 cmdTimeout = 10;
3782 break;
3783
3784 default:
3785 /* Error Case */
3786 return -EFAULT;
3787 }
3788
3789 /* Get and Populate a free Frame
3790 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003791 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3793 hd->ioc->name));
3794 return -EBUSY;
3795 }
3796
3797 pScsiReq = (SCSIIORequest_t *) mf;
3798
3799 /* Get the request index */
3800 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3801 ADD_INDEX_LOG(my_idx); /* for debug */
3802
3803 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3804 pScsiReq->TargetID = io->physDiskNum;
3805 pScsiReq->Bus = 0;
3806 pScsiReq->ChainOffset = 0;
3807 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3808 } else {
3809 pScsiReq->TargetID = io->id;
3810 pScsiReq->Bus = io->bus;
3811 pScsiReq->ChainOffset = 0;
3812 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3813 }
3814
3815 pScsiReq->CDBLength = cmdLen;
3816 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3817
3818 pScsiReq->Reserved = 0;
3819
3820 pScsiReq->MsgFlags = mpt_msg_flags();
3821 /* MsgContext set in mpt_get_msg_fram call */
3822
3823 for (ii=0; ii < 8; ii++)
3824 pScsiReq->LUN[ii] = 0;
3825 pScsiReq->LUN[1] = io->lun;
3826
3827 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3828 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3829 else
3830 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3831
3832 if (cmd == REQUEST_SENSE) {
3833 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3834 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3835 hd->ioc->name, cmd));
3836 }
3837
3838 for (ii=0; ii < 16; ii++)
3839 pScsiReq->CDB[ii] = CDB[ii];
3840
3841 pScsiReq->DataLength = cpu_to_le32(io->size);
3842 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3843 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3844
3845 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3846 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3847
3848 if (dir == MPI_SCSIIO_CONTROL_READ) {
3849 mpt_add_sge((char *) &pScsiReq->SGL,
3850 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3851 io->data_dma);
3852 } else {
3853 mpt_add_sge((char *) &pScsiReq->SGL,
3854 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3855 io->data_dma);
3856 }
3857
3858 /* The ISR will free the request frame, but we need
3859 * the information to initialize the target. Duplicate.
3860 */
3861 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3862
3863 /* Issue this command after:
3864 * finish init
3865 * add timer
3866 * Wait until the reply has been received
3867 * ScsiScanDvCtx callback function will
3868 * set hd->pLocal;
3869 * set scandv_wait_done and call wake_up
3870 */
3871 hd->pLocal = NULL;
3872 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003873 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874
3875 /* Save cmd pointer, for resource free if timeout or
3876 * FW reload occurs
3877 */
3878 hd->cmdPtr = mf;
3879
3880 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003881 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3882 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
3884 if (hd->pLocal) {
3885 rc = hd->pLocal->completion;
3886 hd->pLocal->skip = 0;
3887
3888 /* Always set fatal error codes in some cases.
3889 */
3890 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3891 rc = -ENXIO;
3892 else if (rc == MPT_SCANDV_SOME_ERROR)
3893 rc = -rc;
3894 } else {
3895 rc = -EFAULT;
3896 /* This should never happen. */
3897 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3898 hd->ioc->name));
3899 }
3900
3901 return rc;
3902}
3903
3904/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3905/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003906 * mptscsih_negotiate_to_asyn_narrow - Restore devices to default state
3907 * @hd: Pointer to a SCSI HOST structure
3908 * @vtarget: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 *
3910 * Uses the ISR, but with special processing.
3911 * MUST be single-threaded.
3912 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003914static void
Moore, Erica69ac322006-01-17 17:06:26 -07003915mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916{
Moore, Erica69ac322006-01-17 17:06:26 -07003917 VirtTarget *vtarget = vdevice->vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 MPT_ADAPTER *ioc= hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003919 SCSIDevicePage1_t *pcfg1Data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 CONFIGPARMS cfg;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003921 dma_addr_t cfg1_dma_addr;
3922 ConfigPageHeader_t header;
3923 int id;
3924 int requested, configuration, data,i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 u8 flags, factor;
3926
Moore, Erica69ac322006-01-17 17:06:26 -07003927 if ((ioc->bus_type != SPI) ||
3928 (!vdevice->configured_lun))
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003929 return;
3930
3931 if (!ioc->spi_data.sdp1length)
3932 return;
3933
3934 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3935 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3936
3937 if (pcfg1Data == NULL)
3938 return;
3939
3940 header.PageVersion = ioc->spi_data.sdp1version;
3941 header.PageLength = ioc->spi_data.sdp1length;
3942 header.PageNumber = 1;
3943 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3944 cfg.cfghdr.hdr = &header;
3945 cfg.physAddr = cfg1_dma_addr;
3946 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3947 cfg.dir = 1;
3948 cfg.timeout = 0;
3949
3950 if (vtarget->raidVolume && ioc->raid_data.pIocPg3) {
3951 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3952 id = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID;
3953 flags = hd->ioc->spi_data.noQas;
3954 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3955 data = hd->ioc->spi_data.nvram[id];
3956 if (data & MPT_NVRAM_WIDE_DISABLE)
3957 flags |= MPT_TARGET_NO_NEGO_WIDE;
3958 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
3959 if ((factor == 0) || (factor == MPT_ASYNC))
3960 flags |= MPT_TARGET_NO_NEGO_SYNC;
3961 }
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 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) | id;
3971 mpt_config(hd->ioc, &cfg);
3972 }
3973 } else {
3974 flags = vtarget->negoFlags;
3975 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3976 &configuration, flags);
Moore, Erica69ac322006-01-17 17:06:26 -07003977 dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003978 "offset=0 negoFlags=%x request=%x config=%x\n",
3979 vtarget->target_id, flags, requested, configuration));
3980 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3981 pcfg1Data->Reserved = 0;
3982 pcfg1Data->Configuration = cpu_to_le32(configuration);
3983 cfg.pageAddr = (vtarget->bus_id<<8) | vtarget->target_id;
3984 mpt_config(hd->ioc, &cfg);
3985 }
3986
3987 if (pcfg1Data)
3988 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr);
3989}
3990
3991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3992/**
3993 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3994 * @hd: Pointer to a SCSI HOST structure
3995 * @vtarget: per device private data
3996 * @lun: lun
3997 *
3998 * Uses the ISR, but with special processing.
3999 * MUST be single-threaded.
4000 *
4001 */
4002static void
4003mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
4004{
4005 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006
4007 /* Following parameters will not change
4008 * in this routine.
4009 */
4010 iocmd.cmd = SYNCHRONIZE_CACHE;
4011 iocmd.flags = 0;
4012 iocmd.physDiskNum = -1;
4013 iocmd.data = NULL;
4014 iocmd.data_dma = -1;
4015 iocmd.size = 0;
4016 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004017 iocmd.bus = vdevice->bus_id;
4018 iocmd.id = vdevice->target_id;
4019 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004021 if ((vdevice->vtarget->type & TYPE_DISK) &&
4022 (vdevice->configured_lun))
4023 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024}
4025
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07004026/* Search IOC page 3 to determine if this is hidden physical disk
4027 */
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07004028static int
4029mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
4030{
4031 int i;
4032
4033 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
4034 return 0;
4035
4036 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
4037 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
4038 return 1;
4039 }
4040
4041 return 0;
4042}
4043
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
4045/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4046/**
4047 * mptscsih_domainValidation - Top level handler for domain validation.
4048 * @hd: Pointer to MPT_SCSI_HOST structure.
4049 *
4050 * Uses the ISR, but with special processing.
4051 * Called from schedule, should not be in interrupt mode.
4052 * While thread alive, do dv for all devices needing dv
4053 *
4054 * Return: None.
4055 */
4056static void
4057mptscsih_domainValidation(void *arg)
4058{
4059 MPT_SCSI_HOST *hd;
4060 MPT_ADAPTER *ioc;
4061 unsigned long flags;
4062 int id, maxid, dvStatus, did;
4063 int ii, isPhysDisk;
4064
4065 spin_lock_irqsave(&dvtaskQ_lock, flags);
4066 dvtaskQ_active = 1;
4067 if (dvtaskQ_release) {
4068 dvtaskQ_active = 0;
4069 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4070 return;
4071 }
4072 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4073
4074 /* For this ioc, loop through all devices and do dv to each device.
4075 * When complete with this ioc, search through the ioc list, and
4076 * for each scsi ioc found, do dv for all devices. Exit when no
4077 * device needs dv.
4078 */
4079 did = 1;
4080 while (did) {
4081 did = 0;
4082 list_for_each_entry(ioc, &ioc_list, list) {
4083 spin_lock_irqsave(&dvtaskQ_lock, flags);
4084 if (dvtaskQ_release) {
4085 dvtaskQ_active = 0;
4086 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4087 return;
4088 }
4089 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4090
4091 msleep(250);
4092
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004093 /* DV only to SPI adapters */
4094 if (ioc->bus_type != SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 continue;
4096
4097 /* Make sure everything looks ok */
4098 if (ioc->sh == NULL)
4099 continue;
4100
4101 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4102 if (hd == NULL)
4103 continue;
4104
4105 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4106 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004107 if (ioc->raid_data.pIocPg3) {
4108 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4109 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
4111 while (numPDisk) {
4112 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4113 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4114
4115 pPDisk++;
4116 numPDisk--;
4117 }
4118 }
4119 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4120 }
4121
4122 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4123
4124 for (id = 0; id < maxid; id++) {
4125 spin_lock_irqsave(&dvtaskQ_lock, flags);
4126 if (dvtaskQ_release) {
4127 dvtaskQ_active = 0;
4128 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4129 return;
4130 }
4131 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4132 dvStatus = hd->ioc->spi_data.dvStatus[id];
4133
4134 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4135 did++;
4136 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4137 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4138
4139 msleep(250);
4140
4141 /* If hidden phys disk, block IO's to all
4142 * raid volumes
4143 * else, process normally
4144 */
4145 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4146 if (isPhysDisk) {
4147 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004148 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4150 }
4151 }
4152 }
4153
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004154 if(mpt_alt_ioc_wait(hd->ioc)!=0) {
4155 ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
4156 hd->ioc->name));
4157 continue;
4158 }
4159
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 if (mptscsih_doDv(hd, 0, id) == 1) {
4161 /* Untagged device was busy, try again
4162 */
4163 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4164 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4165 } else {
4166 /* DV is complete. Clear flags.
4167 */
4168 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4169 }
4170
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004171 spin_lock(&hd->ioc->initializing_hba_lock);
4172 hd->ioc->initializing_hba_lock_flag=0;
4173 spin_unlock(&hd->ioc->initializing_hba_lock);
4174
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 if (isPhysDisk) {
4176 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004177 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4179 }
4180 }
4181 }
4182
4183 if (hd->ioc->spi_data.noQas)
4184 mptscsih_qas_check(hd, id);
4185 }
4186 }
4187 }
4188 }
4189
4190 spin_lock_irqsave(&dvtaskQ_lock, flags);
4191 dvtaskQ_active = 0;
4192 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4193
4194 return;
4195}
4196
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197/* Write SDP1 if no QAS has been enabled
4198 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004199static void
4200mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004202 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 int ii;
4204
4205 if (hd->Targets == NULL)
4206 return;
4207
4208 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4209 if (ii == id)
4210 continue;
4211
4212 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4213 continue;
4214
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004215 vtarget = hd->Targets[ii];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004217 if ((vtarget != NULL) && (!vtarget->raidVolume)) {
4218 if ((vtarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4219 vtarget->negoFlags |= hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4221 mptscsih_writeSDP1(hd, 0, ii, 0);
4222 }
4223 } else {
4224 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4225 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4226 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4227 }
4228 }
4229 }
4230 return;
4231}
4232
4233
4234
4235#define MPT_GET_NVRAM_VALS 0x01
4236#define MPT_UPDATE_MAX 0x02
4237#define MPT_SET_MAX 0x04
4238#define MPT_SET_MIN 0x08
4239#define MPT_FALLBACK 0x10
4240#define MPT_SAVE 0x20
4241
4242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4243/**
4244 * mptscsih_doDv - Perform domain validation to a target.
4245 * @hd: Pointer to MPT_SCSI_HOST structure.
4246 * @portnum: IOC port number.
4247 * @target: Physical ID of this target
4248 *
4249 * Uses the ISR, but with special processing.
4250 * MUST be single-threaded.
4251 * Test will exit if target is at async & narrow.
4252 *
4253 * Return: None.
4254 */
4255static int
4256mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4257{
4258 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004259 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 SCSIDevicePage1_t *pcfg1Data;
4261 SCSIDevicePage0_t *pcfg0Data;
4262 u8 *pbuf1;
4263 u8 *pbuf2;
4264 u8 *pDvBuf;
4265 dma_addr_t dvbuf_dma = -1;
4266 dma_addr_t buf1_dma = -1;
4267 dma_addr_t buf2_dma = -1;
4268 dma_addr_t cfg1_dma_addr = -1;
4269 dma_addr_t cfg0_dma_addr = -1;
4270 ConfigPageHeader_t header1;
4271 ConfigPageHeader_t header0;
4272 DVPARAMETERS dv;
4273 INTERNAL_CMD iocmd;
4274 CONFIGPARMS cfg;
4275 int dv_alloc = 0;
4276 int rc, sz = 0;
4277 int bufsize = 0;
4278 int dataBufSize = 0;
4279 int echoBufSize = 0;
4280 int notDone;
4281 int patt;
4282 int repeat;
4283 int retcode = 0;
4284 int nfactor = MPT_ULTRA320;
4285 char firstPass = 1;
4286 char doFallback = 0;
4287 char readPage0;
4288 char bus, lun;
4289 char inq0 = 0;
4290
4291 if (ioc->spi_data.sdp1length == 0)
4292 return 0;
4293
4294 if (ioc->spi_data.sdp0length == 0)
4295 return 0;
4296
4297 /* If multiple buses are used, require that the initiator
4298 * id be the same on all buses.
4299 */
4300 if (id == ioc->pfacts[0].PortSCSIID)
4301 return 0;
4302
4303 lun = 0;
4304 bus = (u8) bus_number;
4305 ddvtprintk((MYIOC_s_NOTE_FMT
4306 "DV started: bus=%d, id=%d dv @ %p\n",
4307 ioc->name, bus, id, &dv));
4308
4309 /* Prep DV structure
4310 */
4311 memset (&dv, 0, sizeof(DVPARAMETERS));
4312 dv.id = id;
4313
4314 /* Populate tmax with the current maximum
4315 * transfer parameters for this target.
4316 * Exit if narrow and async.
4317 */
4318 dv.cmd = MPT_GET_NVRAM_VALS;
4319 mptscsih_dv_parms(hd, &dv, NULL);
4320
4321 /* Prep SCSI IO structure
4322 */
4323 iocmd.id = id;
4324 iocmd.bus = bus;
4325 iocmd.lun = lun;
4326 iocmd.flags = 0;
4327 iocmd.physDiskNum = -1;
4328 iocmd.rsvd = iocmd.rsvd2 = 0;
4329
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004330 vtarget = hd->Targets[id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331
4332 /* Use tagged commands if possible.
4333 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004334 if (vtarget) {
4335 if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4337 else {
4338 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4339 return 0;
4340
4341 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4342 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4343 return 0;
4344 }
4345 }
4346
4347 /* Prep cfg structure
4348 */
4349 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004350 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
4352 /* Prep SDP0 header
4353 */
4354 header0.PageVersion = ioc->spi_data.sdp0version;
4355 header0.PageLength = ioc->spi_data.sdp0length;
4356 header0.PageNumber = 0;
4357 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4358
4359 /* Prep SDP1 header
4360 */
4361 header1.PageVersion = ioc->spi_data.sdp1version;
4362 header1.PageLength = ioc->spi_data.sdp1length;
4363 header1.PageNumber = 1;
4364 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4365
4366 if (header0.PageLength & 1)
4367 dv_alloc = (header0.PageLength * 4) + 4;
4368
4369 dv_alloc += (2048 + (header1.PageLength * 4));
4370
4371 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4372 if (pDvBuf == NULL)
4373 return 0;
4374
4375 sz = 0;
4376 pbuf1 = (u8 *)pDvBuf;
4377 buf1_dma = dvbuf_dma;
4378 sz +=1024;
4379
4380 pbuf2 = (u8 *) (pDvBuf + sz);
4381 buf2_dma = dvbuf_dma + sz;
4382 sz +=1024;
4383
4384 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4385 cfg0_dma_addr = dvbuf_dma + sz;
4386 sz += header0.PageLength * 4;
4387
4388 /* 8-byte alignment
4389 */
4390 if (header0.PageLength & 1)
4391 sz += 4;
4392
4393 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4394 cfg1_dma_addr = dvbuf_dma + sz;
4395
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004396 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 */
4398 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004399 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4401 /* Set the factor from nvram */
4402 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4403 if (nfactor < pspi_data->minSyncFactor )
4404 nfactor = pspi_data->minSyncFactor;
4405
4406 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4407 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4408
4409 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4410 ioc->name, bus, id, lun));
4411
4412 dv.cmd = MPT_SET_MAX;
4413 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004414 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
4416 /* Save the final negotiated settings to
4417 * SCSI device page 1.
4418 */
4419 cfg.physAddr = cfg1_dma_addr;
4420 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4421 cfg.dir = 1;
4422 mpt_config(hd->ioc, &cfg);
4423 goto target_done;
4424 }
4425 }
4426 }
4427
4428 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004429 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 /* Search IOC page 3 for matching id
4431 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004432 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4433 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
4435 while (numPDisk) {
4436 if (pPDisk->PhysDiskID == id) {
4437 /* match */
4438 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4439 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4440
4441 /* Quiesce the IM
4442 */
4443 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4444 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4445 goto target_done;
4446 }
4447 break;
4448 }
4449 pPDisk++;
4450 numPDisk--;
4451 }
4452 }
4453
4454 /* RAID Volume ID's may double for a physical device. If RAID but
4455 * not a physical ID as well, skip DV.
4456 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004457 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 goto target_done;
4459
4460
4461 /* Basic Test.
4462 * Async & Narrow - Inquiry
4463 * Async & Narrow - Inquiry
4464 * Maximum transfer rate - Inquiry
4465 * Compare buffers:
4466 * If compare, test complete.
4467 * If miscompare and first pass, repeat
4468 * If miscompare and not first pass, fall back and repeat
4469 */
4470 hd->pLocal = NULL;
4471 readPage0 = 0;
4472 sz = SCSI_MAX_INQUIRY_BYTES;
4473 rc = MPT_SCANDV_GOOD;
4474 while (1) {
4475 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4476 retcode = 0;
4477 dv.cmd = MPT_SET_MIN;
4478 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4479
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004480 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 cfg.physAddr = cfg1_dma_addr;
4482 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4483 cfg.dir = 1;
4484 if (mpt_config(hd->ioc, &cfg) != 0)
4485 goto target_done;
4486
4487 /* Wide - narrow - wide workaround case
4488 */
4489 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4490 /* Send an untagged command to reset disk Qs corrupted
4491 * when a parity error occurs on a Request Sense.
4492 */
4493 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4494 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4495 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4496
4497 iocmd.cmd = REQUEST_SENSE;
4498 iocmd.data_dma = buf1_dma;
4499 iocmd.data = pbuf1;
4500 iocmd.size = 0x12;
4501 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4502 goto target_done;
4503 else {
4504 if (hd->pLocal == NULL)
4505 goto target_done;
4506 rc = hd->pLocal->completion;
4507 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4508 dv.max.width = 0;
4509 doFallback = 0;
4510 } else
4511 goto target_done;
4512 }
4513 } else
4514 goto target_done;
4515 }
4516
4517 iocmd.cmd = INQUIRY;
4518 iocmd.data_dma = buf1_dma;
4519 iocmd.data = pbuf1;
4520 iocmd.size = sz;
4521 memset(pbuf1, 0x00, sz);
4522 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4523 goto target_done;
4524 else {
4525 if (hd->pLocal == NULL)
4526 goto target_done;
4527 rc = hd->pLocal->completion;
4528 if (rc == MPT_SCANDV_GOOD) {
4529 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4530 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4531 retcode = 1;
4532 else
4533 retcode = 0;
4534
4535 goto target_done;
4536 }
4537 } else if (rc == MPT_SCANDV_SENSE) {
4538 ;
4539 } else {
4540 /* If first command doesn't complete
4541 * with a good status or with a check condition,
4542 * exit.
4543 */
4544 goto target_done;
4545 }
4546 }
4547
4548 /* Reset the size for disks
4549 */
4550 inq0 = (*pbuf1) & 0x1F;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004551 if ((inq0 == 0) && vtarget && !vtarget->raidVolume) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 sz = 0x40;
4553 iocmd.size = sz;
4554 }
4555
4556 /* Another GEM workaround. Check peripheral device type,
4557 * if PROCESSOR, quit DV.
4558 */
4559 if (inq0 == TYPE_PROCESSOR) {
4560 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004561 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 lun,
4563 pbuf1,
4564 sz);
4565 goto target_done;
4566 }
4567
4568 if (inq0 > 0x08)
4569 goto target_done;
4570
4571 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4572 goto target_done;
4573
4574 if (sz == 0x40) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004575 if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A)
4576 && (vtarget->minSyncFactor > 0x09)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 if ((pbuf1[56] & 0x04) == 0)
4578 ;
4579 else if ((pbuf1[56] & 0x01) == 1) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004580 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4582 } else {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004583 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4585 }
4586
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004587 dv.max.factor = vtarget->minSyncFactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
4589 if ((pbuf1[56] & 0x02) == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004590 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004592 ddvprintk((MYIOC_s_NOTE_FMT
4593 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 ioc->name, id, pbuf1[56]));
4595 }
4596 }
4597 }
4598
4599 if (doFallback)
4600 dv.cmd = MPT_FALLBACK;
4601 else
4602 dv.cmd = MPT_SET_MAX;
4603
4604 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4605 if (mpt_config(hd->ioc, &cfg) != 0)
4606 goto target_done;
4607
4608 if ((!dv.now.width) && (!dv.now.offset))
4609 goto target_done;
4610
4611 iocmd.cmd = INQUIRY;
4612 iocmd.data_dma = buf2_dma;
4613 iocmd.data = pbuf2;
4614 iocmd.size = sz;
4615 memset(pbuf2, 0x00, sz);
4616 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4617 goto target_done;
4618 else if (hd->pLocal == NULL)
4619 goto target_done;
4620 else {
4621 /* Save the return code.
4622 * If this is the first pass,
4623 * read SCSI Device Page 0
4624 * and update the target max parameters.
4625 */
4626 rc = hd->pLocal->completion;
4627 doFallback = 0;
4628 if (rc == MPT_SCANDV_GOOD) {
4629 if (!readPage0) {
4630 u32 sdp0_info;
4631 u32 sdp0_nego;
4632
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004633 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 cfg.physAddr = cfg0_dma_addr;
4635 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4636 cfg.dir = 0;
4637
4638 if (mpt_config(hd->ioc, &cfg) != 0)
4639 goto target_done;
4640
4641 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4642 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4643
4644 /* Quantum and Fujitsu workarounds.
4645 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4646 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4647 * Resetart with a request for U160.
4648 */
4649 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4650 doFallback = 1;
4651 } else {
4652 dv.cmd = MPT_UPDATE_MAX;
4653 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4654 /* Update the SCSI device page 1 area
4655 */
4656 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4657 readPage0 = 1;
4658 }
4659 }
4660
4661 /* Quantum workaround. Restart this test will the fallback
4662 * flag set.
4663 */
4664 if (doFallback == 0) {
4665 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4666 if (!firstPass)
4667 doFallback = 1;
4668 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004669 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4671 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4672 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004673 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 lun,
4675 pbuf1,
4676 sz);
4677 break; /* test complete */
4678 }
4679 }
4680
4681
4682 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4683 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004684 else if ((rc == MPT_SCANDV_DID_RESET) ||
4685 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 (rc == MPT_SCANDV_FALLBACK))
4687 doFallback = 1; /* set fallback flag */
4688 else
4689 goto target_done;
4690
4691 firstPass = 0;
4692 }
4693 }
4694 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4695
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004696 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 goto target_done;
4698
4699 inq0 = (*pbuf1) & 0x1F;
4700
4701 /* Continue only for disks
4702 */
4703 if (inq0 != 0)
4704 goto target_done;
4705
4706 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4707 goto target_done;
4708
4709 /* Start the Enhanced Test.
4710 * 0) issue TUR to clear out check conditions
4711 * 1) read capacity of echo (regular) buffer
4712 * 2) reserve device
4713 * 3) do write-read-compare data pattern test
4714 * 4) release
4715 * 5) update nego parms to target struct
4716 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004717 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 cfg.physAddr = cfg1_dma_addr;
4719 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4720 cfg.dir = 1;
4721
4722 iocmd.cmd = TEST_UNIT_READY;
4723 iocmd.data_dma = -1;
4724 iocmd.data = NULL;
4725 iocmd.size = 0;
4726 notDone = 1;
4727 while (notDone) {
4728 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4729 goto target_done;
4730
4731 if (hd->pLocal == NULL)
4732 goto target_done;
4733
4734 rc = hd->pLocal->completion;
4735 if (rc == MPT_SCANDV_GOOD)
4736 notDone = 0;
4737 else if (rc == MPT_SCANDV_SENSE) {
4738 u8 skey = hd->pLocal->sense[2] & 0x0F;
4739 u8 asc = hd->pLocal->sense[12];
4740 u8 ascq = hd->pLocal->sense[13];
4741 ddvprintk((MYIOC_s_INFO_FMT
4742 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4743 ioc->name, skey, asc, ascq));
4744
4745 if (skey == UNIT_ATTENTION)
4746 notDone++; /* repeat */
4747 else if ((skey == NOT_READY) &&
4748 (asc == 0x04)&&(ascq == 0x01)) {
4749 /* wait then repeat */
4750 mdelay (2000);
4751 notDone++;
4752 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4753 /* no medium, try read test anyway */
4754 notDone = 0;
4755 } else {
4756 /* All other errors are fatal.
4757 */
4758 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4759 ioc->name));
4760 goto target_done;
4761 }
4762 } else
4763 goto target_done;
4764 }
4765
4766 iocmd.cmd = READ_BUFFER;
4767 iocmd.data_dma = buf1_dma;
4768 iocmd.data = pbuf1;
4769 iocmd.size = 4;
4770 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4771
4772 dataBufSize = 0;
4773 echoBufSize = 0;
4774 for (patt = 0; patt < 2; patt++) {
4775 if (patt == 0)
4776 iocmd.flags |= MPT_ICFLAG_ECHO;
4777 else
4778 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4779
4780 notDone = 1;
4781 while (notDone) {
4782 bufsize = 0;
4783
4784 /* If not ready after 8 trials,
4785 * give up on this device.
4786 */
4787 if (notDone > 8)
4788 goto target_done;
4789
4790 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4791 goto target_done;
4792 else if (hd->pLocal == NULL)
4793 goto target_done;
4794 else {
4795 rc = hd->pLocal->completion;
4796 ddvprintk(("ReadBuffer Comp Code %d", rc));
4797 ddvprintk((" buff: %0x %0x %0x %0x\n",
4798 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4799
4800 if (rc == MPT_SCANDV_GOOD) {
4801 notDone = 0;
4802 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4803 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004804 if (pbuf1[0] & 0x01)
4805 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 } else {
4807 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4808 }
4809 } else if (rc == MPT_SCANDV_SENSE) {
4810 u8 skey = hd->pLocal->sense[2] & 0x0F;
4811 u8 asc = hd->pLocal->sense[12];
4812 u8 ascq = hd->pLocal->sense[13];
4813 ddvprintk((MYIOC_s_INFO_FMT
4814 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4815 ioc->name, skey, asc, ascq));
4816 if (skey == ILLEGAL_REQUEST) {
4817 notDone = 0;
4818 } else if (skey == UNIT_ATTENTION) {
4819 notDone++; /* repeat */
4820 } else if ((skey == NOT_READY) &&
4821 (asc == 0x04)&&(ascq == 0x01)) {
4822 /* wait then repeat */
4823 mdelay (2000);
4824 notDone++;
4825 } else {
4826 /* All other errors are fatal.
4827 */
4828 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4829 ioc->name));
4830 goto target_done;
4831 }
4832 } else {
4833 /* All other errors are fatal
4834 */
4835 goto target_done;
4836 }
4837 }
4838 }
4839
4840 if (iocmd.flags & MPT_ICFLAG_ECHO)
4841 echoBufSize = bufsize;
4842 else
4843 dataBufSize = bufsize;
4844 }
4845 sz = 0;
4846 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4847
4848 /* Use echo buffers if possible,
4849 * Exit if both buffers are 0.
4850 */
4851 if (echoBufSize > 0) {
4852 iocmd.flags |= MPT_ICFLAG_ECHO;
4853 if (dataBufSize > 0)
4854 bufsize = min(echoBufSize, dataBufSize);
4855 else
4856 bufsize = echoBufSize;
4857 } else if (dataBufSize == 0)
4858 goto target_done;
4859
4860 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4861 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4862
4863 /* Data buffers for write-read-compare test max 1K.
4864 */
4865 sz = min(bufsize, 1024);
4866
4867 /* --- loop ----
4868 * On first pass, always issue a reserve.
4869 * On additional loops, only if a reset has occurred.
4870 * iocmd.flags indicates if echo or regular buffer
4871 */
4872 for (patt = 0; patt < 4; patt++) {
4873 ddvprintk(("Pattern %d\n", patt));
4874 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4875 iocmd.cmd = TEST_UNIT_READY;
4876 iocmd.data_dma = -1;
4877 iocmd.data = NULL;
4878 iocmd.size = 0;
4879 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4880 goto target_done;
4881
4882 iocmd.cmd = RELEASE;
4883 iocmd.data_dma = -1;
4884 iocmd.data = NULL;
4885 iocmd.size = 0;
4886 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4887 goto target_done;
4888 else if (hd->pLocal == NULL)
4889 goto target_done;
4890 else {
4891 rc = hd->pLocal->completion;
4892 ddvprintk(("Release rc %d\n", rc));
4893 if (rc == MPT_SCANDV_GOOD)
4894 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4895 else
4896 goto target_done;
4897 }
4898 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4899 }
4900 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4901
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004902 if (iocmd.flags & MPT_ICFLAG_EBOS)
4903 goto skip_Reserve;
4904
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 repeat = 5;
4906 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4907 iocmd.cmd = RESERVE;
4908 iocmd.data_dma = -1;
4909 iocmd.data = NULL;
4910 iocmd.size = 0;
4911 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4912 goto target_done;
4913 else if (hd->pLocal == NULL)
4914 goto target_done;
4915 else {
4916 rc = hd->pLocal->completion;
4917 if (rc == MPT_SCANDV_GOOD) {
4918 iocmd.flags |= MPT_ICFLAG_RESERVED;
4919 } else if (rc == MPT_SCANDV_SENSE) {
4920 /* Wait if coming ready
4921 */
4922 u8 skey = hd->pLocal->sense[2] & 0x0F;
4923 u8 asc = hd->pLocal->sense[12];
4924 u8 ascq = hd->pLocal->sense[13];
4925 ddvprintk((MYIOC_s_INFO_FMT
4926 "DV: Reserve Failed: ", ioc->name));
4927 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4928 skey, asc, ascq));
4929
4930 if ((skey == NOT_READY) && (asc == 0x04)&&
4931 (ascq == 0x01)) {
4932 /* wait then repeat */
4933 mdelay (2000);
4934 notDone++;
4935 } else {
4936 ddvprintk((MYIOC_s_INFO_FMT
4937 "DV: Reserved Failed.", ioc->name));
4938 goto target_done;
4939 }
4940 } else {
4941 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4942 ioc->name));
4943 goto target_done;
4944 }
4945 }
4946 }
4947
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004948skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4950 iocmd.cmd = WRITE_BUFFER;
4951 iocmd.data_dma = buf1_dma;
4952 iocmd.data = pbuf1;
4953 iocmd.size = sz;
4954 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4955 goto target_done;
4956 else if (hd->pLocal == NULL)
4957 goto target_done;
4958 else {
4959 rc = hd->pLocal->completion;
4960 if (rc == MPT_SCANDV_GOOD)
4961 ; /* Issue read buffer */
4962 else if (rc == MPT_SCANDV_DID_RESET) {
4963 /* If using echo buffers, reset to data buffers.
4964 * Else do Fallback and restart
4965 * this test (re-issue reserve
4966 * because of bus reset).
4967 */
4968 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4969 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4970 } else {
4971 dv.cmd = MPT_FALLBACK;
4972 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4973
4974 if (mpt_config(hd->ioc, &cfg) != 0)
4975 goto target_done;
4976
4977 if ((!dv.now.width) && (!dv.now.offset))
4978 goto target_done;
4979 }
4980
4981 iocmd.flags |= MPT_ICFLAG_DID_RESET;
4982 patt = -1;
4983 continue;
4984 } else if (rc == MPT_SCANDV_SENSE) {
4985 /* Restart data test if UA, else quit.
4986 */
4987 u8 skey = hd->pLocal->sense[2] & 0x0F;
4988 ddvprintk((MYIOC_s_INFO_FMT
4989 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
4990 hd->pLocal->sense[12], hd->pLocal->sense[13]));
4991 if (skey == UNIT_ATTENTION) {
4992 patt = -1;
4993 continue;
4994 } else if (skey == ILLEGAL_REQUEST) {
4995 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4996 if (dataBufSize >= bufsize) {
4997 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4998 patt = -1;
4999 continue;
5000 }
5001 }
5002 goto target_done;
5003 }
5004 else
5005 goto target_done;
5006 } else {
5007 /* fatal error */
5008 goto target_done;
5009 }
5010 }
5011
5012 iocmd.cmd = READ_BUFFER;
5013 iocmd.data_dma = buf2_dma;
5014 iocmd.data = pbuf2;
5015 iocmd.size = sz;
5016 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5017 goto target_done;
5018 else if (hd->pLocal == NULL)
5019 goto target_done;
5020 else {
5021 rc = hd->pLocal->completion;
5022 if (rc == MPT_SCANDV_GOOD) {
5023 /* If buffers compare,
5024 * go to next pattern,
5025 * else, do a fallback and restart
5026 * data transfer test.
5027 */
5028 if (memcmp (pbuf1, pbuf2, sz) == 0) {
5029 ; /* goto next pattern */
5030 } else {
5031 /* Miscompare with Echo buffer, go to data buffer,
5032 * if that buffer exists.
5033 * Miscompare with Data buffer, check first 4 bytes,
5034 * some devices return capacity. Exit in this case.
5035 */
5036 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5037 if (dataBufSize >= bufsize)
5038 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5039 else
5040 goto target_done;
5041 } else {
5042 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
5043 /* Argh. Device returning wrong data.
5044 * Quit DV for this device.
5045 */
5046 goto target_done;
5047 }
5048
5049 /* Had an actual miscompare. Slow down.*/
5050 dv.cmd = MPT_FALLBACK;
5051 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5052
5053 if (mpt_config(hd->ioc, &cfg) != 0)
5054 goto target_done;
5055
5056 if ((!dv.now.width) && (!dv.now.offset))
5057 goto target_done;
5058 }
5059
5060 patt = -1;
5061 continue;
5062 }
5063 } else if (rc == MPT_SCANDV_DID_RESET) {
5064 /* Do Fallback and restart
5065 * this test (re-issue reserve
5066 * because of bus reset).
5067 */
5068 dv.cmd = MPT_FALLBACK;
5069 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5070
5071 if (mpt_config(hd->ioc, &cfg) != 0)
5072 goto target_done;
5073
5074 if ((!dv.now.width) && (!dv.now.offset))
5075 goto target_done;
5076
5077 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5078 patt = -1;
5079 continue;
5080 } else if (rc == MPT_SCANDV_SENSE) {
5081 /* Restart data test if UA, else quit.
5082 */
5083 u8 skey = hd->pLocal->sense[2] & 0x0F;
5084 ddvprintk((MYIOC_s_INFO_FMT
5085 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5086 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5087 if (skey == UNIT_ATTENTION) {
5088 patt = -1;
5089 continue;
5090 }
5091 else
5092 goto target_done;
5093 } else {
5094 /* fatal error */
5095 goto target_done;
5096 }
5097 }
5098
5099 } /* --- end of patt loop ---- */
5100
5101target_done:
5102 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5103 iocmd.cmd = RELEASE;
5104 iocmd.data_dma = -1;
5105 iocmd.data = NULL;
5106 iocmd.size = 0;
5107 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5108 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5109 ioc->name, id);
5110 else if (hd->pLocal) {
5111 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5112 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5113 } else {
5114 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5115 ioc->name, id);
5116 }
5117 }
5118
5119
5120 /* Set if cfg1_dma_addr contents is valid
5121 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005122 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 /* If disk, not U320, disable QAS
5124 */
5125 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5126 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005127 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5129 }
5130
5131 dv.cmd = MPT_SAVE;
5132 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5133
5134 /* Double writes to SDP1 can cause problems,
5135 * skip save of the final negotiated settings to
5136 * SCSI device page 1.
5137 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005138 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 cfg.physAddr = cfg1_dma_addr;
5140 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5141 cfg.dir = 1;
5142 mpt_config(hd->ioc, &cfg);
5143 */
5144 }
5145
5146 /* If this is a RAID Passthrough, enable internal IOs
5147 */
5148 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5149 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5150 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5151 }
5152
5153 /* Done with the DV scan of the current target
5154 */
5155 if (pDvBuf)
5156 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5157
5158 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5159 ioc->name, id));
5160
5161 return retcode;
5162}
5163
5164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5165/* mptscsih_dv_parms - perform a variety of operations on the
5166 * parameters used for negotiation.
5167 * @hd: Pointer to a SCSI host.
5168 * @dv: Pointer to a structure that contains the maximum and current
5169 * negotiated parameters.
5170 */
5171static void
5172mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5173{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005174 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 SCSIDevicePage0_t *pPage0;
5176 SCSIDevicePage1_t *pPage1;
5177 int val = 0, data, configuration;
5178 u8 width = 0;
5179 u8 offset = 0;
5180 u8 factor = 0;
5181 u8 negoFlags = 0;
5182 u8 cmd = dv->cmd;
5183 u8 id = dv->id;
5184
5185 switch (cmd) {
5186 case MPT_GET_NVRAM_VALS:
5187 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5188 hd->ioc->name));
5189 /* Get the NVRAM values and save in tmax
5190 * If not an LVD bus, the adapter minSyncFactor has been
5191 * already throttled back.
5192 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005193 negoFlags = hd->ioc->spi_data.noQas;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005194 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume) {
5195 width = vtarget->maxWidth;
5196 offset = vtarget->maxOffset;
5197 factor = vtarget->minSyncFactor;
5198 negoFlags |= vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 } else {
5200 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5201 data = hd->ioc->spi_data.nvram[id];
5202 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5203 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5204 factor = MPT_ASYNC;
5205 else {
5206 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5207 if ((factor == 0) || (factor == MPT_ASYNC)){
5208 factor = MPT_ASYNC;
5209 offset = 0;
5210 }
5211 }
5212 } else {
5213 width = MPT_NARROW;
5214 offset = 0;
5215 factor = MPT_ASYNC;
5216 }
5217
5218 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 if (!width)
5220 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5221
5222 if (!offset)
5223 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5224 }
5225
5226 /* limit by adapter capabilities */
5227 width = min(width, hd->ioc->spi_data.maxBusWidth);
5228 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5229 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5230
5231 /* Check Consistency */
5232 if (offset && (factor < MPT_ULTRA2) && !width)
5233 factor = MPT_ULTRA2;
5234
5235 dv->max.width = width;
5236 dv->max.offset = offset;
5237 dv->max.factor = factor;
5238 dv->max.flags = negoFlags;
5239 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5240 id, width, factor, offset, negoFlags));
5241 break;
5242
5243 case MPT_UPDATE_MAX:
5244 ddvprintk((MYIOC_s_NOTE_FMT
5245 "Updating with SDP0 Data: ", hd->ioc->name));
5246 /* Update tmax values with those from Device Page 0.*/
5247 pPage0 = (SCSIDevicePage0_t *) pPage;
5248 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005249 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5251 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5252 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5253 }
5254
5255 dv->now.width = dv->max.width;
5256 dv->now.offset = dv->max.offset;
5257 dv->now.factor = dv->max.factor;
5258 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5259 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5260 break;
5261
5262 case MPT_SET_MAX:
5263 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5264 hd->ioc->name));
5265 /* Set current to the max values. Update the config page.*/
5266 dv->now.width = dv->max.width;
5267 dv->now.offset = dv->max.offset;
5268 dv->now.factor = dv->max.factor;
5269 dv->now.flags = dv->max.flags;
5270
5271 pPage1 = (SCSIDevicePage1_t *)pPage;
5272 if (pPage1) {
5273 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5274 dv->now.offset, &val, &configuration, dv->now.flags);
5275 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5276 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005277 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005279 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 }
5281
Christoph Hellwig637fa992005-08-18 16:25:44 +02005282 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5284 break;
5285
5286 case MPT_SET_MIN:
5287 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5288 hd->ioc->name));
5289 /* Set page to asynchronous and narrow
5290 * Do not update now, breaks fallback routine. */
5291 width = MPT_NARROW;
5292 offset = 0;
5293 factor = MPT_ASYNC;
5294 negoFlags = dv->max.flags;
5295
5296 pPage1 = (SCSIDevicePage1_t *)pPage;
5297 if (pPage1) {
5298 mptscsih_setDevicePage1Flags (width, factor,
5299 offset, &val, &configuration, negoFlags);
5300 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5301 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005302 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005304 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 }
5306 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5307 id, width, factor, offset, val, configuration, negoFlags));
5308 break;
5309
5310 case MPT_FALLBACK:
5311 ddvprintk((MYIOC_s_NOTE_FMT
5312 "Fallback: Start: offset %d, factor %x, width %d \n",
5313 hd->ioc->name, dv->now.offset,
5314 dv->now.factor, dv->now.width));
5315 width = dv->now.width;
5316 offset = dv->now.offset;
5317 factor = dv->now.factor;
5318 if ((offset) && (dv->max.width)) {
5319 if (factor < MPT_ULTRA160)
5320 factor = MPT_ULTRA160;
5321 else if (factor < MPT_ULTRA2) {
5322 factor = MPT_ULTRA2;
5323 width = MPT_WIDE;
5324 } else if ((factor == MPT_ULTRA2) && width) {
5325 factor = MPT_ULTRA2;
5326 width = MPT_NARROW;
5327 } else if (factor < MPT_ULTRA) {
5328 factor = MPT_ULTRA;
5329 width = MPT_WIDE;
5330 } else if ((factor == MPT_ULTRA) && width) {
5331 width = MPT_NARROW;
5332 } else if (factor < MPT_FAST) {
5333 factor = MPT_FAST;
5334 width = MPT_WIDE;
5335 } else if ((factor == MPT_FAST) && width) {
5336 factor = MPT_FAST;
5337 width = MPT_NARROW;
5338 } else if (factor < MPT_SCSI) {
5339 factor = MPT_SCSI;
5340 width = MPT_WIDE;
5341 } else if ((factor == MPT_SCSI) && width) {
5342 factor = MPT_SCSI;
5343 width = MPT_NARROW;
5344 } else {
5345 factor = MPT_ASYNC;
5346 offset = 0;
5347 }
5348
5349 } else if (offset) {
5350 width = MPT_NARROW;
5351 if (factor < MPT_ULTRA)
5352 factor = MPT_ULTRA;
5353 else if (factor < MPT_FAST)
5354 factor = MPT_FAST;
5355 else if (factor < MPT_SCSI)
5356 factor = MPT_SCSI;
5357 else {
5358 factor = MPT_ASYNC;
5359 offset = 0;
5360 }
5361
5362 } else {
5363 width = MPT_NARROW;
5364 factor = MPT_ASYNC;
5365 }
5366 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5367 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5368
5369 dv->now.width = width;
5370 dv->now.offset = offset;
5371 dv->now.factor = factor;
5372 dv->now.flags = dv->max.flags;
5373
5374 pPage1 = (SCSIDevicePage1_t *)pPage;
5375 if (pPage1) {
5376 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5377 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005378 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 id, width, offset, factor, dv->now.flags, val, configuration));
5380
Christoph Hellwig637fa992005-08-18 16:25:44 +02005381 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005383 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 }
5385
5386 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5387 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5388 break;
5389
5390 case MPT_SAVE:
5391 ddvprintk((MYIOC_s_NOTE_FMT
5392 "Saving to Target structure: ", hd->ioc->name));
5393 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5394 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5395
5396 /* Save these values to target structures
5397 * or overwrite nvram (phys disks only).
5398 */
5399
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005400 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume ) {
5401 vtarget->maxWidth = dv->now.width;
5402 vtarget->maxOffset = dv->now.offset;
5403 vtarget->minSyncFactor = dv->now.factor;
5404 vtarget->negoFlags = dv->now.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 } else {
5406 /* Preserv all flags, use
5407 * read-modify-write algorithm
5408 */
5409 if (hd->ioc->spi_data.nvram) {
5410 data = hd->ioc->spi_data.nvram[id];
5411
5412 if (dv->now.width)
5413 data &= ~MPT_NVRAM_WIDE_DISABLE;
5414 else
5415 data |= MPT_NVRAM_WIDE_DISABLE;
5416
5417 if (!dv->now.offset)
5418 factor = MPT_ASYNC;
5419
5420 data &= ~MPT_NVRAM_SYNC_MASK;
5421 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5422
5423 hd->ioc->spi_data.nvram[id] = data;
5424 }
5425 }
5426 break;
5427 }
5428}
5429
5430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5431/* mptscsih_fillbuf - fill a buffer with a special data pattern
5432 * cleanup. For bus scan only.
5433 *
5434 * @buffer: Pointer to data buffer to be filled.
5435 * @size: Number of bytes to fill
5436 * @index: Pattern index
5437 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5438 */
5439static void
5440mptscsih_fillbuf(char *buffer, int size, int index, int width)
5441{
5442 char *ptr = buffer;
5443 int ii;
5444 char byte;
5445 short val;
5446
5447 switch (index) {
5448 case 0:
5449
5450 if (width) {
5451 /* Pattern: 0000 FFFF 0000 FFFF
5452 */
5453 for (ii=0; ii < size; ii++, ptr++) {
5454 if (ii & 0x02)
5455 *ptr = 0xFF;
5456 else
5457 *ptr = 0x00;
5458 }
5459 } else {
5460 /* Pattern: 00 FF 00 FF
5461 */
5462 for (ii=0; ii < size; ii++, ptr++) {
5463 if (ii & 0x01)
5464 *ptr = 0xFF;
5465 else
5466 *ptr = 0x00;
5467 }
5468 }
5469 break;
5470
5471 case 1:
5472 if (width) {
5473 /* Pattern: 5555 AAAA 5555 AAAA 5555
5474 */
5475 for (ii=0; ii < size; ii++, ptr++) {
5476 if (ii & 0x02)
5477 *ptr = 0xAA;
5478 else
5479 *ptr = 0x55;
5480 }
5481 } else {
5482 /* Pattern: 55 AA 55 AA 55
5483 */
5484 for (ii=0; ii < size; ii++, ptr++) {
5485 if (ii & 0x01)
5486 *ptr = 0xAA;
5487 else
5488 *ptr = 0x55;
5489 }
5490 }
5491 break;
5492
5493 case 2:
5494 /* Pattern: 00 01 02 03 04 05
5495 * ... FE FF 00 01..
5496 */
5497 for (ii=0; ii < size; ii++, ptr++)
5498 *ptr = (char) ii;
5499 break;
5500
5501 case 3:
5502 if (width) {
5503 /* Wide Pattern: FFFE 0001 FFFD 0002
5504 * ... 4000 DFFF 8000 EFFF
5505 */
5506 byte = 0;
5507 for (ii=0; ii < size/2; ii++) {
5508 /* Create the base pattern
5509 */
5510 val = (1 << byte);
5511 /* every 64 (0x40) bytes flip the pattern
5512 * since we fill 2 bytes / iteration,
5513 * test for ii = 0x20
5514 */
5515 if (ii & 0x20)
5516 val = ~(val);
5517
5518 if (ii & 0x01) {
5519 *ptr = (char)( (val & 0xFF00) >> 8);
5520 ptr++;
5521 *ptr = (char)(val & 0xFF);
5522 byte++;
5523 byte &= 0x0F;
5524 } else {
5525 val = ~val;
5526 *ptr = (char)( (val & 0xFF00) >> 8);
5527 ptr++;
5528 *ptr = (char)(val & 0xFF);
5529 }
5530
5531 ptr++;
5532 }
5533 } else {
5534 /* Narrow Pattern: FE 01 FD 02 FB 04
5535 * .. 7F 80 01 FE 02 FD ... 80 7F
5536 */
5537 byte = 0;
5538 for (ii=0; ii < size; ii++, ptr++) {
5539 /* Base pattern - first 32 bytes
5540 */
5541 if (ii & 0x01) {
5542 *ptr = (1 << byte);
5543 byte++;
5544 byte &= 0x07;
5545 } else {
5546 *ptr = (char) (~(1 << byte));
5547 }
5548
5549 /* Flip the pattern every 32 bytes
5550 */
5551 if (ii & 0x20)
5552 *ptr = ~(*ptr);
5553 }
5554 }
5555 break;
5556 }
5557}
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005558
5559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5560/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
5561 * Else set the NEED_DV flag after Read Capacity Issued (disks)
5562 * or Mode Sense (cdroms).
5563 *
5564 * Tapes, initTarget will set this flag on completion of Inquiry command.
5565 * Called only if DV_NOT_DONE flag is set
5566 */
5567static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005568mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005569{
5570 MPT_ADAPTER *ioc = hd->ioc;
5571 u8 cmd;
5572 SpiCfgData *pSpi;
5573
5574 ddvtprintk((MYIOC_s_NOTE_FMT
5575 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005576 hd->ioc->name, sc->device->id, sc->device->lun , hd->negoNvram, sc->cmnd[0]));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005577
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005578 if ((sc->device->lun != 0) || (hd->negoNvram != 0))
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005579 return;
5580
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005581 cmd = sc->cmnd[0];
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005582
5583 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
5584 pSpi = &ioc->spi_data;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005585 if ((ioc->raid_data.isRaid & (1 << sc->device->id)) && ioc->raid_data.pIocPg3) {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005586 /* Set NEED_DV for all hidden disks
5587 */
5588 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5589 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5590
5591 while (numPDisk) {
5592 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
5593 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
5594 pPDisk++;
5595 numPDisk--;
5596 }
5597 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005598 pSpi->dvStatus[sc->device->id] |= MPT_SCSICFG_NEED_DV;
5599 ddvtprintk(("NEED_DV set for visible disk id %d\n", sc->device->id));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005600 }
5601}
5602
5603/* mptscsih_raid_set_dv_flags()
5604 *
5605 * New or replaced disk. Set DV flag and schedule DV.
5606 */
5607static void
5608mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
5609{
5610 MPT_ADAPTER *ioc = hd->ioc;
5611 SpiCfgData *pSpi = &ioc->spi_data;
5612 Ioc3PhysDisk_t *pPDisk;
5613 int numPDisk;
5614
5615 if (hd->negoNvram != 0)
5616 return;
5617
5618 ddvtprintk(("DV requested for phys disk id %d\n", id));
5619 if (ioc->raid_data.pIocPg3) {
5620 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5621 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5622 while (numPDisk) {
5623 if (id == pPDisk->PhysDiskNum) {
5624 pSpi->dvStatus[pPDisk->PhysDiskID] =
5625 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
5626 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
5627 ddvtprintk(("NEED_DV set for phys disk id %d\n",
5628 pPDisk->PhysDiskID));
5629 break;
5630 }
5631 pPDisk++;
5632 numPDisk--;
5633 }
5634
5635 if (numPDisk == 0) {
5636 /* The physical disk that needs DV was not found
5637 * in the stored IOC Page 3. The driver must reload
5638 * this page. DV routine will set the NEED_DV flag for
5639 * all phys disks that have DV_NOT_DONE set.
5640 */
5641 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
5642 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
5643 }
5644 }
5645}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5647
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005648EXPORT_SYMBOL(mptscsih_remove);
5649EXPORT_SYMBOL(mptscsih_shutdown);
5650#ifdef CONFIG_PM
5651EXPORT_SYMBOL(mptscsih_suspend);
5652EXPORT_SYMBOL(mptscsih_resume);
5653#endif
5654EXPORT_SYMBOL(mptscsih_proc_info);
5655EXPORT_SYMBOL(mptscsih_info);
5656EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005657EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005658EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005659EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005660EXPORT_SYMBOL(mptscsih_slave_destroy);
5661EXPORT_SYMBOL(mptscsih_slave_configure);
5662EXPORT_SYMBOL(mptscsih_abort);
5663EXPORT_SYMBOL(mptscsih_dev_reset);
5664EXPORT_SYMBOL(mptscsih_bus_reset);
5665EXPORT_SYMBOL(mptscsih_host_reset);
5666EXPORT_SYMBOL(mptscsih_bios_param);
5667EXPORT_SYMBOL(mptscsih_io_done);
5668EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5669EXPORT_SYMBOL(mptscsih_scandv_complete);
5670EXPORT_SYMBOL(mptscsih_event_process);
5671EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005672EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005673EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06005674EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/