blob: 4330ed0cedaaaafbc2a435b73c1b42b4aadc43d9 [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
147static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
148static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
149
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400150int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
151int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153static void mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
154static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
155static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
156static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
157static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
158static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
159static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400160int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
162static int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
163
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600164static struct work_struct mptscsih_persistTask;
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
167static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
168static void mptscsih_domainValidation(void *hd);
169static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
170static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
171static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
172static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
173static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600174static void mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400177void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700178void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400180int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
181int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#endif
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
185
186#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
187/*
188 * Domain Validation task structure
189 */
190static DEFINE_SPINLOCK(dvtaskQ_lock);
191static int dvtaskQ_active = 0;
192static int dvtaskQ_release = 0;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400193static struct work_struct dvTaskQ_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194#endif
195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
197/**
198 * mptscsih_add_sge - Place a simple SGE at address pAddr.
199 * @pAddr: virtual address for SGE
200 * @flagslength: SGE flags and data transfer length
201 * @dma_addr: Physical address
202 *
203 * This routine places a MPT request frame back on the MPT adapter's
204 * FreeQ.
205 */
206static inline void
207mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
208{
209 if (sizeof(dma_addr_t) == sizeof(u64)) {
210 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
211 u32 tmp = dma_addr & 0xFFFFFFFF;
212
213 pSge->FlagsLength = cpu_to_le32(flagslength);
214 pSge->Address.Low = cpu_to_le32(tmp);
215 tmp = (u32) ((u64)dma_addr >> 32);
216 pSge->Address.High = cpu_to_le32(tmp);
217
218 } else {
219 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
220 pSge->FlagsLength = cpu_to_le32(flagslength);
221 pSge->Address = cpu_to_le32(dma_addr);
222 }
223} /* mptscsih_add_sge() */
224
225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
226/**
227 * mptscsih_add_chain - Place a chain SGE at address pAddr.
228 * @pAddr: virtual address for SGE
229 * @next: nextChainOffset value (u32's)
230 * @length: length of next SGL segment
231 * @dma_addr: Physical address
232 *
233 * This routine places a MPT request frame back on the MPT adapter's
234 * FreeQ.
235 */
236static inline void
237mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
238{
239 if (sizeof(dma_addr_t) == sizeof(u64)) {
240 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
241 u32 tmp = dma_addr & 0xFFFFFFFF;
242
243 pChain->Length = cpu_to_le16(length);
244 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
245
246 pChain->NextChainOffset = next;
247
248 pChain->Address.Low = cpu_to_le32(tmp);
249 tmp = (u32) ((u64)dma_addr >> 32);
250 pChain->Address.High = cpu_to_le32(tmp);
251 } else {
252 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
253 pChain->Length = cpu_to_le16(length);
254 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
255 pChain->NextChainOffset = next;
256 pChain->Address = cpu_to_le32(dma_addr);
257 }
258} /* mptscsih_add_chain() */
259
260/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
261/*
262 * mptscsih_getFreeChainBuffer - Function to get a free chain
263 * from the MPT_SCSI_HOST FreeChainQ.
264 * @ioc: Pointer to MPT_ADAPTER structure
265 * @req_idx: Index of the SCSI IO request frame. (output)
266 *
267 * return SUCCESS or FAILED
268 */
269static inline int
270mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
271{
272 MPT_FRAME_HDR *chainBuf;
273 unsigned long flags;
274 int rc;
275 int chain_idx;
276
277 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
278 ioc->name));
279 spin_lock_irqsave(&ioc->FreeQlock, flags);
280 if (!list_empty(&ioc->FreeChainQ)) {
281 int offset;
282
283 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
284 u.frame.linkage.list);
285 list_del(&chainBuf->u.frame.linkage.list);
286 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
287 chain_idx = offset / ioc->req_sz;
288 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200289 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
290 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 } else {
292 rc = FAILED;
293 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200294 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 ioc->name));
296 }
297 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
298
299 *retIndex = chain_idx;
300 return rc;
301} /* mptscsih_getFreeChainBuffer() */
302
303/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
304/*
305 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
306 * SCSIIORequest_t Message Frame.
307 * @ioc: Pointer to MPT_ADAPTER structure
308 * @SCpnt: Pointer to scsi_cmnd structure
309 * @pReq: Pointer to SCSIIORequest_t structure
310 *
311 * Returns ...
312 */
313static int
314mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
315 SCSIIORequest_t *pReq, int req_idx)
316{
317 char *psge;
318 char *chainSge;
319 struct scatterlist *sg;
320 int frm_sz;
321 int sges_left, sg_done;
322 int chain_idx = MPT_HOST_NO_CHAIN;
323 int sgeOffset;
324 int numSgeSlots, numSgeThisFrame;
325 u32 sgflags, sgdir, thisxfer = 0;
326 int chain_dma_off = 0;
327 int newIndex;
328 int ii;
329 dma_addr_t v2;
330 u32 RequestNB;
331
332 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
333 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
334 sgdir = MPT_TRANSFER_HOST_TO_IOC;
335 } else {
336 sgdir = MPT_TRANSFER_IOC_TO_HOST;
337 }
338
339 psge = (char *) &pReq->SGL;
340 frm_sz = ioc->req_sz;
341
342 /* Map the data portion, if any.
343 * sges_left = 0 if no data transfer.
344 */
345 if ( (sges_left = SCpnt->use_sg) ) {
346 sges_left = pci_map_sg(ioc->pcidev,
347 (struct scatterlist *) SCpnt->request_buffer,
348 SCpnt->use_sg,
349 SCpnt->sc_data_direction);
350 if (sges_left == 0)
351 return FAILED;
352 } else if (SCpnt->request_bufflen) {
353 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
354 SCpnt->request_buffer,
355 SCpnt->request_bufflen,
356 SCpnt->sc_data_direction);
357 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
358 ioc->name, SCpnt, SCpnt->request_bufflen));
359 mptscsih_add_sge((char *) &pReq->SGL,
360 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
361 SCpnt->SCp.dma_handle);
362
363 return SUCCESS;
364 }
365
366 /* Handle the SG case.
367 */
368 sg = (struct scatterlist *) SCpnt->request_buffer;
369 sg_done = 0;
370 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
371 chainSge = NULL;
372
373 /* Prior to entering this loop - the following must be set
374 * current MF: sgeOffset (bytes)
375 * chainSge (Null if original MF is not a chain buffer)
376 * sg_done (num SGE done for this MF)
377 */
378
379nextSGEset:
380 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
381 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
382
383 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
384
385 /* Get first (num - 1) SG elements
386 * Skip any SG entries with a length of 0
387 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
388 */
389 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
390 thisxfer = sg_dma_len(sg);
391 if (thisxfer == 0) {
392 sg ++; /* Get next SG element from the OS */
393 sg_done++;
394 continue;
395 }
396
397 v2 = sg_dma_address(sg);
398 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
399
400 sg++; /* Get next SG element from the OS */
401 psge += (sizeof(u32) + sizeof(dma_addr_t));
402 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
403 sg_done++;
404 }
405
406 if (numSgeThisFrame == sges_left) {
407 /* Add last element, end of buffer and end of list flags.
408 */
409 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
410 MPT_SGE_FLAGS_END_OF_BUFFER |
411 MPT_SGE_FLAGS_END_OF_LIST;
412
413 /* Add last SGE and set termination flags.
414 * Note: Last SGE may have a length of 0 - which should be ok.
415 */
416 thisxfer = sg_dma_len(sg);
417
418 v2 = sg_dma_address(sg);
419 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
420 /*
421 sg++;
422 psge += (sizeof(u32) + sizeof(dma_addr_t));
423 */
424 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
425 sg_done++;
426
427 if (chainSge) {
428 /* The current buffer is a chain buffer,
429 * but there is not another one.
430 * Update the chain element
431 * Offset and Length fields.
432 */
433 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
434 } else {
435 /* The current buffer is the original MF
436 * and there is no Chain buffer.
437 */
438 pReq->ChainOffset = 0;
439 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200440 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
442 ioc->RequestNB[req_idx] = RequestNB;
443 }
444 } else {
445 /* At least one chain buffer is needed.
446 * Complete the first MF
447 * - last SGE element, set the LastElement bit
448 * - set ChainOffset (words) for orig MF
449 * (OR finish previous MF chain buffer)
450 * - update MFStructPtr ChainIndex
451 * - Populate chain element
452 * Also
453 * Loop until done.
454 */
455
456 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
457 ioc->name, sg_done));
458
459 /* Set LAST_ELEMENT flag for last non-chain element
460 * in the buffer. Since psge points at the NEXT
461 * SGE element, go back one SGE element, update the flags
462 * and reset the pointer. (Note: sgflags & thisxfer are already
463 * set properly).
464 */
465 if (sg_done) {
466 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
467 sgflags = le32_to_cpu(*ptmp);
468 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
469 *ptmp = cpu_to_le32(sgflags);
470 }
471
472 if (chainSge) {
473 /* The current buffer is a chain buffer.
474 * chainSge points to the previous Chain Element.
475 * Update its chain element Offset and Length (must
476 * include chain element size) fields.
477 * Old chain element is now complete.
478 */
479 u8 nextChain = (u8) (sgeOffset >> 2);
480 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
481 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
482 } else {
483 /* The original MF buffer requires a chain buffer -
484 * set the offset.
485 * Last element in this MF is a chain element.
486 */
487 pReq->ChainOffset = (u8) (sgeOffset >> 2);
488 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
489 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
490 ioc->RequestNB[req_idx] = RequestNB;
491 }
492
493 sges_left -= sg_done;
494
495
496 /* NOTE: psge points to the beginning of the chain element
497 * in current buffer. Get a chain buffer.
498 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200499 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
500 dfailprintk((MYIOC_s_INFO_FMT
501 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
502 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 /* Update the tracking arrays.
507 * If chainSge == NULL, update ReqToChain, else ChainToChain
508 */
509 if (chainSge) {
510 ioc->ChainToChain[chain_idx] = newIndex;
511 } else {
512 ioc->ReqToChain[req_idx] = newIndex;
513 }
514 chain_idx = newIndex;
515 chain_dma_off = ioc->req_sz * chain_idx;
516
517 /* Populate the chainSGE for the current buffer.
518 * - Set chain buffer pointer to psge and fill
519 * out the Address and Flags fields.
520 */
521 chainSge = (char *) psge;
522 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
523 psge, req_idx));
524
525 /* Start the SGE for the next buffer
526 */
527 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
528 sgeOffset = 0;
529 sg_done = 0;
530
531 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
532 psge, chain_idx));
533
534 /* Start the SGE for the next buffer
535 */
536
537 goto nextSGEset;
538 }
539
540 return SUCCESS;
541} /* mptscsih_AddSGE() */
542
543/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
544/*
545 * mptscsih_io_done - Main SCSI IO callback routine registered to
546 * Fusion MPT (base) driver
547 * @ioc: Pointer to MPT_ADAPTER structure
548 * @mf: Pointer to original MPT request frame
549 * @r: Pointer to MPT reply frame (NULL if TurboReply)
550 *
551 * This routine is called from mpt.c::mpt_interrupt() at the completion
552 * of any SCSI IO request.
553 * This routine is registered with the Fusion MPT (base) driver at driver
554 * load/init time via the mpt_register() API call.
555 *
556 * Returns 1 indicating alloc'd request frame ptr should be freed.
557 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400558int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
560{
561 struct scsi_cmnd *sc;
562 MPT_SCSI_HOST *hd;
563 SCSIIORequest_t *pScsiReq;
564 SCSIIOReply_t *pScsiReply;
565 u16 req_idx;
566
567 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
568
569 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
570 sc = hd->ScsiLookup[req_idx];
571 if (sc == NULL) {
572 MPIHeader_t *hdr = (MPIHeader_t *)mf;
573
574 /* Remark: writeSDP1 will use the ScsiDoneCtx
575 * If a SCSI I/O cmd, device disabled by OS and
576 * completion done. Cannot touch sc struct. Just free mem.
577 */
578 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
579 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
580 ioc->name);
581
582 mptscsih_freeChainBuffers(ioc, req_idx);
583 return 1;
584 }
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 sc->result = DID_OK << 16; /* Set default reply as OK */
587 pScsiReq = (SCSIIORequest_t *) mf;
588 pScsiReply = (SCSIIOReply_t *) mr;
589
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200590 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
591 dmfprintk((MYIOC_s_INFO_FMT
592 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
593 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
594 }else{
595 dmfprintk((MYIOC_s_INFO_FMT
596 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
597 ioc->name, mf, mr, sc, req_idx));
598 }
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (pScsiReply == NULL) {
601 /* special context reply handling */
602 ;
603 } else {
604 u32 xfer_cnt;
605 u16 status;
606 u8 scsi_state, scsi_status;
607
608 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
609 scsi_state = pScsiReply->SCSIState;
610 scsi_status = pScsiReply->SCSIStatus;
611 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
612 sc->resid = sc->request_bufflen - xfer_cnt;
613
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600614 /*
615 * if we get a data underrun indication, yet no data was
616 * transferred and the SCSI status indicates that the
617 * command was never started, change the data underrun
618 * to success
619 */
620 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
621 (scsi_status == MPI_SCSI_STATUS_BUSY ||
622 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
623 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
624 status = MPI_IOCSTATUS_SUCCESS;
625 }
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
628 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
629 "resid=%d bufflen=%d xfer_cnt=%d\n",
630 ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600631 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 sc->request_bufflen, xfer_cnt));
633
634 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400635 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /*
638 * Look for + dump FCP ResponseInfo[]!
639 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600640 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
641 pScsiReply->ResponseInfo) {
642 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
643 "FCP_ResponseInfo=%08xh\n",
644 ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 le32_to_cpu(pScsiReply->ResponseInfo));
646 }
647
648 switch(status) {
649 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
650 /* CHECKME!
651 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
652 * But not: DID_BUS_BUSY lest one risk
653 * killing interrupt handler:-(
654 */
655 sc->result = SAM_STAT_BUSY;
656 break;
657
658 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
659 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
660 sc->result = DID_BAD_TARGET << 16;
661 break;
662
663 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
664 /* Spoof to SCSI Selection Timeout! */
665 sc->result = DID_NO_CONNECT << 16;
666
667 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
668 hd->sel_timeout[pScsiReq->TargetID]++;
669 break;
670
671 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
672 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
673 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
674 /* Linux handles an unsolicited DID_RESET better
675 * than an unsolicited DID_ABORT.
676 */
677 sc->result = DID_RESET << 16;
678
679 /* GEM Workaround. */
680 if (ioc->bus_type == SCSI)
681 mptscsih_no_negotiate(hd, sc->device->id);
682 break;
683
684 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600685 sc->resid = sc->request_bufflen - xfer_cnt;
686 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
687 sc->result=DID_SOFT_ERROR << 16;
688 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600690 dreplyprintk((KERN_NOTICE
691 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
695 /*
696 * Do upfront check for valid SenseData and give it
697 * precedence!
698 */
699 sc->result = (DID_OK << 16) | scsi_status;
700 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
701 /* Have already saved the status and sense data
702 */
703 ;
704 } else {
705 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600706 if (scsi_status == SAM_STAT_BUSY)
707 sc->result = SAM_STAT_BUSY;
708 else
709 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
711 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
712 /* What to do?
713 */
714 sc->result = DID_SOFT_ERROR << 16;
715 }
716 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
717 /* Not real sure here either... */
718 sc->result = DID_RESET << 16;
719 }
720 }
721
722 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
723 sc->underflow));
724 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
725 /* Report Queue Full
726 */
727 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
728 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400729
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 break;
731
732 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
733 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600734 if (scsi_status == MPI_SCSI_STATUS_BUSY)
735 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
736 else
737 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (scsi_state == 0) {
739 ;
740 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
741 /*
742 * If running against circa 200003dd 909 MPT f/w,
743 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
744 * (QUEUE_FULL) returned from device! --> get 0x0000?128
745 * and with SenseBytes set to 0.
746 */
747 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
748 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
749
750 }
751 else if (scsi_state &
752 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
753 ) {
754 /*
755 * What to do?
756 */
757 sc->result = DID_SOFT_ERROR << 16;
758 }
759 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
760 /* Not real sure here either... */
761 sc->result = DID_RESET << 16;
762 }
763 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
764 /* Device Inq. data indicates that it supports
765 * QTags, but rejects QTag messages.
766 * This command completed OK.
767 *
768 * Not real sure here either so do nothing... */
769 }
770
771 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
772 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
773
774 /* Add handling of:
775 * Reservation Conflict, Busy,
776 * Command Terminated, CHECK
777 */
778 break;
779
780 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
781 sc->result = DID_SOFT_ERROR << 16;
782 break;
783
784 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
785 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
786 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
787 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
788 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
789 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
790 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
791 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
792 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
793 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
794 default:
795 /*
796 * What to do?
797 */
798 sc->result = DID_SOFT_ERROR << 16;
799 break;
800
801 } /* switch(status) */
802
803 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
804 } /* end of address reply case */
805
806 /* Unmap the DMA buffers, if any. */
807 if (sc->use_sg) {
808 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
809 sc->use_sg, sc->sc_data_direction);
810 } else if (sc->request_bufflen) {
811 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
812 sc->request_bufflen, sc->sc_data_direction);
813 }
814
815 hd->ScsiLookup[req_idx] = NULL;
816
817 sc->scsi_done(sc); /* Issue the command callback */
818
819 /* Free Chain buffers */
820 mptscsih_freeChainBuffers(ioc, req_idx);
821 return 1;
822}
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824/*
825 * mptscsih_flush_running_cmds - For each command found, search
826 * Scsi_Host instance taskQ and reply to OS.
827 * Called only if recovering from a FW reload.
828 * @hd: Pointer to a SCSI HOST structure
829 *
830 * Returns: None.
831 *
832 * Must be called while new I/Os are being queued.
833 */
834static void
835mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
836{
837 MPT_ADAPTER *ioc = hd->ioc;
838 struct scsi_cmnd *SCpnt;
839 MPT_FRAME_HDR *mf;
840 int ii;
841 int max = ioc->req_depth;
842
843 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
844 for (ii= 0; ii < max; ii++) {
845 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
846
847 /* Command found.
848 */
849
850 /* Null ScsiLookup index
851 */
852 hd->ScsiLookup[ii] = NULL;
853
854 mf = MPT_INDEX_2_MFPTR(ioc, ii);
855 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
856 mf, SCpnt));
857
858 /* Set status, free OS resources (SG DMA buffers)
859 * Do OS callback
860 * Free driver resources (chain, msg buffers)
861 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400862 if (SCpnt->use_sg) {
863 pci_unmap_sg(ioc->pcidev,
864 (struct scatterlist *) SCpnt->request_buffer,
865 SCpnt->use_sg,
866 SCpnt->sc_data_direction);
867 } else if (SCpnt->request_bufflen) {
868 pci_unmap_single(ioc->pcidev,
869 SCpnt->SCp.dma_handle,
870 SCpnt->request_bufflen,
871 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
873 SCpnt->result = DID_RESET << 16;
874 SCpnt->host_scribble = NULL;
875
876 /* Free Chain buffers */
877 mptscsih_freeChainBuffers(ioc, ii);
878
879 /* Free Message frames */
880 mpt_free_msg_frame(ioc, mf);
881
882 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
883 }
884 }
885
886 return;
887}
888
889/*
890 * mptscsih_search_running_cmds - Delete any commands associated
891 * with the specified target and lun. Function called only
892 * when a lun is disable by mid-layer.
893 * Do NOT access the referenced scsi_cmnd structure or
894 * members. Will cause either a paging or NULL ptr error.
895 * @hd: Pointer to a SCSI HOST structure
896 * @target: target id
897 * @lun: lun
898 *
899 * Returns: None.
900 *
901 * Called from slave_destroy.
902 */
903static void
904mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun)
905{
906 SCSIIORequest_t *mf = NULL;
907 int ii;
908 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600909 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
912 target, lun, max));
913
914 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600915 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
918
919 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
920 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
921
922 if ((mf->TargetID != ((u8)target)) || (mf->LUN[1] != ((u8) lun)))
923 continue;
924
925 /* Cleanup
926 */
927 hd->ScsiLookup[ii] = NULL;
928 mptscsih_freeChainBuffers(hd->ioc, ii);
929 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600930 if (sc->use_sg) {
931 pci_unmap_sg(hd->ioc->pcidev,
932 (struct scatterlist *) sc->request_buffer,
933 sc->use_sg,
934 sc->sc_data_direction);
935 } else if (sc->request_bufflen) {
936 pci_unmap_single(hd->ioc->pcidev,
937 sc->SCp.dma_handle,
938 sc->request_bufflen,
939 sc->sc_data_direction);
940 }
941 sc->host_scribble = NULL;
942 sc->result = DID_NO_CONNECT << 16;
943 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 return;
947}
948
949/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
952/*
953 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
954 * from a SCSI target device.
955 * @sc: Pointer to scsi_cmnd structure
956 * @pScsiReply: Pointer to SCSIIOReply_t
957 * @pScsiReq: Pointer to original SCSI request
958 *
959 * This routine periodically reports QUEUE_FULL status returned from a
960 * SCSI target device. It reports this to the console via kernel
961 * printk() API call, not more than once every 10 seconds.
962 */
963static void
964mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
965{
966 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400969 if (sc->device == NULL)
970 return;
971 if (sc->device->host == NULL)
972 return;
973 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
974 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400976 if (time - hd->last_queue_full > 10 * HZ) {
977 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
978 hd->ioc->name, 0, sc->device->id, sc->device->lun));
979 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981}
982
983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
984/*
985 * mptscsih_remove - Removed scsi devices
986 * @pdev: Pointer to pci_dev structure
987 *
988 *
989 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400990void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991mptscsih_remove(struct pci_dev *pdev)
992{
993 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
994 struct Scsi_Host *host = ioc->sh;
995 MPT_SCSI_HOST *hd;
996 int count;
997 unsigned long flags;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400998 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001000 if(!host) {
1001 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 scsi_remove_host(host);
1006
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001007 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1008 return;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1011 /* Check DV thread active */
1012 count = 10 * HZ;
1013 spin_lock_irqsave(&dvtaskQ_lock, flags);
1014 if (dvtaskQ_active) {
1015 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
Nishanth Aravamudan65210182005-11-07 01:01:19 -08001016 while(dvtaskQ_active && --count)
1017 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 } else {
1019 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
1020 }
1021 if (!count)
1022 printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
1023#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
1024 else
1025 printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
1026#endif
1027#endif
1028
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001029 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001031 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001033 if (hd->ScsiLookup != NULL) {
1034 sz1 = hd->ioc->req_depth * sizeof(void *);
1035 kfree(hd->ScsiLookup);
1036 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
1038
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001039 /*
1040 * Free pointer array.
1041 */
1042 kfree(hd->Targets);
1043 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001045 dprintk((MYIOC_s_INFO_FMT
1046 "Free'd ScsiLookup (%d) memory\n",
1047 hd->ioc->name, sz1));
1048
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001049 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001050
1051 /* NULL the Scsi_Host pointer
1052 */
1053 hd->ioc->sh = NULL;
1054
1055 scsi_host_put(host);
1056
1057 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1062/*
1063 * mptscsih_shutdown - reboot notifier
1064 *
1065 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001066void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001067mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001069 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 struct Scsi_Host *host = ioc->sh;
1071 MPT_SCSI_HOST *hd;
1072
1073 if(!host)
1074 return;
1075
1076 hd = (MPT_SCSI_HOST *)host->hostdata;
1077
1078 /* Flush the cache of this adapter
1079 */
1080 if(hd != NULL)
1081 mptscsih_synchronize_cache(hd, 0);
1082
1083}
1084
1085#ifdef CONFIG_PM
1086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1087/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001088 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 *
1090 *
1091 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001092int
Pavel Machek8d189f72005-04-16 15:25:28 -07001093mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001095 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001096 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/*
1101 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1102 *
1103 *
1104 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001105int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106mptscsih_resume(struct pci_dev *pdev)
1107{
1108 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1109 struct Scsi_Host *host = ioc->sh;
1110 MPT_SCSI_HOST *hd;
1111
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001112 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if(!host)
1115 return 0;
1116
1117 hd = (MPT_SCSI_HOST *)host->hostdata;
1118 if(!hd)
1119 return 0;
1120
1121#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1122 {
1123 unsigned long lflags;
1124 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1125 if (!dvtaskQ_active) {
1126 dvtaskQ_active = 1;
1127 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001130 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 } else {
1132 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1133 }
1134 }
1135#endif
1136 return 0;
1137}
1138
1139#endif
1140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1142/**
1143 * mptscsih_info - Return information about MPT adapter
1144 * @SChost: Pointer to Scsi_Host structure
1145 *
1146 * (linux scsi_host_template.info routine)
1147 *
1148 * Returns pointer to buffer where information was written.
1149 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001150const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151mptscsih_info(struct Scsi_Host *SChost)
1152{
1153 MPT_SCSI_HOST *h;
1154 int size = 0;
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159 if (h->info_kbuf == NULL)
1160 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1161 return h->info_kbuf;
1162 h->info_kbuf[0] = '\0';
1163
1164 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1165 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001168 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169}
1170
1171struct info_str {
1172 char *buffer;
1173 int length;
1174 int offset;
1175 int pos;
1176};
1177
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001178static void
1179mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
1181 if (info->pos + len > info->length)
1182 len = info->length - info->pos;
1183
1184 if (info->pos + len < info->offset) {
1185 info->pos += len;
1186 return;
1187 }
1188
1189 if (info->pos < info->offset) {
1190 data += (info->offset - info->pos);
1191 len -= (info->offset - info->pos);
1192 }
1193
1194 if (len > 0) {
1195 memcpy(info->buffer + info->pos, data, len);
1196 info->pos += len;
1197 }
1198}
1199
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001200static int
1201mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 va_list args;
1204 char buf[81];
1205 int len;
1206
1207 va_start(args, fmt);
1208 len = vsprintf(buf, fmt, args);
1209 va_end(args);
1210
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return len;
1213}
1214
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001215static int
1216mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
1218 struct info_str info;
1219
1220 info.buffer = pbuf;
1221 info.length = len;
1222 info.offset = offset;
1223 info.pos = 0;
1224
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001225 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1226 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1227 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1228 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1231}
1232
1233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1234/**
1235 * mptscsih_proc_info - Return information about MPT adapter
1236 *
1237 * (linux scsi_host_template.info routine)
1238 *
1239 * buffer: if write, user data; if read, buffer for user
1240 * length: if write, return length;
1241 * offset: if write, 0; if read, the current offset into the buffer from
1242 * the previous read.
1243 * hostno: scsi host number
1244 * func: if write = 1; if read = 0
1245 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001246int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1248 int length, int func)
1249{
1250 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1251 MPT_ADAPTER *ioc = hd->ioc;
1252 int size = 0;
1253
1254 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001255 /*
1256 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 */
1258 } else {
1259 if (start)
1260 *start = buffer;
1261
1262 size = mptscsih_host_info(ioc, buffer, offset, length);
1263 }
1264
1265 return size;
1266}
1267
1268/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1269#define ADD_INDEX_LOG(req_ent) do { } while(0)
1270
1271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1272/**
1273 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1274 * @SCpnt: Pointer to scsi_cmnd structure
1275 * @done: Pointer SCSI mid-layer IO completion function
1276 *
1277 * (linux scsi_host_template.queuecommand routine)
1278 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1279 * from a linux scsi_cmnd request and send it to the IOC.
1280 *
1281 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1282 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1285{
1286 MPT_SCSI_HOST *hd;
1287 MPT_FRAME_HDR *mf;
1288 SCSIIORequest_t *pScsiReq;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001289 VirtDevice *pTarget = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 int lun;
1291 u32 datalen;
1292 u32 scsictl;
1293 u32 scsidir;
1294 u32 cmd_len;
1295 int my_idx;
1296 int ii;
1297
1298 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 lun = SCpnt->device->lun;
1300 SCpnt->scsi_done = done;
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1303 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1304
1305 if (hd->resetPending) {
1306 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1307 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1308 return SCSI_MLQUEUE_HOST_BUSY;
1309 }
1310
1311 /*
1312 * Put together a MPT SCSI request...
1313 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001314 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1316 hd->ioc->name));
1317 return SCSI_MLQUEUE_HOST_BUSY;
1318 }
1319
1320 pScsiReq = (SCSIIORequest_t *) mf;
1321
1322 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1323
1324 ADD_INDEX_LOG(my_idx);
1325
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001326 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 * Seems we may receive a buffer (datalen>0) even when there
1328 * will be no data transfer! GRRRRR...
1329 */
1330 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1331 datalen = SCpnt->request_bufflen;
1332 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1333 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1334 datalen = SCpnt->request_bufflen;
1335 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1336 } else {
1337 datalen = 0;
1338 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1339 }
1340
1341 /* Default to untagged. Once a target structure has been allocated,
1342 * use the Inquiry data to determine if device supports tagged.
1343 */
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001344 if (pTarget
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
1346 && (SCpnt->device->tagged_supported)) {
1347 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1348 } else {
1349 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1350 }
1351
1352 /* Use the above information to set up the message frame
1353 */
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001354 pScsiReq->TargetID = (u8) pTarget->target_id;
1355 pScsiReq->Bus = pTarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 pScsiReq->ChainOffset = 0;
1357 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1358 pScsiReq->CDBLength = SCpnt->cmd_len;
1359 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1360 pScsiReq->Reserved = 0;
1361 pScsiReq->MsgFlags = mpt_msg_flags();
1362 pScsiReq->LUN[0] = 0;
1363 pScsiReq->LUN[1] = lun;
1364 pScsiReq->LUN[2] = 0;
1365 pScsiReq->LUN[3] = 0;
1366 pScsiReq->LUN[4] = 0;
1367 pScsiReq->LUN[5] = 0;
1368 pScsiReq->LUN[6] = 0;
1369 pScsiReq->LUN[7] = 0;
1370 pScsiReq->Control = cpu_to_le32(scsictl);
1371
1372 /*
1373 * Write SCSI CDB into the message
1374 */
1375 cmd_len = SCpnt->cmd_len;
1376 for (ii=0; ii < cmd_len; ii++)
1377 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1378
1379 for (ii=cmd_len; ii < 16; ii++)
1380 pScsiReq->CDB[ii] = 0;
1381
1382 /* DataLength */
1383 pScsiReq->DataLength = cpu_to_le32(datalen);
1384
1385 /* SenseBuffer low address */
1386 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1387 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1388
1389 /* Now add the SG list
1390 * Always have a SGE even if null length.
1391 */
1392 if (datalen == 0) {
1393 /* Add a NULL SGE */
1394 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1395 (dma_addr_t) -1);
1396 } else {
1397 /* Add a 32 or 64 bit SGE */
1398 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1399 goto fail;
1400 }
1401
1402 hd->ScsiLookup[my_idx] = SCpnt;
1403 SCpnt->host_scribble = NULL;
1404
1405#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1406 if (hd->ioc->bus_type == SCSI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001407 int dvStatus = hd->ioc->spi_data.dvStatus[pTarget->target_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 int issueCmd = 1;
1409
1410 if (dvStatus || hd->ioc->spi_data.forceDv) {
1411
1412 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1413 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1414 unsigned long lflags;
1415 /* Schedule DV if necessary */
1416 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1417 if (!dvtaskQ_active) {
1418 dvtaskQ_active = 1;
1419 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001420 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001422 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 } else {
1424 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1425 }
1426 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1427 }
1428
1429 /* Trying to do DV to this target, extend timeout.
1430 * Wait to issue until flag is clear
1431 */
1432 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1433 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1434 issueCmd = 0;
1435 }
1436
1437 /* Set the DV flags.
1438 */
1439 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
1440 mptscsih_set_dvflags(hd, pScsiReq);
1441
1442 if (!issueCmd)
1443 goto fail;
1444 }
1445 }
1446#endif
1447
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001448 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1450 hd->ioc->name, SCpnt, mf, my_idx));
1451 DBG_DUMP_REQUEST_FRAME(mf)
1452 return 0;
1453
1454 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001455 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1457 mpt_free_msg_frame(hd->ioc, mf);
1458 return SCSI_MLQUEUE_HOST_BUSY;
1459}
1460
1461/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1462/*
1463 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1464 * with a SCSI IO request
1465 * @hd: Pointer to the MPT_SCSI_HOST instance
1466 * @req_idx: Index of the SCSI IO request frame.
1467 *
1468 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1469 * No return.
1470 */
1471static void
1472mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1473{
1474 MPT_FRAME_HDR *chain;
1475 unsigned long flags;
1476 int chain_idx;
1477 int next;
1478
1479 /* Get the first chain index and reset
1480 * tracker state.
1481 */
1482 chain_idx = ioc->ReqToChain[req_idx];
1483 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1484
1485 while (chain_idx != MPT_HOST_NO_CHAIN) {
1486
1487 /* Save the next chain buffer index */
1488 next = ioc->ChainToChain[chain_idx];
1489
1490 /* Free this chain buffer and reset
1491 * tracker
1492 */
1493 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1494
1495 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1496 + (chain_idx * ioc->req_sz));
1497
1498 spin_lock_irqsave(&ioc->FreeQlock, flags);
1499 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1500 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1501
1502 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1503 ioc->name, chain_idx));
1504
1505 /* handle next */
1506 chain_idx = next;
1507 }
1508 return;
1509}
1510
1511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1512/*
1513 * Reset Handling
1514 */
1515
1516/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1517/*
1518 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1519 * Fall through to mpt_HardResetHandler if: not operational, too many
1520 * failed TM requests or handshake failure.
1521 *
1522 * @ioc: Pointer to MPT_ADAPTER structure
1523 * @type: Task Management type
1524 * @target: Logical Target ID for reset (if appropriate)
1525 * @lun: Logical Unit for reset (if appropriate)
1526 * @ctx2abort: Context for the task to be aborted (if appropriate)
1527 *
1528 * Remark: Currently invoked from a non-interrupt thread (_bh).
1529 *
1530 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1531 * will be active.
1532 *
1533 * Returns 0 for SUCCESS or -1 if FAILED.
1534 */
1535static int
1536mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1537{
1538 MPT_ADAPTER *ioc;
1539 int rc = -1;
1540 int doTask = 1;
1541 u32 ioc_raw_state;
1542 unsigned long flags;
1543
1544 /* If FW is being reloaded currently, return success to
1545 * the calling function.
1546 */
1547 if (hd == NULL)
1548 return 0;
1549
1550 ioc = hd->ioc;
1551 if (ioc == NULL) {
1552 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1553 return FAILED;
1554 }
1555 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1556
1557 // SJR - CHECKME - Can we avoid this here?
1558 // (mpt_HardResetHandler has this check...)
1559 spin_lock_irqsave(&ioc->diagLock, flags);
1560 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1561 spin_unlock_irqrestore(&ioc->diagLock, flags);
1562 return FAILED;
1563 }
1564 spin_unlock_irqrestore(&ioc->diagLock, flags);
1565
1566 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1567 * If we time out and not bus reset, then we return a FAILED status to the caller.
1568 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1569 * successful. Otherwise, reload the FW.
1570 */
1571 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1572 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001573 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 "Timed out waiting for last TM (%d) to complete! \n",
1575 hd->ioc->name, hd->tmPending));
1576 return FAILED;
1577 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001578 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 "Timed out waiting for last TM (%d) to complete! \n",
1580 hd->ioc->name, hd->tmPending));
1581 return FAILED;
1582 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001583 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 "Timed out waiting for last TM (%d) to complete! \n",
1585 hd->ioc->name, hd->tmPending));
1586 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1587 return FAILED;
1588
1589 doTask = 0;
1590 }
1591 } else {
1592 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1593 hd->tmPending |= (1 << type);
1594 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1595 }
1596
1597 /* Is operational?
1598 */
1599 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1600
1601#ifdef MPT_DEBUG_RESET
1602 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1603 printk(MYIOC_s_WARN_FMT
1604 "TM Handler: IOC Not operational(0x%x)!\n",
1605 hd->ioc->name, ioc_raw_state);
1606 }
1607#endif
1608
1609 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1610 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1611
1612 /* Isse the Task Mgmt request.
1613 */
1614 if (hd->hard_resets < -1)
1615 hd->hard_resets++;
1616 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1617 if (rc) {
1618 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1619 } else {
1620 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1621 }
1622 }
1623
1624 /* Only fall through to the HRH if this is a bus reset
1625 */
1626 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1627 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1628 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1629 hd->ioc->name));
1630 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1631 }
1632
1633 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1634
1635 return rc;
1636}
1637
1638
1639/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1640/*
1641 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1642 * @hd: Pointer to MPT_SCSI_HOST structure
1643 * @type: Task Management type
1644 * @target: Logical Target ID for reset (if appropriate)
1645 * @lun: Logical Unit for reset (if appropriate)
1646 * @ctx2abort: Context for the task to be aborted (if appropriate)
1647 *
1648 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1649 * or a non-interrupt thread. In the former, must not call schedule().
1650 *
1651 * Not all fields are meaningfull for all task types.
1652 *
1653 * Returns 0 for SUCCESS, -999 for "no msg frames",
1654 * else other non-zero value returned.
1655 */
1656static int
1657mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1658{
1659 MPT_FRAME_HDR *mf;
1660 SCSITaskMgmt_t *pScsiTm;
1661 int ii;
1662 int retval;
1663
1664 /* Return Fail to calling function if no message frames available.
1665 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001666 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1668 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001669 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 }
1671 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1672 hd->ioc->name, mf));
1673
1674 /* Format the Request
1675 */
1676 pScsiTm = (SCSITaskMgmt_t *) mf;
1677 pScsiTm->TargetID = target;
1678 pScsiTm->Bus = channel;
1679 pScsiTm->ChainOffset = 0;
1680 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1681
1682 pScsiTm->Reserved = 0;
1683 pScsiTm->TaskType = type;
1684 pScsiTm->Reserved1 = 0;
1685 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1686 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1687
1688 for (ii= 0; ii < 8; ii++) {
1689 pScsiTm->LUN[ii] = 0;
1690 }
1691 pScsiTm->LUN[1] = lun;
1692
1693 for (ii=0; ii < 7; ii++)
1694 pScsiTm->Reserved2[ii] = 0;
1695
1696 pScsiTm->TaskMsgContext = ctx2abort;
1697
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001698 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1699 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1702
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001703 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1705 CAN_SLEEP)) != 0) {
1706 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1707 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1708 hd->ioc, mf));
1709 mpt_free_msg_frame(hd->ioc, mf);
1710 return retval;
1711 }
1712
1713 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1714 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1715 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1716 hd->ioc, mf));
1717 mpt_free_msg_frame(hd->ioc, mf);
1718 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1719 hd->ioc->name));
1720 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1721 }
1722
1723 return retval;
1724}
1725
1726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1727/**
1728 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1729 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1730 *
1731 * (linux scsi_host_template.eh_abort_handler routine)
1732 *
1733 * Returns SUCCESS or FAILED.
1734 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001735int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736mptscsih_abort(struct scsi_cmnd * SCpnt)
1737{
1738 MPT_SCSI_HOST *hd;
1739 MPT_ADAPTER *ioc;
1740 MPT_FRAME_HDR *mf;
1741 u32 ctx2abort;
1742 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001743 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
1745 /* If we can't locate our host adapter structure, return FAILED status.
1746 */
1747 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1748 SCpnt->result = DID_RESET << 16;
1749 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001750 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 "Can't locate host! (sc=%p)\n",
1752 SCpnt));
1753 return FAILED;
1754 }
1755
1756 ioc = hd->ioc;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001757 if (hd->resetPending) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 return FAILED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 if (hd->timeouts < -1)
1762 hd->timeouts++;
1763
1764 /* Find this command
1765 */
1766 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001767 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 * Do OS callback.
1769 */
1770 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001771 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 "Command not in the active list! (sc=%p)\n",
1773 hd->ioc->name, SCpnt));
1774 return SUCCESS;
1775 }
1776
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001777 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1778 hd->ioc->name, SCpnt);
1779 scsi_print_command(SCpnt);
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1782 * (the IO to be ABORT'd)
1783 *
1784 * NOTE: Since we do not byteswap MsgContext, we do not
1785 * swap it here either. It is an opaque cookie to
1786 * the controller, so it does not matter. -DaveM
1787 */
1788 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1789 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1790
1791 hd->abortSCpnt = SCpnt;
1792
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001793 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001795 ctx2abort, 2 /* 2 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001797 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1798 hd->ioc->name,
1799 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001801 if (retval == 0)
1802 return SUCCESS;
1803
1804 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 hd->tmPending = 0;
1806 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001808 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809}
1810
1811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1812/**
1813 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1814 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1815 *
1816 * (linux scsi_host_template.eh_dev_reset_handler routine)
1817 *
1818 * Returns SUCCESS or FAILED.
1819 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001820int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1822{
1823 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001824 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
1826 /* If we can't locate our host adapter structure, return FAILED status.
1827 */
1828 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001829 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 "Can't locate host! (sc=%p)\n",
1831 SCpnt));
1832 return FAILED;
1833 }
1834
1835 if (hd->resetPending)
1836 return FAILED;
1837
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001838 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001840 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 SCpnt->device->channel, SCpnt->device->id,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001844 0, 0, 5 /* 5 second timeout */);
1845
1846 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1847 hd->ioc->name,
1848 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1849
1850 if (retval == 0)
1851 return SUCCESS;
1852
1853 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 hd->tmPending = 0;
1855 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001857 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858}
1859
1860/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1861/**
1862 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1863 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1864 *
1865 * (linux scsi_host_template.eh_bus_reset_handler routine)
1866 *
1867 * Returns SUCCESS or FAILED.
1868 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001869int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1871{
1872 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001873 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 /* If we can't locate our host adapter structure, return FAILED status.
1876 */
1877 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001878 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 "Can't locate host! (sc=%p)\n",
1880 SCpnt ) );
1881 return FAILED;
1882 }
1883
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001884 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001886 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 if (hd->timeouts < -1)
1889 hd->timeouts++;
1890
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001891 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1892 SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001894 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1895 hd->ioc->name,
1896 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1897
1898 if (retval == 0)
1899 return SUCCESS;
1900
1901 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 hd->tmPending = 0;
1903 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001905 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906}
1907
1908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1909/**
1910 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1911 * new_eh variant
1912 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1913 *
1914 * (linux scsi_host_template.eh_host_reset_handler routine)
1915 *
1916 * Returns SUCCESS or FAILED.
1917 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001918int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1920{
1921 MPT_SCSI_HOST * hd;
1922 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924 /* If we can't locate the host to reset, then we failed. */
1925 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001926 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 "Can't locate host! (sc=%p)\n",
1928 SCpnt ) );
1929 return FAILED;
1930 }
1931
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001932 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 hd->ioc->name, SCpnt);
1934
1935 /* If our attempts to reset the host failed, then return a failed
1936 * status. The host will be taken off line by the SCSI mid-layer.
1937 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1939 status = FAILED;
1940 } else {
1941 /* Make sure TM pending is cleared and TM state is set to
1942 * NONE.
1943 */
1944 hd->tmPending = 0;
1945 hd->tmState = TM_STATE_NONE;
1946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001948 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 "Status = %s\n",
1950 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1951
1952 return status;
1953}
1954
1955/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1956/**
1957 * mptscsih_tm_pending_wait - wait for pending task management request to
1958 * complete.
1959 * @hd: Pointer to MPT host structure.
1960 *
1961 * Returns {SUCCESS,FAILED}.
1962 */
1963static int
1964mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1965{
1966 unsigned long flags;
1967 int loop_count = 4 * 10; /* Wait 10 seconds */
1968 int status = FAILED;
1969
1970 do {
1971 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1972 if (hd->tmState == TM_STATE_NONE) {
1973 hd->tmState = TM_STATE_IN_PROGRESS;
1974 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001976 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 break;
1978 }
1979 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1980 msleep(250);
1981 } while (--loop_count);
1982
1983 return status;
1984}
1985
1986/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1987/**
1988 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1989 * @hd: Pointer to MPT host structure.
1990 *
1991 * Returns {SUCCESS,FAILED}.
1992 */
1993static int
1994mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1995{
1996 unsigned long flags;
1997 int loop_count = 4 * timeout;
1998 int status = FAILED;
1999
2000 do {
2001 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2002 if(hd->tmPending == 0) {
2003 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002004 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 break;
2006 }
2007 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2008 msleep_interruptible(250);
2009 } while (--loop_count);
2010
2011 return status;
2012}
2013
2014/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2015/**
2016 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2017 * @ioc: Pointer to MPT_ADAPTER structure
2018 * @mf: Pointer to SCSI task mgmt request frame
2019 * @mr: Pointer to SCSI task mgmt reply frame
2020 *
2021 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2022 * of any SCSI task management request.
2023 * This routine is registered with the MPT (base) driver at driver
2024 * load/init time via the mpt_register() API call.
2025 *
2026 * Returns 1 indicating alloc'd request frame ptr should be freed.
2027 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002028int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2030{
2031 SCSITaskMgmtReply_t *pScsiTmReply;
2032 SCSITaskMgmt_t *pScsiTmReq;
2033 MPT_SCSI_HOST *hd;
2034 unsigned long flags;
2035 u16 iocstatus;
2036 u8 tmType;
2037
2038 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2039 ioc->name, mf, mr));
2040 if (ioc->sh) {
2041 /* Depending on the thread, a timer is activated for
2042 * the TM request. Delete this timer on completion of TM.
2043 * Decrement count of outstanding TM requests.
2044 */
2045 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2046 } else {
2047 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2048 ioc->name));
2049 return 1;
2050 }
2051
2052 if (mr == NULL) {
2053 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2054 ioc->name, mf));
2055 return 1;
2056 } else {
2057 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2058 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2059
2060 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2061 tmType = pScsiTmReq->TaskType;
2062
2063 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2064 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2065 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2066
2067 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2068 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2069 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2070 /* Error? (anything non-zero?) */
2071 if (iocstatus) {
2072
2073 /* clear flags and continue.
2074 */
2075 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2076 hd->abortSCpnt = NULL;
2077
2078 /* If an internal command is present
2079 * or the TM failed - reload the FW.
2080 * FC FW may respond FAILED to an ABORT
2081 */
2082 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2083 if ((hd->cmdPtr) ||
2084 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2085 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2086 printk((KERN_WARNING
2087 " Firmware Reload FAILED!!\n"));
2088 }
2089 }
2090 }
2091 } else {
2092 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2093
2094 hd->abortSCpnt = NULL;
2095
2096 }
2097 }
2098
2099 spin_lock_irqsave(&ioc->FreeQlock, flags);
2100 hd->tmPending = 0;
2101 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2102 hd->tmState = TM_STATE_NONE;
2103
2104 return 1;
2105}
2106
2107/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2108/*
2109 * This is anyones guess quite frankly.
2110 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002111int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2113 sector_t capacity, int geom[])
2114{
2115 int heads;
2116 int sectors;
2117 sector_t cylinders;
2118 ulong dummy;
2119
2120 heads = 64;
2121 sectors = 32;
2122
2123 dummy = heads * sectors;
2124 cylinders = capacity;
2125 sector_div(cylinders,dummy);
2126
2127 /*
2128 * Handle extended translation size for logical drives
2129 * > 1Gb
2130 */
2131 if ((ulong)capacity >= 0x200000) {
2132 heads = 255;
2133 sectors = 63;
2134 dummy = heads * sectors;
2135 cylinders = capacity;
2136 sector_div(cylinders,dummy);
2137 }
2138
2139 /* return result */
2140 geom[0] = heads;
2141 geom[1] = sectors;
2142 geom[2] = cylinders;
2143
2144 dprintk((KERN_NOTICE
2145 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2146 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2147
2148 return 0;
2149}
2150
2151/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2152/*
2153 * OS entry point to allow host driver to alloc memory
2154 * for each scsi device. Called once per device the bus scan.
2155 * Return non-zero if allocation fails.
2156 * Init memory once per id (not LUN).
2157 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002158int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159mptscsih_slave_alloc(struct scsi_device *device)
2160{
2161 struct Scsi_Host *host = device->host;
2162 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2163 VirtDevice *vdev;
2164 uint target = device->id;
2165
2166 if (hd == NULL)
2167 return -ENODEV;
2168
2169 if ((vdev = hd->Targets[target]) != NULL)
2170 goto out;
2171
2172 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
2173 if (!vdev) {
2174 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2175 hd->ioc->name, sizeof(VirtDevice));
2176 return -ENOMEM;
2177 }
2178
2179 memset(vdev, 0, sizeof(VirtDevice));
2180 vdev->tflags = MPT_TARGET_FLAGS_Q_YES;
2181 vdev->ioc_id = hd->ioc->id;
2182 vdev->target_id = device->id;
2183 vdev->bus_id = device->channel;
2184 vdev->raidVolume = 0;
2185 hd->Targets[device->id] = vdev;
2186 if (hd->ioc->bus_type == SCSI) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002187 if (hd->ioc->raid_data.isRaid & (1 << device->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 vdev->raidVolume = 1;
2189 ddvtprintk((KERN_INFO
2190 "RAID Volume @ id %d\n", device->id));
2191 }
2192 } else {
2193 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2194 }
2195
2196 out:
2197 vdev->num_luns++;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002198 device->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 return 0;
2200}
2201
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202/*
2203 * OS entry point to allow for host driver to free allocated memory
2204 * Called if no device present or device being unloaded
2205 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002206void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207mptscsih_slave_destroy(struct scsi_device *device)
2208{
2209 struct Scsi_Host *host = device->host;
2210 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2211 VirtDevice *vdev;
2212 uint target = device->id;
2213 uint lun = device->lun;
2214
2215 if (hd == NULL)
2216 return;
2217
2218 mptscsih_search_running_cmds(hd, target, lun);
2219
2220 vdev = hd->Targets[target];
2221 vdev->luns[0] &= ~(1 << lun);
2222 if (--vdev->num_luns)
2223 return;
2224
2225 kfree(hd->Targets[target]);
2226 hd->Targets[target] = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 if (hd->ioc->bus_type == SCSI) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002229 if (mptscsih_is_phys_disk(hd->ioc, target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2231 } else {
2232 hd->ioc->spi_data.dvStatus[target] =
2233 MPT_SCSICFG_NEGOTIATE;
2234
2235 if (!hd->negoNvram) {
2236 hd->ioc->spi_data.dvStatus[target] |=
2237 MPT_SCSICFG_DV_NOT_DONE;
2238 }
2239 }
2240 }
2241}
2242
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2244/*
2245 * mptscsih_change_queue_depth - This function will set a devices queue depth
2246 * @sdev: per scsi_device pointer
2247 * @qdepth: requested queue depth
2248 *
2249 * Adding support for new 'change_queue_depth' api.
2250*/
2251int
2252mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253{
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002254 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2255 VirtDevice *pTarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 int max_depth;
2257 int tagged;
2258
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002259 if (hd == NULL)
2260 return 0;
2261 if (!(pTarget = hd->Targets[sdev->id]))
2262 return 0;
2263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 if (hd->ioc->bus_type == SCSI) {
2265 if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2266 if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
2267 max_depth = 1;
2268 else if (((pTarget->inq_data[0] & 0x1f) == 0x00) &&
2269 (pTarget->minSyncFactor <= MPT_ULTRA160 ))
2270 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2271 else
2272 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2273 } else {
2274 /* error case - No Inq. Data */
2275 max_depth = 1;
2276 }
2277 } else
2278 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2279
2280 if (qdepth > max_depth)
2281 qdepth = max_depth;
2282 if (qdepth == 1)
2283 tagged = 0;
2284 else
2285 tagged = MSG_SIMPLE_TAG;
2286
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002287 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2288 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289}
2290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291/*
2292 * OS entry point to adjust the queue_depths on a per-device basis.
2293 * Called once per device the bus scan. Use it to force the queue_depth
2294 * member to 1 if a device does not support Q tags.
2295 * Return non-zero if fails.
2296 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002297int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298mptscsih_slave_configure(struct scsi_device *device)
2299{
2300 struct Scsi_Host *sh = device->host;
2301 VirtDevice *pTarget;
2302 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2303
2304 if ((hd == NULL) || (hd->Targets == NULL)) {
2305 return 0;
2306 }
2307
2308 dsprintk((MYIOC_s_INFO_FMT
2309 "device @ %p, id=%d, LUN=%d, channel=%d\n",
2310 hd->ioc->name, device, device->id, device->lun, device->channel));
2311 dsprintk((MYIOC_s_INFO_FMT
2312 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2313 hd->ioc->name, device->sdtr, device->wdtr,
2314 device->ppr, device->inquiry_len));
2315
2316 if (device->id > sh->max_id) {
2317 /* error case, should never happen */
2318 scsi_adjust_queue_depth(device, 0, 1);
2319 goto slave_configure_exit;
2320 }
2321
2322 pTarget = hd->Targets[device->id];
2323
2324 if (pTarget == NULL) {
2325 /* Driver doesn't know about this device.
2326 * Kernel may generate a "Dummy Lun 0" which
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002327 * may become a real Lun if a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 * "scsi add-single-device" command is executed
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002329 * while the driver is active (hot-plug a
2330 * device). LSI Raid controllers need
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 * queue_depth set to DEV_HIGH for this reason.
2332 */
2333 scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
2334 MPT_SCSI_CMD_PER_DEV_HIGH);
2335 goto slave_configure_exit;
2336 }
2337
2338 mptscsih_initTarget(hd, device->channel, device->id, device->lun,
2339 device->inquiry, device->inquiry_len );
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002340 mptscsih_change_queue_depth(device, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
2342 dsprintk((MYIOC_s_INFO_FMT
2343 "Queue depth=%d, tflags=%x\n",
2344 hd->ioc->name, device->queue_depth, pTarget->tflags));
2345
2346 dsprintk((MYIOC_s_INFO_FMT
2347 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2348 hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor));
2349
2350slave_configure_exit:
2351
2352 dsprintk((MYIOC_s_INFO_FMT
2353 "tagged %d, simple %d, ordered %d\n",
2354 hd->ioc->name,device->tagged_supported, device->simple_tags,
2355 device->ordered_tags));
2356
2357 return 0;
2358}
2359
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2361/*
2362 * Private routines...
2363 */
2364
2365/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2366/* Utility function to copy sense data from the scsi_cmnd buffer
2367 * to the FC and SCSI target structures.
2368 *
2369 */
2370static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002371mptscsih_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 -07002372{
2373 VirtDevice *target;
2374 SCSIIORequest_t *pReq;
2375 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
2376 int index;
2377
2378 /* Get target structure
2379 */
2380 pReq = (SCSIIORequest_t *) mf;
2381 index = (int) pReq->TargetID;
2382 target = hd->Targets[index];
2383
2384 if (sense_count) {
2385 u8 *sense_data;
2386 int req_index;
2387
2388 /* Copy the sense received into the scsi command block. */
2389 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2390 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2391 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2392
2393 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2394 */
2395 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2396 if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
2397 int idx;
2398 MPT_ADAPTER *ioc = hd->ioc;
2399
2400 idx = ioc->eventContext % ioc->eventLogSize;
2401 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2402 ioc->events[idx].eventContext = ioc->eventContext;
2403
2404 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2405 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
2406 (pReq->Bus << 8) || pReq->TargetID;
2407
2408 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2409
2410 ioc->eventContext++;
2411 }
2412 }
2413 } else {
2414 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2415 hd->ioc->name));
2416 }
2417}
2418
2419static u32
2420SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2421{
2422 MPT_SCSI_HOST *hd;
2423 int i;
2424
2425 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2426
2427 for (i = 0; i < hd->ioc->req_depth; i++) {
2428 if (hd->ScsiLookup[i] == sc) {
2429 return i;
2430 }
2431 }
2432
2433 return -1;
2434}
2435
2436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002437int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2439{
2440 MPT_SCSI_HOST *hd;
2441 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002442 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 dtmprintk((KERN_WARNING MYNAM
2445 ": IOC %s_reset routed to SCSI host driver!\n",
2446 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2447 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2448
2449 /* If a FW reload request arrives after base installed but
2450 * before all scsi hosts have been attached, then an alt_ioc
2451 * may have a NULL sh pointer.
2452 */
2453 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2454 return 0;
2455 else
2456 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2457
2458 if (reset_phase == MPT_IOC_SETUP_RESET) {
2459 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2460
2461 /* Clean Up:
2462 * 1. Set Hard Reset Pending Flag
2463 * All new commands go to doneQ
2464 */
2465 hd->resetPending = 1;
2466
2467 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2468 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2469
2470 /* 2. Flush running commands
2471 * Clean ScsiLookup (and associated memory)
2472 * AND clean mytaskQ
2473 */
2474
2475 /* 2b. Reply to OS all known outstanding I/O commands.
2476 */
2477 mptscsih_flush_running_cmds(hd);
2478
2479 /* 2c. If there was an internal command that
2480 * has not completed, configuration or io request,
2481 * free these resources.
2482 */
2483 if (hd->cmdPtr) {
2484 del_timer(&hd->timer);
2485 mpt_free_msg_frame(ioc, hd->cmdPtr);
2486 }
2487
2488 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2489
2490 } else {
2491 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2492
2493 /* Once a FW reload begins, all new OS commands are
2494 * redirected to the doneQ w/ a reset status.
2495 * Init all control structures.
2496 */
2497
2498 /* ScsiLookup initialization
2499 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002500 for (ii=0; ii < hd->ioc->req_depth; ii++)
2501 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
2503 /* 2. Chain Buffer initialization
2504 */
2505
2506 /* 4. Renegotiate to all devices, if SCSI
2507 */
2508 if (ioc->bus_type == SCSI) {
2509 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2510 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2511 }
2512
2513 /* 5. Enable new commands to be posted
2514 */
2515 spin_lock_irqsave(&ioc->FreeQlock, flags);
2516 hd->tmPending = 0;
2517 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2518 hd->resetPending = 0;
2519 hd->tmState = TM_STATE_NONE;
2520
2521 /* 6. If there was an internal command,
2522 * wake this process up.
2523 */
2524 if (hd->cmdPtr) {
2525 /*
2526 * Wake up the original calling thread
2527 */
2528 hd->pLocal = &hd->localReply;
2529 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002530 hd->scandv_wait_done = 1;
2531 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 hd->cmdPtr = NULL;
2533 }
2534
2535 /* 7. Set flag to force DV and re-read IOC Page 3
2536 */
2537 if (ioc->bus_type == SCSI) {
2538 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2539 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2540 }
2541
2542 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2543
2544 }
2545
2546 return 1; /* currently means nothing really */
2547}
2548
2549/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002550/* work queue thread to clear the persitency table */
2551static void
2552mptscsih_sas_persist_clear_table(void * arg)
2553{
2554 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
2555
2556 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2557}
2558
2559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002560int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2562{
2563 MPT_SCSI_HOST *hd;
2564 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2565
2566 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2567 ioc->name, event));
2568
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002569 if (ioc->sh == NULL ||
2570 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2571 return 1;
2572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 switch (event) {
2574 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2575 /* FIXME! */
2576 break;
2577 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2578 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002579 if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1))
2580 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 break;
2582 case MPI_EVENT_LOGOUT: /* 09 */
2583 /* FIXME! */
2584 break;
2585
2586 /*
2587 * CHECKME! Don't think we need to do
2588 * anything for these, but...
2589 */
2590 case MPI_EVENT_RESCAN: /* 06 */
2591 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2592 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2593 /*
2594 * CHECKME! Falling thru...
2595 */
2596 break;
2597
2598 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002599 {
2600 pMpiEventDataRaid_t pRaidEventData =
2601 (pMpiEventDataRaid_t) pEvReply->Data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002603 /* Domain Validation Needed */
2604 if (ioc->bus_type == SCSI &&
2605 pRaidEventData->ReasonCode ==
2606 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2607 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002609 break;
2610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002612 /* Persistent table is full. */
2613 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2614 INIT_WORK(&mptscsih_persistTask,
2615 mptscsih_sas_persist_clear_table,(void *)ioc);
2616 schedule_work(&mptscsih_persistTask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 break;
2618
2619 case MPI_EVENT_NONE: /* 00 */
2620 case MPI_EVENT_LOG_DATA: /* 01 */
2621 case MPI_EVENT_STATE_CHANGE: /* 02 */
2622 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2623 default:
2624 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2625 break;
2626 }
2627
2628 return 1; /* currently means nothing really */
2629}
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2632/*
2633 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2634 * @hd: Pointer to MPT_SCSI_HOST structure
2635 * @bus_id: Bus number (?)
2636 * @target_id: SCSI target id
2637 * @lun: SCSI LUN id
2638 * @data: Pointer to data
2639 * @dlen: Number of INQUIRY bytes
2640 *
2641 * NOTE: It's only SAFE to call this routine if data points to
2642 * sane & valid STANDARD INQUIRY data!
2643 *
2644 * Allocate and initialize memory for this target.
2645 * Save inquiry data.
2646 *
2647 */
2648static void
2649mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
2650{
2651 int indexed_lun, lun_index;
2652 VirtDevice *vdev;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002653 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 char data_56;
2655
2656 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
2657 hd->ioc->name, bus_id, target_id, lun, hd));
2658
2659 /*
2660 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2661 * (i.e. The targer is capable of supporting the specified peripheral device type
2662 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002663 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 * capable of supporting a physical device on this logical unit). This is to work
2665 * around a bug in th emid-layer in some distributions in which the mid-layer will
2666 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2667 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002668 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 /* Is LUN supported? If so, upper 2 bits will be 0
2672 * in first byte of inquiry data.
2673 */
2674 if (data[0] & 0xe0)
2675 return;
2676
2677 if ((vdev = hd->Targets[target_id]) == NULL) {
2678 return;
2679 }
2680
2681 lun_index = (lun >> 5); /* 32 luns per lun_index */
2682 indexed_lun = (lun % 32);
2683 vdev->luns[lun_index] |= (1 << indexed_lun);
2684
2685 if (hd->ioc->bus_type == SCSI) {
2686 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2687 /* Treat all Processors as SAF-TE if
2688 * command line option is set */
2689 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2690 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2691 }else if ((data[0] == TYPE_PROCESSOR) &&
2692 !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2693 if ( dlen > 49 ) {
2694 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2695 if ( data[44] == 'S' &&
2696 data[45] == 'A' &&
2697 data[46] == 'F' &&
2698 data[47] == '-' &&
2699 data[48] == 'T' &&
2700 data[49] == 'E' ) {
2701 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2702 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2703 }
2704 }
2705 }
2706 if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2707 if ( dlen > 8 ) {
2708 memcpy (vdev->inq_data, data, 8);
2709 } else {
2710 memcpy (vdev->inq_data, data, dlen);
2711 }
2712
2713 /* If have not done DV, set the DV flag.
2714 */
2715 pSpi = &hd->ioc->spi_data;
2716 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2717 if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
2718 pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
2719 }
2720
2721 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2722
2723
2724 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2725 if (dlen > 56) {
2726 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2727 /* Update the target capabilities
2728 */
2729 data_56 = data[56];
2730 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2731 }
2732 }
2733 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2734 } else {
2735 /* Initial Inquiry may not request enough data bytes to
2736 * obtain byte 57. DV will; if target doesn't return
2737 * at least 57 bytes, data[56] will be zero. */
2738 if (dlen > 56) {
2739 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2740 /* Update the target capabilities
2741 */
2742 data_56 = data[56];
2743 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2744 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2745 }
2746 }
2747 }
2748 }
2749}
2750
2751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2752/*
2753 * Update the target negotiation parameters based on the
2754 * the Inquiry data, adapter capabilities, and NVRAM settings.
2755 *
2756 */
2757static void
2758mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
2759{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002760 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 int id = (int) target->target_id;
2762 int nvram;
2763 VirtDevice *vdev;
2764 int ii;
2765 u8 width = MPT_NARROW;
2766 u8 factor = MPT_ASYNC;
2767 u8 offset = 0;
2768 u8 version, nfactor;
2769 u8 noQas = 1;
2770
2771 target->negoFlags = pspi_data->noQas;
2772
2773 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2774 * support. If available, default QAS to off and allow enabling.
2775 * If not available, default QAS to on, turn off for non-disks.
2776 */
2777
2778 /* Set flags based on Inquiry data
2779 */
2780 version = target->inq_data[2] & 0x07;
2781 if (version < 2) {
2782 width = 0;
2783 factor = MPT_ULTRA2;
2784 offset = pspi_data->maxSyncOffset;
2785 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2786 } else {
2787 if (target->inq_data[7] & 0x20) {
2788 width = 1;
2789 }
2790
2791 if (target->inq_data[7] & 0x10) {
2792 factor = pspi_data->minSyncFactor;
2793 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2794 /* bits 2 & 3 show Clocking support */
2795 if ((byte56 & 0x0C) == 0)
2796 factor = MPT_ULTRA2;
2797 else {
2798 if ((byte56 & 0x03) == 0)
2799 factor = MPT_ULTRA160;
2800 else {
2801 factor = MPT_ULTRA320;
2802 if (byte56 & 0x02)
2803 {
2804 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2805 noQas = 0;
2806 }
2807 if (target->inq_data[0] == TYPE_TAPE) {
2808 if (byte56 & 0x01)
2809 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2810 }
2811 }
2812 }
2813 } else {
2814 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2815 noQas = 0;
2816 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002817
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 offset = pspi_data->maxSyncOffset;
2819
2820 /* If RAID, never disable QAS
2821 * else if non RAID, do not disable
2822 * QAS if bit 1 is set
2823 * bit 1 QAS support, non-raid only
2824 * bit 0 IU support
2825 */
2826 if (target->raidVolume == 1) {
2827 noQas = 0;
2828 }
2829 } else {
2830 factor = MPT_ASYNC;
2831 offset = 0;
2832 }
2833 }
2834
2835 if ( (target->inq_data[7] & 0x02) == 0) {
2836 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2837 }
2838
2839 /* Update tflags based on NVRAM settings. (SCSI only)
2840 */
2841 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2842 nvram = pspi_data->nvram[id];
2843 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2844
2845 if (width)
2846 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2847
2848 if (offset > 0) {
2849 /* Ensure factor is set to the
2850 * maximum of: adapter, nvram, inquiry
2851 */
2852 if (nfactor) {
2853 if (nfactor < pspi_data->minSyncFactor )
2854 nfactor = pspi_data->minSyncFactor;
2855
2856 factor = max(factor, nfactor);
2857 if (factor == MPT_ASYNC)
2858 offset = 0;
2859 } else {
2860 offset = 0;
2861 factor = MPT_ASYNC;
2862 }
2863 } else {
2864 factor = MPT_ASYNC;
2865 }
2866 }
2867
2868 /* Make sure data is consistent
2869 */
2870 if ((!width) && (factor < MPT_ULTRA2)) {
2871 factor = MPT_ULTRA2;
2872 }
2873
2874 /* Save the data to the target structure.
2875 */
2876 target->minSyncFactor = factor;
2877 target->maxOffset = offset;
2878 target->maxWidth = width;
2879
2880 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2881
2882 /* Disable unused features.
2883 */
2884 if (!width)
2885 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2886
2887 if (!offset)
2888 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2889
2890 if ( factor > MPT_ULTRA320 )
2891 noQas = 0;
2892
2893 /* GEM, processor WORKAROUND
2894 */
2895 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2896 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2897 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2898 } else {
2899 if (noQas && (pspi_data->noQas == 0)) {
2900 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2901 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2902
2903 /* Disable QAS in a mixed configuration case
2904 */
2905
2906 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2907 for (ii = 0; ii < id; ii++) {
2908 if ( (vdev = hd->Targets[ii]) ) {
2909 vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2910 mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 }
2913 }
2914 }
2915
2916 /* Write SDP1 on this I/O to this target */
2917 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2918 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2919 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2920 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2921 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2922 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2923 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2924 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2925 }
2926}
2927
2928/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2929/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
2930 * Else set the NEED_DV flag after Read Capacity Issued (disks)
2931 * or Mode Sense (cdroms).
2932 *
2933 * Tapes, initTarget will set this flag on completion of Inquiry command.
2934 * Called only if DV_NOT_DONE flag is set
2935 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002936static void
2937mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002939 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 u8 cmd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002941 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002943 ddvtprintk((MYIOC_s_NOTE_FMT
2944 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
2945 hd->ioc->name, pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0]));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002946
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
2948 return;
2949
2950 cmd = pReq->CDB[0];
2951
2952 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002953 pSpi = &ioc->spi_data;
2954 if ((ioc->raid_data.isRaid & (1 << pReq->TargetID)) && ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 /* Set NEED_DV for all hidden disks
2956 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002957 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
2958 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 while (numPDisk) {
2961 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
2962 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
2963 pPDisk++;
2964 numPDisk--;
2965 }
2966 }
2967 pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
2968 ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
2969 }
2970}
2971
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002972/* mptscsih_raid_set_dv_flags()
2973 *
2974 * New or replaced disk. Set DV flag and schedule DV.
2975 */
2976static void
2977mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
2978{
2979 MPT_ADAPTER *ioc = hd->ioc;
2980 SpiCfgData *pSpi = &ioc->spi_data;
2981 Ioc3PhysDisk_t *pPDisk;
2982 int numPDisk;
2983
2984 if (hd->negoNvram != 0)
2985 return;
2986
2987 ddvtprintk(("DV requested for phys disk id %d\n", id));
2988 if (ioc->raid_data.pIocPg3) {
2989 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
2990 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
2991 while (numPDisk) {
2992 if (id == pPDisk->PhysDiskNum) {
2993 pSpi->dvStatus[pPDisk->PhysDiskID] =
2994 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
2995 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
2996 ddvtprintk(("NEED_DV set for phys disk id %d\n",
2997 pPDisk->PhysDiskID));
2998 break;
2999 }
3000 pPDisk++;
3001 numPDisk--;
3002 }
3003
3004 if (numPDisk == 0) {
3005 /* The physical disk that needs DV was not found
3006 * in the stored IOC Page 3. The driver must reload
3007 * this page. DV routine will set the NEED_DV flag for
3008 * all phys disks that have DV_NOT_DONE set.
3009 */
3010 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
3011 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
3012 }
3013 }
3014}
3015
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3017/*
3018 * If no Target, bus reset on 1st I/O. Set the flag to
3019 * prevent any future negotiations to this device.
3020 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003021static void
3022mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023{
3024
3025 if ((hd->Targets) && (hd->Targets[target_id] == NULL))
3026 hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
3027
3028 return;
3029}
3030
3031/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3032/*
3033 * SCSI Config Page functionality ...
3034 */
3035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3036/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
3037 * based on width, factor and offset parameters.
3038 * @width: bus width
3039 * @factor: sync factor
3040 * @offset: sync offset
3041 * @requestedPtr: pointer to requested values (updated)
3042 * @configurationPtr: pointer to configuration values (updated)
3043 * @flags: flags to block WDTR or SDTR negotiation
3044 *
3045 * Return: None.
3046 *
3047 * Remark: Called by writeSDP1 and _dv_params
3048 */
3049static void
3050mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3051{
3052 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3053 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3054
3055 *configurationPtr = 0;
3056 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3057 *requestedPtr |= (offset << 16) | (factor << 8);
3058
3059 if (width && offset && !nowide && !nosync) {
3060 if (factor < MPT_ULTRA160) {
3061 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3062 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3063 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3064 if (flags & MPT_TAPE_NEGO_IDP)
3065 *requestedPtr |= 0x08000000;
3066 } else if (factor < MPT_ULTRA2) {
3067 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3068 }
3069 }
3070
3071 if (nowide)
3072 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3073
3074 if (nosync)
3075 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3076
3077 return;
3078}
3079
3080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3081/* mptscsih_writeSDP1 - write SCSI Device Page 1
3082 * @hd: Pointer to a SCSI Host Strucutre
3083 * @portnum: IOC port number
3084 * @target_id: writeSDP1 for single ID
3085 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3086 *
3087 * Return: -EFAULT if read of config page header fails
3088 * or 0 if success.
3089 *
3090 * Remark: If a target has been found, the settings from the
3091 * target structure are used, else the device is set
3092 * to async/narrow.
3093 *
3094 * Remark: Called during init and after a FW reload.
3095 * Remark: We do not wait for a return, write pages sequentially.
3096 */
3097static int
3098mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3099{
3100 MPT_ADAPTER *ioc = hd->ioc;
3101 Config_t *pReq;
3102 SCSIDevicePage1_t *pData;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003103 VirtDevice *pTarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 MPT_FRAME_HDR *mf;
3105 dma_addr_t dataDma;
3106 u16 req_idx;
3107 u32 frameOffset;
3108 u32 requested, configuration, flagsLength;
3109 int ii, nvram;
3110 int id = 0, maxid = 0;
3111 u8 width;
3112 u8 factor;
3113 u8 offset;
3114 u8 bus = 0;
3115 u8 negoFlags;
3116 u8 maxwidth, maxoffset, maxfactor;
3117
3118 if (ioc->spi_data.sdp1length == 0)
3119 return 0;
3120
3121 if (flags & MPT_SCSICFG_ALL_IDS) {
3122 id = 0;
3123 maxid = ioc->sh->max_id - 1;
3124 } else if (ioc->sh) {
3125 id = target_id;
3126 maxid = min_t(int, id, ioc->sh->max_id - 1);
3127 }
3128
3129 for (; id <= maxid; id++) {
3130
3131 if (id == ioc->pfacts[portnum].PortSCSIID)
3132 continue;
3133
3134 /* Use NVRAM to get adapter and target maximums
3135 * Data over-riden by target structure information, if present
3136 */
3137 maxwidth = ioc->spi_data.maxBusWidth;
3138 maxoffset = ioc->spi_data.maxSyncOffset;
3139 maxfactor = ioc->spi_data.minSyncFactor;
3140 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3141 nvram = ioc->spi_data.nvram[id];
3142
3143 if (maxwidth)
3144 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3145
3146 if (maxoffset > 0) {
3147 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3148 if (maxfactor == 0) {
3149 /* Key for async */
3150 maxfactor = MPT_ASYNC;
3151 maxoffset = 0;
3152 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3153 maxfactor = ioc->spi_data.minSyncFactor;
3154 }
3155 } else
3156 maxfactor = MPT_ASYNC;
3157 }
3158
3159 /* Set the negotiation flags.
3160 */
3161 negoFlags = ioc->spi_data.noQas;
3162 if (!maxwidth)
3163 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3164
3165 if (!maxoffset)
3166 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3167
3168 if (flags & MPT_SCSICFG_USE_NVRAM) {
3169 width = maxwidth;
3170 factor = maxfactor;
3171 offset = maxoffset;
3172 } else {
3173 width = 0;
3174 factor = MPT_ASYNC;
3175 offset = 0;
3176 //negoFlags = 0;
3177 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3178 }
3179
3180 /* If id is not a raid volume, get the updated
3181 * transmission settings from the target structure.
3182 */
3183 if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3184 width = pTarget->maxWidth;
3185 factor = pTarget->minSyncFactor;
3186 offset = pTarget->maxOffset;
3187 negoFlags = pTarget->negoFlags;
3188 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003189
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3191 /* Force to async and narrow if DV has not been executed
3192 * for this ID
3193 */
3194 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3195 width = 0;
3196 factor = MPT_ASYNC;
3197 offset = 0;
3198 }
3199#endif
3200
3201 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003202 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 mptscsih_setDevicePage1Flags(width, factor, offset,
3205 &requested, &configuration, negoFlags);
3206 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3207 target_id, width, factor, offset, negoFlags, requested, configuration));
3208
3209 /* Get a MF for this command.
3210 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003211 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003212 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3213 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 return -EAGAIN;
3215 }
3216
3217 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3218 hd->ioc->name, mf, id, requested, configuration));
3219
3220
3221 /* Set the request and the data pointers.
3222 * Request takes: 36 bytes (32 bit SGE)
3223 * SCSI Device Page 1 requires 16 bytes
3224 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3225 * and MF size >= 64 bytes.
3226 * Place data at end of MF.
3227 */
3228 pReq = (Config_t *)mf;
3229
3230 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3231 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3232
3233 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3234 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3235
3236 /* Complete the request frame (same for all requests).
3237 */
3238 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3239 pReq->Reserved = 0;
3240 pReq->ChainOffset = 0;
3241 pReq->Function = MPI_FUNCTION_CONFIG;
3242 pReq->ExtPageLength = 0;
3243 pReq->ExtPageType = 0;
3244 pReq->MsgFlags = 0;
3245 for (ii=0; ii < 8; ii++) {
3246 pReq->Reserved2[ii] = 0;
3247 }
3248 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3249 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3250 pReq->Header.PageNumber = 1;
3251 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3252 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3253
3254 /* Add a SGE to the config request.
3255 */
3256 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3257
3258 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3259
3260 /* Set up the common data portion
3261 */
3262 pData->Header.PageVersion = pReq->Header.PageVersion;
3263 pData->Header.PageLength = pReq->Header.PageLength;
3264 pData->Header.PageNumber = pReq->Header.PageNumber;
3265 pData->Header.PageType = pReq->Header.PageType;
3266 pData->RequestedParameters = cpu_to_le32(requested);
3267 pData->Reserved = 0;
3268 pData->Configuration = cpu_to_le32(configuration);
3269
3270 dprintk((MYIOC_s_INFO_FMT
3271 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3272 ioc->name, id, (id | (bus<<8)),
3273 requested, configuration));
3274
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003275 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 }
3277
3278 return 0;
3279}
3280
3281/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3282/* mptscsih_writeIOCPage4 - write IOC Page 4
3283 * @hd: Pointer to a SCSI Host Structure
3284 * @target_id: write IOC Page4 for this ID & Bus
3285 *
3286 * Return: -EAGAIN if unable to obtain a Message Frame
3287 * or 0 if success.
3288 *
3289 * Remark: We do not wait for a return, write pages sequentially.
3290 */
3291static int
3292mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3293{
3294 MPT_ADAPTER *ioc = hd->ioc;
3295 Config_t *pReq;
3296 IOCPage4_t *IOCPage4Ptr;
3297 MPT_FRAME_HDR *mf;
3298 dma_addr_t dataDma;
3299 u16 req_idx;
3300 u32 frameOffset;
3301 u32 flagsLength;
3302 int ii;
3303
3304 /* Get a MF for this command.
3305 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003306 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003307 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 ioc->name));
3309 return -EAGAIN;
3310 }
3311
3312 /* Set the request and the data pointers.
3313 * Place data at end of MF.
3314 */
3315 pReq = (Config_t *)mf;
3316
3317 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3318 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3319
3320 /* Complete the request frame (same for all requests).
3321 */
3322 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3323 pReq->Reserved = 0;
3324 pReq->ChainOffset = 0;
3325 pReq->Function = MPI_FUNCTION_CONFIG;
3326 pReq->ExtPageLength = 0;
3327 pReq->ExtPageType = 0;
3328 pReq->MsgFlags = 0;
3329 for (ii=0; ii < 8; ii++) {
3330 pReq->Reserved2[ii] = 0;
3331 }
3332
3333 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3334 dataDma = ioc->spi_data.IocPg4_dma;
3335 ii = IOCPage4Ptr->ActiveSEP++;
3336 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3337 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3338 pReq->Header = IOCPage4Ptr->Header;
3339 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3340
3341 /* Add a SGE to the config request.
3342 */
3343 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3344 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3345
3346 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3347
3348 dinitprintk((MYIOC_s_INFO_FMT
3349 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3350 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3351
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003352 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
3354 return 0;
3355}
3356
3357/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3358/*
3359 * Bus Scan and Domain Validation functionality ...
3360 */
3361
3362/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3363/*
3364 * mptscsih_scandv_complete - Scan and DV callback routine registered
3365 * to Fustion MPT (base) driver.
3366 *
3367 * @ioc: Pointer to MPT_ADAPTER structure
3368 * @mf: Pointer to original MPT request frame
3369 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3370 *
3371 * This routine is called from mpt.c::mpt_interrupt() at the completion
3372 * of any SCSI IO request.
3373 * This routine is registered with the Fusion MPT (base) driver at driver
3374 * load/init time via the mpt_register() API call.
3375 *
3376 * Returns 1 indicating alloc'd request frame ptr should be freed.
3377 *
3378 * Remark: Sets a completion code and (possibly) saves sense data
3379 * in the IOC member localReply structure.
3380 * Used ONLY for DV and other internal commands.
3381 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003382int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3384{
3385 MPT_SCSI_HOST *hd;
3386 SCSIIORequest_t *pReq;
3387 int completionCode;
3388 u16 req_idx;
3389
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003390 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3391
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 if ((mf == NULL) ||
3393 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3394 printk(MYIOC_s_ERR_FMT
3395 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3396 ioc->name, mf?"BAD":"NULL", (void *) mf);
3397 goto wakeup;
3398 }
3399
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 del_timer(&hd->timer);
3401 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3402 hd->ScsiLookup[req_idx] = NULL;
3403 pReq = (SCSIIORequest_t *) mf;
3404
3405 if (mf != hd->cmdPtr) {
3406 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3407 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3408 }
3409 hd->cmdPtr = NULL;
3410
3411 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3412 hd->ioc->name, mf, mr, req_idx));
3413
3414 hd->pLocal = &hd->localReply;
3415 hd->pLocal->scsiStatus = 0;
3416
3417 /* If target struct exists, clear sense valid flag.
3418 */
3419 if (mr == NULL) {
3420 completionCode = MPT_SCANDV_GOOD;
3421 } else {
3422 SCSIIOReply_t *pReply;
3423 u16 status;
3424 u8 scsi_status;
3425
3426 pReply = (SCSIIOReply_t *) mr;
3427
3428 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3429 scsi_status = pReply->SCSIStatus;
3430
3431 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3432 status, pReply->SCSIState, scsi_status,
3433 le32_to_cpu(pReply->IOCLogInfo)));
3434
3435 switch(status) {
3436
3437 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3438 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3439 break;
3440
3441 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3442 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3443 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3444 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3445 completionCode = MPT_SCANDV_DID_RESET;
3446 break;
3447
3448 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3449 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3450 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3451 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3452 ConfigReply_t *pr = (ConfigReply_t *)mr;
3453 completionCode = MPT_SCANDV_GOOD;
3454 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3455 hd->pLocal->header.PageLength = pr->Header.PageLength;
3456 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3457 hd->pLocal->header.PageType = pr->Header.PageType;
3458
3459 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3460 /* If the RAID Volume request is successful,
3461 * return GOOD, else indicate that
3462 * some type of error occurred.
3463 */
3464 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003465 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 completionCode = MPT_SCANDV_GOOD;
3467 else
3468 completionCode = MPT_SCANDV_SOME_ERROR;
3469
3470 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3471 u8 *sense_data;
3472 int sz;
3473
3474 /* save sense data in global structure
3475 */
3476 completionCode = MPT_SCANDV_SENSE;
3477 hd->pLocal->scsiStatus = scsi_status;
3478 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3479 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3480
3481 sz = min_t(int, pReq->SenseBufferLength,
3482 SCSI_STD_SENSE_BYTES);
3483 memcpy(hd->pLocal->sense, sense_data, sz);
3484
3485 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3486 sense_data));
3487 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3488 if (pReq->CDB[0] == INQUIRY)
3489 completionCode = MPT_SCANDV_ISSUE_SENSE;
3490 else
3491 completionCode = MPT_SCANDV_DID_RESET;
3492 }
3493 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3494 completionCode = MPT_SCANDV_DID_RESET;
3495 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3496 completionCode = MPT_SCANDV_DID_RESET;
3497 else {
3498 completionCode = MPT_SCANDV_GOOD;
3499 hd->pLocal->scsiStatus = scsi_status;
3500 }
3501 break;
3502
3503 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3504 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3505 completionCode = MPT_SCANDV_DID_RESET;
3506 else
3507 completionCode = MPT_SCANDV_SOME_ERROR;
3508 break;
3509
3510 default:
3511 completionCode = MPT_SCANDV_SOME_ERROR;
3512 break;
3513
3514 } /* switch(status) */
3515
3516 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3517 completionCode));
3518 } /* end of address reply case */
3519
3520 hd->pLocal->completion = completionCode;
3521
3522 /* MF and RF are freed in mpt_interrupt
3523 */
3524wakeup:
3525 /* Free Chain buffers (will never chain) in scan or dv */
3526 //mptscsih_freeChainBuffers(ioc, req_idx);
3527
3528 /*
3529 * Wake up the original calling thread
3530 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003531 hd->scandv_wait_done = 1;
3532 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534 return 1;
3535}
3536
3537/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3538/* mptscsih_timer_expired - Call back for timer process.
3539 * Used only for dv functionality.
3540 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3541 *
3542 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003543void
3544mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545{
3546 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3547
3548 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3549
3550 if (hd->cmdPtr) {
3551 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3552
3553 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3554 /* Desire to issue a task management request here.
3555 * TM requests MUST be single threaded.
3556 * If old eh code and no TM current, issue request.
3557 * If new eh code, do nothing. Wait for OS cmd timeout
3558 * for bus reset.
3559 */
3560 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3561 } else {
3562 /* Perform a FW reload */
3563 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3564 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3565 }
3566 }
3567 } else {
3568 /* This should NEVER happen */
3569 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3570 }
3571
3572 /* No more processing.
3573 * TM call will generate an interrupt for SCSI TM Management.
3574 * The FW will reply to all outstanding commands, callback will finish cleanup.
3575 * Hard reset clean-up will free all resources.
3576 */
3577 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3578
3579 return;
3580}
3581
3582#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3584/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3585 * @hd: Pointer to scsi host structure
3586 * @action: What do be done.
3587 * @id: Logical target id.
3588 * @bus: Target locations bus.
3589 *
3590 * Returns: < 0 on a fatal error
3591 * 0 on success
3592 *
3593 * Remark: Wait to return until reply processed by the ISR.
3594 */
3595static int
3596mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3597{
3598 MpiRaidActionRequest_t *pReq;
3599 MPT_FRAME_HDR *mf;
3600 int in_isr;
3601
3602 in_isr = in_interrupt();
3603 if (in_isr) {
3604 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3605 hd->ioc->name));
3606 return -EPERM;
3607 }
3608
3609 /* Get and Populate a free Frame
3610 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003611 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3613 hd->ioc->name));
3614 return -EAGAIN;
3615 }
3616 pReq = (MpiRaidActionRequest_t *)mf;
3617 pReq->Action = action;
3618 pReq->Reserved1 = 0;
3619 pReq->ChainOffset = 0;
3620 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3621 pReq->VolumeID = io->id;
3622 pReq->VolumeBus = io->bus;
3623 pReq->PhysDiskNum = io->physDiskNum;
3624 pReq->MsgFlags = 0;
3625 pReq->Reserved2 = 0;
3626 pReq->ActionDataWord = 0; /* Reserved for this action */
3627 //pReq->ActionDataSGE = 0;
3628
3629 mpt_add_sge((char *)&pReq->ActionDataSGE,
3630 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3631
3632 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3633 hd->ioc->name, action, io->id));
3634
3635 hd->pLocal = NULL;
3636 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003637 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
3639 /* Save cmd pointer, for resource free if timeout or
3640 * FW reload occurs
3641 */
3642 hd->cmdPtr = mf;
3643
3644 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003645 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3646 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3649 return -1;
3650
3651 return 0;
3652}
3653#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3654
3655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3656/**
3657 * mptscsih_do_cmd - Do internal command.
3658 * @hd: MPT_SCSI_HOST pointer
3659 * @io: INTERNAL_CMD pointer.
3660 *
3661 * Issue the specified internally generated command and do command
3662 * specific cleanup. For bus scan / DV only.
3663 * NOTES: If command is Inquiry and status is good,
3664 * initialize a target structure, save the data
3665 *
3666 * Remark: Single threaded access only.
3667 *
3668 * Return:
3669 * < 0 if an illegal command or no resources
3670 *
3671 * 0 if good
3672 *
3673 * > 0 if command complete but some type of completion error.
3674 */
3675static int
3676mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3677{
3678 MPT_FRAME_HDR *mf;
3679 SCSIIORequest_t *pScsiReq;
3680 SCSIIORequest_t ReqCopy;
3681 int my_idx, ii, dir;
3682 int rc, cmdTimeout;
3683 int in_isr;
3684 char cmdLen;
3685 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3686 char cmd = io->cmd;
3687
3688 in_isr = in_interrupt();
3689 if (in_isr) {
3690 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3691 hd->ioc->name));
3692 return -EPERM;
3693 }
3694
3695
3696 /* Set command specific information
3697 */
3698 switch (cmd) {
3699 case INQUIRY:
3700 cmdLen = 6;
3701 dir = MPI_SCSIIO_CONTROL_READ;
3702 CDB[0] = cmd;
3703 CDB[4] = io->size;
3704 cmdTimeout = 10;
3705 break;
3706
3707 case TEST_UNIT_READY:
3708 cmdLen = 6;
3709 dir = MPI_SCSIIO_CONTROL_READ;
3710 cmdTimeout = 10;
3711 break;
3712
3713 case START_STOP:
3714 cmdLen = 6;
3715 dir = MPI_SCSIIO_CONTROL_READ;
3716 CDB[0] = cmd;
3717 CDB[4] = 1; /*Spin up the disk */
3718 cmdTimeout = 15;
3719 break;
3720
3721 case REQUEST_SENSE:
3722 cmdLen = 6;
3723 CDB[0] = cmd;
3724 CDB[4] = io->size;
3725 dir = MPI_SCSIIO_CONTROL_READ;
3726 cmdTimeout = 10;
3727 break;
3728
3729 case READ_BUFFER:
3730 cmdLen = 10;
3731 dir = MPI_SCSIIO_CONTROL_READ;
3732 CDB[0] = cmd;
3733 if (io->flags & MPT_ICFLAG_ECHO) {
3734 CDB[1] = 0x0A;
3735 } else {
3736 CDB[1] = 0x02;
3737 }
3738
3739 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3740 CDB[1] |= 0x01;
3741 }
3742 CDB[6] = (io->size >> 16) & 0xFF;
3743 CDB[7] = (io->size >> 8) & 0xFF;
3744 CDB[8] = io->size & 0xFF;
3745 cmdTimeout = 10;
3746 break;
3747
3748 case WRITE_BUFFER:
3749 cmdLen = 10;
3750 dir = MPI_SCSIIO_CONTROL_WRITE;
3751 CDB[0] = cmd;
3752 if (io->flags & MPT_ICFLAG_ECHO) {
3753 CDB[1] = 0x0A;
3754 } else {
3755 CDB[1] = 0x02;
3756 }
3757 CDB[6] = (io->size >> 16) & 0xFF;
3758 CDB[7] = (io->size >> 8) & 0xFF;
3759 CDB[8] = io->size & 0xFF;
3760 cmdTimeout = 10;
3761 break;
3762
3763 case RESERVE:
3764 cmdLen = 6;
3765 dir = MPI_SCSIIO_CONTROL_READ;
3766 CDB[0] = cmd;
3767 cmdTimeout = 10;
3768 break;
3769
3770 case RELEASE:
3771 cmdLen = 6;
3772 dir = MPI_SCSIIO_CONTROL_READ;
3773 CDB[0] = cmd;
3774 cmdTimeout = 10;
3775 break;
3776
3777 case SYNCHRONIZE_CACHE:
3778 cmdLen = 10;
3779 dir = MPI_SCSIIO_CONTROL_READ;
3780 CDB[0] = cmd;
3781// CDB[1] = 0x02; /* set immediate bit */
3782 cmdTimeout = 10;
3783 break;
3784
3785 default:
3786 /* Error Case */
3787 return -EFAULT;
3788 }
3789
3790 /* Get and Populate a free Frame
3791 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003792 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3794 hd->ioc->name));
3795 return -EBUSY;
3796 }
3797
3798 pScsiReq = (SCSIIORequest_t *) mf;
3799
3800 /* Get the request index */
3801 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3802 ADD_INDEX_LOG(my_idx); /* for debug */
3803
3804 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3805 pScsiReq->TargetID = io->physDiskNum;
3806 pScsiReq->Bus = 0;
3807 pScsiReq->ChainOffset = 0;
3808 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3809 } else {
3810 pScsiReq->TargetID = io->id;
3811 pScsiReq->Bus = io->bus;
3812 pScsiReq->ChainOffset = 0;
3813 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3814 }
3815
3816 pScsiReq->CDBLength = cmdLen;
3817 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3818
3819 pScsiReq->Reserved = 0;
3820
3821 pScsiReq->MsgFlags = mpt_msg_flags();
3822 /* MsgContext set in mpt_get_msg_fram call */
3823
3824 for (ii=0; ii < 8; ii++)
3825 pScsiReq->LUN[ii] = 0;
3826 pScsiReq->LUN[1] = io->lun;
3827
3828 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3829 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3830 else
3831 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3832
3833 if (cmd == REQUEST_SENSE) {
3834 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3835 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3836 hd->ioc->name, cmd));
3837 }
3838
3839 for (ii=0; ii < 16; ii++)
3840 pScsiReq->CDB[ii] = CDB[ii];
3841
3842 pScsiReq->DataLength = cpu_to_le32(io->size);
3843 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3844 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3845
3846 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3847 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3848
3849 if (dir == MPI_SCSIIO_CONTROL_READ) {
3850 mpt_add_sge((char *) &pScsiReq->SGL,
3851 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3852 io->data_dma);
3853 } else {
3854 mpt_add_sge((char *) &pScsiReq->SGL,
3855 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3856 io->data_dma);
3857 }
3858
3859 /* The ISR will free the request frame, but we need
3860 * the information to initialize the target. Duplicate.
3861 */
3862 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3863
3864 /* Issue this command after:
3865 * finish init
3866 * add timer
3867 * Wait until the reply has been received
3868 * ScsiScanDvCtx callback function will
3869 * set hd->pLocal;
3870 * set scandv_wait_done and call wake_up
3871 */
3872 hd->pLocal = NULL;
3873 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003874 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
3876 /* Save cmd pointer, for resource free if timeout or
3877 * FW reload occurs
3878 */
3879 hd->cmdPtr = mf;
3880
3881 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003882 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3883 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884
3885 if (hd->pLocal) {
3886 rc = hd->pLocal->completion;
3887 hd->pLocal->skip = 0;
3888
3889 /* Always set fatal error codes in some cases.
3890 */
3891 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3892 rc = -ENXIO;
3893 else if (rc == MPT_SCANDV_SOME_ERROR)
3894 rc = -rc;
3895 } else {
3896 rc = -EFAULT;
3897 /* This should never happen. */
3898 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3899 hd->ioc->name));
3900 }
3901
3902 return rc;
3903}
3904
3905/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3906/**
3907 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3908 * @hd: Pointer to MPT_SCSI_HOST structure
3909 * @portnum: IOC port number
3910 *
3911 * Uses the ISR, but with special processing.
3912 * MUST be single-threaded.
3913 *
3914 * Return: 0 on completion
3915 */
3916static int
3917mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
3918{
3919 MPT_ADAPTER *ioc= hd->ioc;
3920 VirtDevice *pTarget;
3921 SCSIDevicePage1_t *pcfg1Data = NULL;
3922 INTERNAL_CMD iocmd;
3923 CONFIGPARMS cfg;
3924 dma_addr_t cfg1_dma_addr = -1;
3925 ConfigPageHeader_t header1;
3926 int bus = 0;
3927 int id = 0;
3928 int lun;
3929 int indexed_lun, lun_index;
3930 int hostId = ioc->pfacts[portnum].PortSCSIID;
3931 int max_id;
3932 int requested, configuration, data;
3933 int doConfig = 0;
3934 u8 flags, factor;
3935
3936 max_id = ioc->sh->max_id - 1;
3937
3938 /* Following parameters will not change
3939 * in this routine.
3940 */
3941 iocmd.cmd = SYNCHRONIZE_CACHE;
3942 iocmd.flags = 0;
3943 iocmd.physDiskNum = -1;
3944 iocmd.data = NULL;
3945 iocmd.data_dma = -1;
3946 iocmd.size = 0;
3947 iocmd.rsvd = iocmd.rsvd2 = 0;
3948
3949 /* No SCSI hosts
3950 */
3951 if (hd->Targets == NULL)
3952 return 0;
3953
3954 /* Skip the host
3955 */
3956 if (id == hostId)
3957 id++;
3958
3959 /* Write SDP1 for all SCSI devices
3960 * Alloc memory and set up config buffer
3961 */
3962 if (ioc->bus_type == SCSI) {
3963 if (ioc->spi_data.sdp1length > 0) {
3964 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3965 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3966
3967 if (pcfg1Data != NULL) {
3968 doConfig = 1;
3969 header1.PageVersion = ioc->spi_data.sdp1version;
3970 header1.PageLength = ioc->spi_data.sdp1length;
3971 header1.PageNumber = 1;
3972 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02003973 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 cfg.physAddr = cfg1_dma_addr;
3975 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3976 cfg.dir = 1;
3977 cfg.timeout = 0;
3978 }
3979 }
3980 }
3981
3982 /* loop through all devices on this port
3983 */
3984 while (bus < MPT_MAX_BUS) {
3985 iocmd.bus = bus;
3986 iocmd.id = id;
3987 pTarget = hd->Targets[(int)id];
3988
3989 if (doConfig) {
3990
3991 /* Set the negotiation flags */
3992 if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3993 flags = pTarget->negoFlags;
3994 } else {
3995 flags = hd->ioc->spi_data.noQas;
3996 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3997 data = hd->ioc->spi_data.nvram[id];
3998
3999 if (data & MPT_NVRAM_WIDE_DISABLE)
4000 flags |= MPT_TARGET_NO_NEGO_WIDE;
4001
4002 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
4003 if ((factor == 0) || (factor == MPT_ASYNC))
4004 flags |= MPT_TARGET_NO_NEGO_SYNC;
4005 }
4006 }
4007
4008 /* Force to async, narrow */
4009 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
4010 &configuration, flags);
4011 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
4012 "offset=0 negoFlags=%x request=%x config=%x\n",
4013 id, flags, requested, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02004014 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 pcfg1Data->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02004016 pcfg1Data->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 cfg.pageAddr = (bus<<8) | id;
4018 mpt_config(hd->ioc, &cfg);
4019 }
4020
4021 /* If target Ptr NULL or if this target is NOT a disk, skip.
4022 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004023 if ((pTarget) && (pTarget->inq_data[0] == TYPE_DISK)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 for (lun=0; lun <= MPT_LAST_LUN; lun++) {
4025 /* If LUN present, issue the command
4026 */
4027 lun_index = (lun >> 5); /* 32 luns per lun_index */
4028 indexed_lun = (lun % 32);
4029 if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
4030 iocmd.lun = lun;
4031 (void) mptscsih_do_cmd(hd, &iocmd);
4032 }
4033 }
4034 }
4035
4036 /* get next relevant device */
4037 id++;
4038
4039 if (id == hostId)
4040 id++;
4041
4042 if (id > max_id) {
4043 id = 0;
4044 bus++;
4045 }
4046 }
4047
4048 if (pcfg1Data) {
4049 pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
4050 }
4051
4052 return 0;
4053}
4054
4055#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
4056/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4057/**
4058 * mptscsih_domainValidation - Top level handler for domain validation.
4059 * @hd: Pointer to MPT_SCSI_HOST structure.
4060 *
4061 * Uses the ISR, but with special processing.
4062 * Called from schedule, should not be in interrupt mode.
4063 * While thread alive, do dv for all devices needing dv
4064 *
4065 * Return: None.
4066 */
4067static void
4068mptscsih_domainValidation(void *arg)
4069{
4070 MPT_SCSI_HOST *hd;
4071 MPT_ADAPTER *ioc;
4072 unsigned long flags;
4073 int id, maxid, dvStatus, did;
4074 int ii, isPhysDisk;
4075
4076 spin_lock_irqsave(&dvtaskQ_lock, flags);
4077 dvtaskQ_active = 1;
4078 if (dvtaskQ_release) {
4079 dvtaskQ_active = 0;
4080 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4081 return;
4082 }
4083 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4084
4085 /* For this ioc, loop through all devices and do dv to each device.
4086 * When complete with this ioc, search through the ioc list, and
4087 * for each scsi ioc found, do dv for all devices. Exit when no
4088 * device needs dv.
4089 */
4090 did = 1;
4091 while (did) {
4092 did = 0;
4093 list_for_each_entry(ioc, &ioc_list, list) {
4094 spin_lock_irqsave(&dvtaskQ_lock, flags);
4095 if (dvtaskQ_release) {
4096 dvtaskQ_active = 0;
4097 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4098 return;
4099 }
4100 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4101
4102 msleep(250);
4103
4104 /* DV only to SCSI adapters */
4105 if (ioc->bus_type != SCSI)
4106 continue;
4107
4108 /* Make sure everything looks ok */
4109 if (ioc->sh == NULL)
4110 continue;
4111
4112 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4113 if (hd == NULL)
4114 continue;
4115
4116 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4117 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004118 if (ioc->raid_data.pIocPg3) {
4119 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4120 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
4122 while (numPDisk) {
4123 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4124 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4125
4126 pPDisk++;
4127 numPDisk--;
4128 }
4129 }
4130 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4131 }
4132
4133 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4134
4135 for (id = 0; id < maxid; id++) {
4136 spin_lock_irqsave(&dvtaskQ_lock, flags);
4137 if (dvtaskQ_release) {
4138 dvtaskQ_active = 0;
4139 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4140 return;
4141 }
4142 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4143 dvStatus = hd->ioc->spi_data.dvStatus[id];
4144
4145 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4146 did++;
4147 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4148 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4149
4150 msleep(250);
4151
4152 /* If hidden phys disk, block IO's to all
4153 * raid volumes
4154 * else, process normally
4155 */
4156 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4157 if (isPhysDisk) {
4158 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004159 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4161 }
4162 }
4163 }
4164
4165 if (mptscsih_doDv(hd, 0, id) == 1) {
4166 /* Untagged device was busy, try again
4167 */
4168 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4169 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4170 } else {
4171 /* DV is complete. Clear flags.
4172 */
4173 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4174 }
4175
4176 if (isPhysDisk) {
4177 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004178 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4180 }
4181 }
4182 }
4183
4184 if (hd->ioc->spi_data.noQas)
4185 mptscsih_qas_check(hd, id);
4186 }
4187 }
4188 }
4189 }
4190
4191 spin_lock_irqsave(&dvtaskQ_lock, flags);
4192 dvtaskQ_active = 0;
4193 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4194
4195 return;
4196}
4197
4198/* Search IOC page 3 to determine if this is hidden physical disk
4199 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004200/* Search IOC page 3 to determine if this is hidden physical disk
4201 */
4202static int
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004203mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004205 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004207 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
4208 return 0;
4209
4210 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
4211 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
4212 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004214
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 return 0;
4216}
4217
4218/* Write SDP1 if no QAS has been enabled
4219 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004220static void
4221mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223 VirtDevice *pTarget;
4224 int ii;
4225
4226 if (hd->Targets == NULL)
4227 return;
4228
4229 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4230 if (ii == id)
4231 continue;
4232
4233 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4234 continue;
4235
4236 pTarget = hd->Targets[ii];
4237
4238 if ((pTarget != NULL) && (!pTarget->raidVolume)) {
4239 if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4240 pTarget->negoFlags |= hd->ioc->spi_data.noQas;
4241 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4242 mptscsih_writeSDP1(hd, 0, ii, 0);
4243 }
4244 } else {
4245 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4246 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4247 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4248 }
4249 }
4250 }
4251 return;
4252}
4253
4254
4255
4256#define MPT_GET_NVRAM_VALS 0x01
4257#define MPT_UPDATE_MAX 0x02
4258#define MPT_SET_MAX 0x04
4259#define MPT_SET_MIN 0x08
4260#define MPT_FALLBACK 0x10
4261#define MPT_SAVE 0x20
4262
4263/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4264/**
4265 * mptscsih_doDv - Perform domain validation to a target.
4266 * @hd: Pointer to MPT_SCSI_HOST structure.
4267 * @portnum: IOC port number.
4268 * @target: Physical ID of this target
4269 *
4270 * Uses the ISR, but with special processing.
4271 * MUST be single-threaded.
4272 * Test will exit if target is at async & narrow.
4273 *
4274 * Return: None.
4275 */
4276static int
4277mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4278{
4279 MPT_ADAPTER *ioc = hd->ioc;
4280 VirtDevice *pTarget;
4281 SCSIDevicePage1_t *pcfg1Data;
4282 SCSIDevicePage0_t *pcfg0Data;
4283 u8 *pbuf1;
4284 u8 *pbuf2;
4285 u8 *pDvBuf;
4286 dma_addr_t dvbuf_dma = -1;
4287 dma_addr_t buf1_dma = -1;
4288 dma_addr_t buf2_dma = -1;
4289 dma_addr_t cfg1_dma_addr = -1;
4290 dma_addr_t cfg0_dma_addr = -1;
4291 ConfigPageHeader_t header1;
4292 ConfigPageHeader_t header0;
4293 DVPARAMETERS dv;
4294 INTERNAL_CMD iocmd;
4295 CONFIGPARMS cfg;
4296 int dv_alloc = 0;
4297 int rc, sz = 0;
4298 int bufsize = 0;
4299 int dataBufSize = 0;
4300 int echoBufSize = 0;
4301 int notDone;
4302 int patt;
4303 int repeat;
4304 int retcode = 0;
4305 int nfactor = MPT_ULTRA320;
4306 char firstPass = 1;
4307 char doFallback = 0;
4308 char readPage0;
4309 char bus, lun;
4310 char inq0 = 0;
4311
4312 if (ioc->spi_data.sdp1length == 0)
4313 return 0;
4314
4315 if (ioc->spi_data.sdp0length == 0)
4316 return 0;
4317
4318 /* If multiple buses are used, require that the initiator
4319 * id be the same on all buses.
4320 */
4321 if (id == ioc->pfacts[0].PortSCSIID)
4322 return 0;
4323
4324 lun = 0;
4325 bus = (u8) bus_number;
4326 ddvtprintk((MYIOC_s_NOTE_FMT
4327 "DV started: bus=%d, id=%d dv @ %p\n",
4328 ioc->name, bus, id, &dv));
4329
4330 /* Prep DV structure
4331 */
4332 memset (&dv, 0, sizeof(DVPARAMETERS));
4333 dv.id = id;
4334
4335 /* Populate tmax with the current maximum
4336 * transfer parameters for this target.
4337 * Exit if narrow and async.
4338 */
4339 dv.cmd = MPT_GET_NVRAM_VALS;
4340 mptscsih_dv_parms(hd, &dv, NULL);
4341
4342 /* Prep SCSI IO structure
4343 */
4344 iocmd.id = id;
4345 iocmd.bus = bus;
4346 iocmd.lun = lun;
4347 iocmd.flags = 0;
4348 iocmd.physDiskNum = -1;
4349 iocmd.rsvd = iocmd.rsvd2 = 0;
4350
4351 pTarget = hd->Targets[id];
4352
4353 /* Use tagged commands if possible.
4354 */
4355 if (pTarget) {
4356 if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
4357 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4358 else {
4359 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4360 return 0;
4361
4362 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4363 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4364 return 0;
4365 }
4366 }
4367
4368 /* Prep cfg structure
4369 */
4370 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004371 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
4373 /* Prep SDP0 header
4374 */
4375 header0.PageVersion = ioc->spi_data.sdp0version;
4376 header0.PageLength = ioc->spi_data.sdp0length;
4377 header0.PageNumber = 0;
4378 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4379
4380 /* Prep SDP1 header
4381 */
4382 header1.PageVersion = ioc->spi_data.sdp1version;
4383 header1.PageLength = ioc->spi_data.sdp1length;
4384 header1.PageNumber = 1;
4385 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4386
4387 if (header0.PageLength & 1)
4388 dv_alloc = (header0.PageLength * 4) + 4;
4389
4390 dv_alloc += (2048 + (header1.PageLength * 4));
4391
4392 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4393 if (pDvBuf == NULL)
4394 return 0;
4395
4396 sz = 0;
4397 pbuf1 = (u8 *)pDvBuf;
4398 buf1_dma = dvbuf_dma;
4399 sz +=1024;
4400
4401 pbuf2 = (u8 *) (pDvBuf + sz);
4402 buf2_dma = dvbuf_dma + sz;
4403 sz +=1024;
4404
4405 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4406 cfg0_dma_addr = dvbuf_dma + sz;
4407 sz += header0.PageLength * 4;
4408
4409 /* 8-byte alignment
4410 */
4411 if (header0.PageLength & 1)
4412 sz += 4;
4413
4414 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4415 cfg1_dma_addr = dvbuf_dma + sz;
4416
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004417 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 */
4419 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004420 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4422 /* Set the factor from nvram */
4423 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4424 if (nfactor < pspi_data->minSyncFactor )
4425 nfactor = pspi_data->minSyncFactor;
4426
4427 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4428 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4429
4430 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4431 ioc->name, bus, id, lun));
4432
4433 dv.cmd = MPT_SET_MAX;
4434 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004435 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436
4437 /* Save the final negotiated settings to
4438 * SCSI device page 1.
4439 */
4440 cfg.physAddr = cfg1_dma_addr;
4441 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4442 cfg.dir = 1;
4443 mpt_config(hd->ioc, &cfg);
4444 goto target_done;
4445 }
4446 }
4447 }
4448
4449 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004450 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 /* Search IOC page 3 for matching id
4452 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004453 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4454 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
4456 while (numPDisk) {
4457 if (pPDisk->PhysDiskID == id) {
4458 /* match */
4459 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4460 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4461
4462 /* Quiesce the IM
4463 */
4464 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4465 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4466 goto target_done;
4467 }
4468 break;
4469 }
4470 pPDisk++;
4471 numPDisk--;
4472 }
4473 }
4474
4475 /* RAID Volume ID's may double for a physical device. If RAID but
4476 * not a physical ID as well, skip DV.
4477 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004478 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 goto target_done;
4480
4481
4482 /* Basic Test.
4483 * Async & Narrow - Inquiry
4484 * Async & Narrow - Inquiry
4485 * Maximum transfer rate - Inquiry
4486 * Compare buffers:
4487 * If compare, test complete.
4488 * If miscompare and first pass, repeat
4489 * If miscompare and not first pass, fall back and repeat
4490 */
4491 hd->pLocal = NULL;
4492 readPage0 = 0;
4493 sz = SCSI_MAX_INQUIRY_BYTES;
4494 rc = MPT_SCANDV_GOOD;
4495 while (1) {
4496 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4497 retcode = 0;
4498 dv.cmd = MPT_SET_MIN;
4499 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4500
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004501 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 cfg.physAddr = cfg1_dma_addr;
4503 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4504 cfg.dir = 1;
4505 if (mpt_config(hd->ioc, &cfg) != 0)
4506 goto target_done;
4507
4508 /* Wide - narrow - wide workaround case
4509 */
4510 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4511 /* Send an untagged command to reset disk Qs corrupted
4512 * when a parity error occurs on a Request Sense.
4513 */
4514 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4515 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4516 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4517
4518 iocmd.cmd = REQUEST_SENSE;
4519 iocmd.data_dma = buf1_dma;
4520 iocmd.data = pbuf1;
4521 iocmd.size = 0x12;
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) || (rc == MPT_SCANDV_SENSE)) {
4529 dv.max.width = 0;
4530 doFallback = 0;
4531 } else
4532 goto target_done;
4533 }
4534 } else
4535 goto target_done;
4536 }
4537
4538 iocmd.cmd = INQUIRY;
4539 iocmd.data_dma = buf1_dma;
4540 iocmd.data = pbuf1;
4541 iocmd.size = sz;
4542 memset(pbuf1, 0x00, sz);
4543 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4544 goto target_done;
4545 else {
4546 if (hd->pLocal == NULL)
4547 goto target_done;
4548 rc = hd->pLocal->completion;
4549 if (rc == MPT_SCANDV_GOOD) {
4550 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4551 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4552 retcode = 1;
4553 else
4554 retcode = 0;
4555
4556 goto target_done;
4557 }
4558 } else if (rc == MPT_SCANDV_SENSE) {
4559 ;
4560 } else {
4561 /* If first command doesn't complete
4562 * with a good status or with a check condition,
4563 * exit.
4564 */
4565 goto target_done;
4566 }
4567 }
4568
4569 /* Reset the size for disks
4570 */
4571 inq0 = (*pbuf1) & 0x1F;
4572 if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
4573 sz = 0x40;
4574 iocmd.size = sz;
4575 }
4576
4577 /* Another GEM workaround. Check peripheral device type,
4578 * if PROCESSOR, quit DV.
4579 */
4580 if (inq0 == TYPE_PROCESSOR) {
4581 mptscsih_initTarget(hd,
4582 bus,
4583 id,
4584 lun,
4585 pbuf1,
4586 sz);
4587 goto target_done;
4588 }
4589
4590 if (inq0 > 0x08)
4591 goto target_done;
4592
4593 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4594 goto target_done;
4595
4596 if (sz == 0x40) {
4597 if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
4598 && (pTarget->minSyncFactor > 0x09)) {
4599 if ((pbuf1[56] & 0x04) == 0)
4600 ;
4601 else if ((pbuf1[56] & 0x01) == 1) {
4602 pTarget->minSyncFactor =
4603 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4604 } else {
4605 pTarget->minSyncFactor =
4606 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4607 }
4608
4609 dv.max.factor = pTarget->minSyncFactor;
4610
4611 if ((pbuf1[56] & 0x02) == 0) {
4612 pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
4613 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004614 ddvprintk((MYIOC_s_NOTE_FMT
4615 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 ioc->name, id, pbuf1[56]));
4617 }
4618 }
4619 }
4620
4621 if (doFallback)
4622 dv.cmd = MPT_FALLBACK;
4623 else
4624 dv.cmd = MPT_SET_MAX;
4625
4626 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4627 if (mpt_config(hd->ioc, &cfg) != 0)
4628 goto target_done;
4629
4630 if ((!dv.now.width) && (!dv.now.offset))
4631 goto target_done;
4632
4633 iocmd.cmd = INQUIRY;
4634 iocmd.data_dma = buf2_dma;
4635 iocmd.data = pbuf2;
4636 iocmd.size = sz;
4637 memset(pbuf2, 0x00, sz);
4638 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4639 goto target_done;
4640 else if (hd->pLocal == NULL)
4641 goto target_done;
4642 else {
4643 /* Save the return code.
4644 * If this is the first pass,
4645 * read SCSI Device Page 0
4646 * and update the target max parameters.
4647 */
4648 rc = hd->pLocal->completion;
4649 doFallback = 0;
4650 if (rc == MPT_SCANDV_GOOD) {
4651 if (!readPage0) {
4652 u32 sdp0_info;
4653 u32 sdp0_nego;
4654
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004655 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 cfg.physAddr = cfg0_dma_addr;
4657 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4658 cfg.dir = 0;
4659
4660 if (mpt_config(hd->ioc, &cfg) != 0)
4661 goto target_done;
4662
4663 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4664 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4665
4666 /* Quantum and Fujitsu workarounds.
4667 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4668 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4669 * Resetart with a request for U160.
4670 */
4671 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4672 doFallback = 1;
4673 } else {
4674 dv.cmd = MPT_UPDATE_MAX;
4675 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4676 /* Update the SCSI device page 1 area
4677 */
4678 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4679 readPage0 = 1;
4680 }
4681 }
4682
4683 /* Quantum workaround. Restart this test will the fallback
4684 * flag set.
4685 */
4686 if (doFallback == 0) {
4687 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4688 if (!firstPass)
4689 doFallback = 1;
4690 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004691 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4693 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4694 mptscsih_initTarget(hd,
4695 bus,
4696 id,
4697 lun,
4698 pbuf1,
4699 sz);
4700 break; /* test complete */
4701 }
4702 }
4703
4704
4705 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4706 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004707 else if ((rc == MPT_SCANDV_DID_RESET) ||
4708 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 (rc == MPT_SCANDV_FALLBACK))
4710 doFallback = 1; /* set fallback flag */
4711 else
4712 goto target_done;
4713
4714 firstPass = 0;
4715 }
4716 }
4717 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4718
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004719 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 goto target_done;
4721
4722 inq0 = (*pbuf1) & 0x1F;
4723
4724 /* Continue only for disks
4725 */
4726 if (inq0 != 0)
4727 goto target_done;
4728
4729 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4730 goto target_done;
4731
4732 /* Start the Enhanced Test.
4733 * 0) issue TUR to clear out check conditions
4734 * 1) read capacity of echo (regular) buffer
4735 * 2) reserve device
4736 * 3) do write-read-compare data pattern test
4737 * 4) release
4738 * 5) update nego parms to target struct
4739 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004740 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 cfg.physAddr = cfg1_dma_addr;
4742 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4743 cfg.dir = 1;
4744
4745 iocmd.cmd = TEST_UNIT_READY;
4746 iocmd.data_dma = -1;
4747 iocmd.data = NULL;
4748 iocmd.size = 0;
4749 notDone = 1;
4750 while (notDone) {
4751 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4752 goto target_done;
4753
4754 if (hd->pLocal == NULL)
4755 goto target_done;
4756
4757 rc = hd->pLocal->completion;
4758 if (rc == MPT_SCANDV_GOOD)
4759 notDone = 0;
4760 else if (rc == MPT_SCANDV_SENSE) {
4761 u8 skey = hd->pLocal->sense[2] & 0x0F;
4762 u8 asc = hd->pLocal->sense[12];
4763 u8 ascq = hd->pLocal->sense[13];
4764 ddvprintk((MYIOC_s_INFO_FMT
4765 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4766 ioc->name, skey, asc, ascq));
4767
4768 if (skey == UNIT_ATTENTION)
4769 notDone++; /* repeat */
4770 else if ((skey == NOT_READY) &&
4771 (asc == 0x04)&&(ascq == 0x01)) {
4772 /* wait then repeat */
4773 mdelay (2000);
4774 notDone++;
4775 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4776 /* no medium, try read test anyway */
4777 notDone = 0;
4778 } else {
4779 /* All other errors are fatal.
4780 */
4781 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4782 ioc->name));
4783 goto target_done;
4784 }
4785 } else
4786 goto target_done;
4787 }
4788
4789 iocmd.cmd = READ_BUFFER;
4790 iocmd.data_dma = buf1_dma;
4791 iocmd.data = pbuf1;
4792 iocmd.size = 4;
4793 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4794
4795 dataBufSize = 0;
4796 echoBufSize = 0;
4797 for (patt = 0; patt < 2; patt++) {
4798 if (patt == 0)
4799 iocmd.flags |= MPT_ICFLAG_ECHO;
4800 else
4801 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4802
4803 notDone = 1;
4804 while (notDone) {
4805 bufsize = 0;
4806
4807 /* If not ready after 8 trials,
4808 * give up on this device.
4809 */
4810 if (notDone > 8)
4811 goto target_done;
4812
4813 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4814 goto target_done;
4815 else if (hd->pLocal == NULL)
4816 goto target_done;
4817 else {
4818 rc = hd->pLocal->completion;
4819 ddvprintk(("ReadBuffer Comp Code %d", rc));
4820 ddvprintk((" buff: %0x %0x %0x %0x\n",
4821 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4822
4823 if (rc == MPT_SCANDV_GOOD) {
4824 notDone = 0;
4825 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4826 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004827 if (pbuf1[0] & 0x01)
4828 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 } else {
4830 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4831 }
4832 } else if (rc == MPT_SCANDV_SENSE) {
4833 u8 skey = hd->pLocal->sense[2] & 0x0F;
4834 u8 asc = hd->pLocal->sense[12];
4835 u8 ascq = hd->pLocal->sense[13];
4836 ddvprintk((MYIOC_s_INFO_FMT
4837 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4838 ioc->name, skey, asc, ascq));
4839 if (skey == ILLEGAL_REQUEST) {
4840 notDone = 0;
4841 } else if (skey == UNIT_ATTENTION) {
4842 notDone++; /* repeat */
4843 } else if ((skey == NOT_READY) &&
4844 (asc == 0x04)&&(ascq == 0x01)) {
4845 /* wait then repeat */
4846 mdelay (2000);
4847 notDone++;
4848 } else {
4849 /* All other errors are fatal.
4850 */
4851 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4852 ioc->name));
4853 goto target_done;
4854 }
4855 } else {
4856 /* All other errors are fatal
4857 */
4858 goto target_done;
4859 }
4860 }
4861 }
4862
4863 if (iocmd.flags & MPT_ICFLAG_ECHO)
4864 echoBufSize = bufsize;
4865 else
4866 dataBufSize = bufsize;
4867 }
4868 sz = 0;
4869 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4870
4871 /* Use echo buffers if possible,
4872 * Exit if both buffers are 0.
4873 */
4874 if (echoBufSize > 0) {
4875 iocmd.flags |= MPT_ICFLAG_ECHO;
4876 if (dataBufSize > 0)
4877 bufsize = min(echoBufSize, dataBufSize);
4878 else
4879 bufsize = echoBufSize;
4880 } else if (dataBufSize == 0)
4881 goto target_done;
4882
4883 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4884 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4885
4886 /* Data buffers for write-read-compare test max 1K.
4887 */
4888 sz = min(bufsize, 1024);
4889
4890 /* --- loop ----
4891 * On first pass, always issue a reserve.
4892 * On additional loops, only if a reset has occurred.
4893 * iocmd.flags indicates if echo or regular buffer
4894 */
4895 for (patt = 0; patt < 4; patt++) {
4896 ddvprintk(("Pattern %d\n", patt));
4897 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4898 iocmd.cmd = TEST_UNIT_READY;
4899 iocmd.data_dma = -1;
4900 iocmd.data = NULL;
4901 iocmd.size = 0;
4902 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4903 goto target_done;
4904
4905 iocmd.cmd = RELEASE;
4906 iocmd.data_dma = -1;
4907 iocmd.data = NULL;
4908 iocmd.size = 0;
4909 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4910 goto target_done;
4911 else if (hd->pLocal == NULL)
4912 goto target_done;
4913 else {
4914 rc = hd->pLocal->completion;
4915 ddvprintk(("Release rc %d\n", rc));
4916 if (rc == MPT_SCANDV_GOOD)
4917 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4918 else
4919 goto target_done;
4920 }
4921 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4922 }
4923 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4924
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004925 if (iocmd.flags & MPT_ICFLAG_EBOS)
4926 goto skip_Reserve;
4927
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 repeat = 5;
4929 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4930 iocmd.cmd = RESERVE;
4931 iocmd.data_dma = -1;
4932 iocmd.data = NULL;
4933 iocmd.size = 0;
4934 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4935 goto target_done;
4936 else if (hd->pLocal == NULL)
4937 goto target_done;
4938 else {
4939 rc = hd->pLocal->completion;
4940 if (rc == MPT_SCANDV_GOOD) {
4941 iocmd.flags |= MPT_ICFLAG_RESERVED;
4942 } else if (rc == MPT_SCANDV_SENSE) {
4943 /* Wait if coming ready
4944 */
4945 u8 skey = hd->pLocal->sense[2] & 0x0F;
4946 u8 asc = hd->pLocal->sense[12];
4947 u8 ascq = hd->pLocal->sense[13];
4948 ddvprintk((MYIOC_s_INFO_FMT
4949 "DV: Reserve Failed: ", ioc->name));
4950 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4951 skey, asc, ascq));
4952
4953 if ((skey == NOT_READY) && (asc == 0x04)&&
4954 (ascq == 0x01)) {
4955 /* wait then repeat */
4956 mdelay (2000);
4957 notDone++;
4958 } else {
4959 ddvprintk((MYIOC_s_INFO_FMT
4960 "DV: Reserved Failed.", ioc->name));
4961 goto target_done;
4962 }
4963 } else {
4964 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4965 ioc->name));
4966 goto target_done;
4967 }
4968 }
4969 }
4970
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004971skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4973 iocmd.cmd = WRITE_BUFFER;
4974 iocmd.data_dma = buf1_dma;
4975 iocmd.data = pbuf1;
4976 iocmd.size = sz;
4977 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4978 goto target_done;
4979 else if (hd->pLocal == NULL)
4980 goto target_done;
4981 else {
4982 rc = hd->pLocal->completion;
4983 if (rc == MPT_SCANDV_GOOD)
4984 ; /* Issue read buffer */
4985 else if (rc == MPT_SCANDV_DID_RESET) {
4986 /* If using echo buffers, reset to data buffers.
4987 * Else do Fallback and restart
4988 * this test (re-issue reserve
4989 * because of bus reset).
4990 */
4991 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4992 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4993 } else {
4994 dv.cmd = MPT_FALLBACK;
4995 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4996
4997 if (mpt_config(hd->ioc, &cfg) != 0)
4998 goto target_done;
4999
5000 if ((!dv.now.width) && (!dv.now.offset))
5001 goto target_done;
5002 }
5003
5004 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5005 patt = -1;
5006 continue;
5007 } else if (rc == MPT_SCANDV_SENSE) {
5008 /* Restart data test if UA, else quit.
5009 */
5010 u8 skey = hd->pLocal->sense[2] & 0x0F;
5011 ddvprintk((MYIOC_s_INFO_FMT
5012 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5013 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5014 if (skey == UNIT_ATTENTION) {
5015 patt = -1;
5016 continue;
5017 } else if (skey == ILLEGAL_REQUEST) {
5018 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5019 if (dataBufSize >= bufsize) {
5020 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5021 patt = -1;
5022 continue;
5023 }
5024 }
5025 goto target_done;
5026 }
5027 else
5028 goto target_done;
5029 } else {
5030 /* fatal error */
5031 goto target_done;
5032 }
5033 }
5034
5035 iocmd.cmd = READ_BUFFER;
5036 iocmd.data_dma = buf2_dma;
5037 iocmd.data = pbuf2;
5038 iocmd.size = sz;
5039 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5040 goto target_done;
5041 else if (hd->pLocal == NULL)
5042 goto target_done;
5043 else {
5044 rc = hd->pLocal->completion;
5045 if (rc == MPT_SCANDV_GOOD) {
5046 /* If buffers compare,
5047 * go to next pattern,
5048 * else, do a fallback and restart
5049 * data transfer test.
5050 */
5051 if (memcmp (pbuf1, pbuf2, sz) == 0) {
5052 ; /* goto next pattern */
5053 } else {
5054 /* Miscompare with Echo buffer, go to data buffer,
5055 * if that buffer exists.
5056 * Miscompare with Data buffer, check first 4 bytes,
5057 * some devices return capacity. Exit in this case.
5058 */
5059 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5060 if (dataBufSize >= bufsize)
5061 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5062 else
5063 goto target_done;
5064 } else {
5065 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
5066 /* Argh. Device returning wrong data.
5067 * Quit DV for this device.
5068 */
5069 goto target_done;
5070 }
5071
5072 /* Had an actual miscompare. Slow down.*/
5073 dv.cmd = MPT_FALLBACK;
5074 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5075
5076 if (mpt_config(hd->ioc, &cfg) != 0)
5077 goto target_done;
5078
5079 if ((!dv.now.width) && (!dv.now.offset))
5080 goto target_done;
5081 }
5082
5083 patt = -1;
5084 continue;
5085 }
5086 } else if (rc == MPT_SCANDV_DID_RESET) {
5087 /* Do Fallback and restart
5088 * this test (re-issue reserve
5089 * because of bus reset).
5090 */
5091 dv.cmd = MPT_FALLBACK;
5092 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5093
5094 if (mpt_config(hd->ioc, &cfg) != 0)
5095 goto target_done;
5096
5097 if ((!dv.now.width) && (!dv.now.offset))
5098 goto target_done;
5099
5100 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5101 patt = -1;
5102 continue;
5103 } else if (rc == MPT_SCANDV_SENSE) {
5104 /* Restart data test if UA, else quit.
5105 */
5106 u8 skey = hd->pLocal->sense[2] & 0x0F;
5107 ddvprintk((MYIOC_s_INFO_FMT
5108 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5109 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5110 if (skey == UNIT_ATTENTION) {
5111 patt = -1;
5112 continue;
5113 }
5114 else
5115 goto target_done;
5116 } else {
5117 /* fatal error */
5118 goto target_done;
5119 }
5120 }
5121
5122 } /* --- end of patt loop ---- */
5123
5124target_done:
5125 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5126 iocmd.cmd = RELEASE;
5127 iocmd.data_dma = -1;
5128 iocmd.data = NULL;
5129 iocmd.size = 0;
5130 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5131 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5132 ioc->name, id);
5133 else if (hd->pLocal) {
5134 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5135 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5136 } else {
5137 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5138 ioc->name, id);
5139 }
5140 }
5141
5142
5143 /* Set if cfg1_dma_addr contents is valid
5144 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005145 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 /* If disk, not U320, disable QAS
5147 */
5148 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5149 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005150 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5152 }
5153
5154 dv.cmd = MPT_SAVE;
5155 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5156
5157 /* Double writes to SDP1 can cause problems,
5158 * skip save of the final negotiated settings to
5159 * SCSI device page 1.
5160 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005161 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 cfg.physAddr = cfg1_dma_addr;
5163 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5164 cfg.dir = 1;
5165 mpt_config(hd->ioc, &cfg);
5166 */
5167 }
5168
5169 /* If this is a RAID Passthrough, enable internal IOs
5170 */
5171 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5172 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5173 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5174 }
5175
5176 /* Done with the DV scan of the current target
5177 */
5178 if (pDvBuf)
5179 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5180
5181 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5182 ioc->name, id));
5183
5184 return retcode;
5185}
5186
5187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5188/* mptscsih_dv_parms - perform a variety of operations on the
5189 * parameters used for negotiation.
5190 * @hd: Pointer to a SCSI host.
5191 * @dv: Pointer to a structure that contains the maximum and current
5192 * negotiated parameters.
5193 */
5194static void
5195mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5196{
5197 VirtDevice *pTarget;
5198 SCSIDevicePage0_t *pPage0;
5199 SCSIDevicePage1_t *pPage1;
5200 int val = 0, data, configuration;
5201 u8 width = 0;
5202 u8 offset = 0;
5203 u8 factor = 0;
5204 u8 negoFlags = 0;
5205 u8 cmd = dv->cmd;
5206 u8 id = dv->id;
5207
5208 switch (cmd) {
5209 case MPT_GET_NVRAM_VALS:
5210 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5211 hd->ioc->name));
5212 /* Get the NVRAM values and save in tmax
5213 * If not an LVD bus, the adapter minSyncFactor has been
5214 * already throttled back.
5215 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005216 negoFlags = hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
5218 width = pTarget->maxWidth;
5219 offset = pTarget->maxOffset;
5220 factor = pTarget->minSyncFactor;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005221 negoFlags |= pTarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 } else {
5223 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5224 data = hd->ioc->spi_data.nvram[id];
5225 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5226 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5227 factor = MPT_ASYNC;
5228 else {
5229 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5230 if ((factor == 0) || (factor == MPT_ASYNC)){
5231 factor = MPT_ASYNC;
5232 offset = 0;
5233 }
5234 }
5235 } else {
5236 width = MPT_NARROW;
5237 offset = 0;
5238 factor = MPT_ASYNC;
5239 }
5240
5241 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 if (!width)
5243 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5244
5245 if (!offset)
5246 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5247 }
5248
5249 /* limit by adapter capabilities */
5250 width = min(width, hd->ioc->spi_data.maxBusWidth);
5251 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5252 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5253
5254 /* Check Consistency */
5255 if (offset && (factor < MPT_ULTRA2) && !width)
5256 factor = MPT_ULTRA2;
5257
5258 dv->max.width = width;
5259 dv->max.offset = offset;
5260 dv->max.factor = factor;
5261 dv->max.flags = negoFlags;
5262 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5263 id, width, factor, offset, negoFlags));
5264 break;
5265
5266 case MPT_UPDATE_MAX:
5267 ddvprintk((MYIOC_s_NOTE_FMT
5268 "Updating with SDP0 Data: ", hd->ioc->name));
5269 /* Update tmax values with those from Device Page 0.*/
5270 pPage0 = (SCSIDevicePage0_t *) pPage;
5271 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005272 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5274 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5275 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5276 }
5277
5278 dv->now.width = dv->max.width;
5279 dv->now.offset = dv->max.offset;
5280 dv->now.factor = dv->max.factor;
5281 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5282 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5283 break;
5284
5285 case MPT_SET_MAX:
5286 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5287 hd->ioc->name));
5288 /* Set current to the max values. Update the config page.*/
5289 dv->now.width = dv->max.width;
5290 dv->now.offset = dv->max.offset;
5291 dv->now.factor = dv->max.factor;
5292 dv->now.flags = dv->max.flags;
5293
5294 pPage1 = (SCSIDevicePage1_t *)pPage;
5295 if (pPage1) {
5296 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5297 dv->now.offset, &val, &configuration, dv->now.flags);
5298 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5299 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005300 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005302 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 }
5304
Christoph Hellwig637fa992005-08-18 16:25:44 +02005305 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5307 break;
5308
5309 case MPT_SET_MIN:
5310 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5311 hd->ioc->name));
5312 /* Set page to asynchronous and narrow
5313 * Do not update now, breaks fallback routine. */
5314 width = MPT_NARROW;
5315 offset = 0;
5316 factor = MPT_ASYNC;
5317 negoFlags = dv->max.flags;
5318
5319 pPage1 = (SCSIDevicePage1_t *)pPage;
5320 if (pPage1) {
5321 mptscsih_setDevicePage1Flags (width, factor,
5322 offset, &val, &configuration, negoFlags);
5323 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5324 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005325 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005327 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 }
5329 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5330 id, width, factor, offset, val, configuration, negoFlags));
5331 break;
5332
5333 case MPT_FALLBACK:
5334 ddvprintk((MYIOC_s_NOTE_FMT
5335 "Fallback: Start: offset %d, factor %x, width %d \n",
5336 hd->ioc->name, dv->now.offset,
5337 dv->now.factor, dv->now.width));
5338 width = dv->now.width;
5339 offset = dv->now.offset;
5340 factor = dv->now.factor;
5341 if ((offset) && (dv->max.width)) {
5342 if (factor < MPT_ULTRA160)
5343 factor = MPT_ULTRA160;
5344 else if (factor < MPT_ULTRA2) {
5345 factor = MPT_ULTRA2;
5346 width = MPT_WIDE;
5347 } else if ((factor == MPT_ULTRA2) && width) {
5348 factor = MPT_ULTRA2;
5349 width = MPT_NARROW;
5350 } else if (factor < MPT_ULTRA) {
5351 factor = MPT_ULTRA;
5352 width = MPT_WIDE;
5353 } else if ((factor == MPT_ULTRA) && width) {
5354 width = MPT_NARROW;
5355 } else if (factor < MPT_FAST) {
5356 factor = MPT_FAST;
5357 width = MPT_WIDE;
5358 } else if ((factor == MPT_FAST) && width) {
5359 factor = MPT_FAST;
5360 width = MPT_NARROW;
5361 } else if (factor < MPT_SCSI) {
5362 factor = MPT_SCSI;
5363 width = MPT_WIDE;
5364 } else if ((factor == MPT_SCSI) && width) {
5365 factor = MPT_SCSI;
5366 width = MPT_NARROW;
5367 } else {
5368 factor = MPT_ASYNC;
5369 offset = 0;
5370 }
5371
5372 } else if (offset) {
5373 width = MPT_NARROW;
5374 if (factor < MPT_ULTRA)
5375 factor = MPT_ULTRA;
5376 else if (factor < MPT_FAST)
5377 factor = MPT_FAST;
5378 else if (factor < MPT_SCSI)
5379 factor = MPT_SCSI;
5380 else {
5381 factor = MPT_ASYNC;
5382 offset = 0;
5383 }
5384
5385 } else {
5386 width = MPT_NARROW;
5387 factor = MPT_ASYNC;
5388 }
5389 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5390 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5391
5392 dv->now.width = width;
5393 dv->now.offset = offset;
5394 dv->now.factor = factor;
5395 dv->now.flags = dv->max.flags;
5396
5397 pPage1 = (SCSIDevicePage1_t *)pPage;
5398 if (pPage1) {
5399 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5400 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005401 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 id, width, offset, factor, dv->now.flags, val, configuration));
5403
Christoph Hellwig637fa992005-08-18 16:25:44 +02005404 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005406 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 }
5408
5409 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5410 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5411 break;
5412
5413 case MPT_SAVE:
5414 ddvprintk((MYIOC_s_NOTE_FMT
5415 "Saving to Target structure: ", hd->ioc->name));
5416 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5417 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5418
5419 /* Save these values to target structures
5420 * or overwrite nvram (phys disks only).
5421 */
5422
5423 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
5424 pTarget->maxWidth = dv->now.width;
5425 pTarget->maxOffset = dv->now.offset;
5426 pTarget->minSyncFactor = dv->now.factor;
5427 pTarget->negoFlags = dv->now.flags;
5428 } else {
5429 /* Preserv all flags, use
5430 * read-modify-write algorithm
5431 */
5432 if (hd->ioc->spi_data.nvram) {
5433 data = hd->ioc->spi_data.nvram[id];
5434
5435 if (dv->now.width)
5436 data &= ~MPT_NVRAM_WIDE_DISABLE;
5437 else
5438 data |= MPT_NVRAM_WIDE_DISABLE;
5439
5440 if (!dv->now.offset)
5441 factor = MPT_ASYNC;
5442
5443 data &= ~MPT_NVRAM_SYNC_MASK;
5444 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5445
5446 hd->ioc->spi_data.nvram[id] = data;
5447 }
5448 }
5449 break;
5450 }
5451}
5452
5453/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5454/* mptscsih_fillbuf - fill a buffer with a special data pattern
5455 * cleanup. For bus scan only.
5456 *
5457 * @buffer: Pointer to data buffer to be filled.
5458 * @size: Number of bytes to fill
5459 * @index: Pattern index
5460 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5461 */
5462static void
5463mptscsih_fillbuf(char *buffer, int size, int index, int width)
5464{
5465 char *ptr = buffer;
5466 int ii;
5467 char byte;
5468 short val;
5469
5470 switch (index) {
5471 case 0:
5472
5473 if (width) {
5474 /* Pattern: 0000 FFFF 0000 FFFF
5475 */
5476 for (ii=0; ii < size; ii++, ptr++) {
5477 if (ii & 0x02)
5478 *ptr = 0xFF;
5479 else
5480 *ptr = 0x00;
5481 }
5482 } else {
5483 /* Pattern: 00 FF 00 FF
5484 */
5485 for (ii=0; ii < size; ii++, ptr++) {
5486 if (ii & 0x01)
5487 *ptr = 0xFF;
5488 else
5489 *ptr = 0x00;
5490 }
5491 }
5492 break;
5493
5494 case 1:
5495 if (width) {
5496 /* Pattern: 5555 AAAA 5555 AAAA 5555
5497 */
5498 for (ii=0; ii < size; ii++, ptr++) {
5499 if (ii & 0x02)
5500 *ptr = 0xAA;
5501 else
5502 *ptr = 0x55;
5503 }
5504 } else {
5505 /* Pattern: 55 AA 55 AA 55
5506 */
5507 for (ii=0; ii < size; ii++, ptr++) {
5508 if (ii & 0x01)
5509 *ptr = 0xAA;
5510 else
5511 *ptr = 0x55;
5512 }
5513 }
5514 break;
5515
5516 case 2:
5517 /* Pattern: 00 01 02 03 04 05
5518 * ... FE FF 00 01..
5519 */
5520 for (ii=0; ii < size; ii++, ptr++)
5521 *ptr = (char) ii;
5522 break;
5523
5524 case 3:
5525 if (width) {
5526 /* Wide Pattern: FFFE 0001 FFFD 0002
5527 * ... 4000 DFFF 8000 EFFF
5528 */
5529 byte = 0;
5530 for (ii=0; ii < size/2; ii++) {
5531 /* Create the base pattern
5532 */
5533 val = (1 << byte);
5534 /* every 64 (0x40) bytes flip the pattern
5535 * since we fill 2 bytes / iteration,
5536 * test for ii = 0x20
5537 */
5538 if (ii & 0x20)
5539 val = ~(val);
5540
5541 if (ii & 0x01) {
5542 *ptr = (char)( (val & 0xFF00) >> 8);
5543 ptr++;
5544 *ptr = (char)(val & 0xFF);
5545 byte++;
5546 byte &= 0x0F;
5547 } else {
5548 val = ~val;
5549 *ptr = (char)( (val & 0xFF00) >> 8);
5550 ptr++;
5551 *ptr = (char)(val & 0xFF);
5552 }
5553
5554 ptr++;
5555 }
5556 } else {
5557 /* Narrow Pattern: FE 01 FD 02 FB 04
5558 * .. 7F 80 01 FE 02 FD ... 80 7F
5559 */
5560 byte = 0;
5561 for (ii=0; ii < size; ii++, ptr++) {
5562 /* Base pattern - first 32 bytes
5563 */
5564 if (ii & 0x01) {
5565 *ptr = (1 << byte);
5566 byte++;
5567 byte &= 0x07;
5568 } else {
5569 *ptr = (char) (~(1 << byte));
5570 }
5571
5572 /* Flip the pattern every 32 bytes
5573 */
5574 if (ii & 0x20)
5575 *ptr = ~(*ptr);
5576 }
5577 }
5578 break;
5579 }
5580}
5581#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5582
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005583EXPORT_SYMBOL(mptscsih_remove);
5584EXPORT_SYMBOL(mptscsih_shutdown);
5585#ifdef CONFIG_PM
5586EXPORT_SYMBOL(mptscsih_suspend);
5587EXPORT_SYMBOL(mptscsih_resume);
5588#endif
5589EXPORT_SYMBOL(mptscsih_proc_info);
5590EXPORT_SYMBOL(mptscsih_info);
5591EXPORT_SYMBOL(mptscsih_qcmd);
5592EXPORT_SYMBOL(mptscsih_slave_alloc);
5593EXPORT_SYMBOL(mptscsih_slave_destroy);
5594EXPORT_SYMBOL(mptscsih_slave_configure);
5595EXPORT_SYMBOL(mptscsih_abort);
5596EXPORT_SYMBOL(mptscsih_dev_reset);
5597EXPORT_SYMBOL(mptscsih_bus_reset);
5598EXPORT_SYMBOL(mptscsih_host_reset);
5599EXPORT_SYMBOL(mptscsih_bios_param);
5600EXPORT_SYMBOL(mptscsih_io_done);
5601EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5602EXPORT_SYMBOL(mptscsih_scandv_complete);
5603EXPORT_SYMBOL(mptscsih_event_process);
5604EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005605EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005606EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005608/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/