blob: a5ca7494c8c1b668d82fd575ee2c3e94a972c5dd [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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
156static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
157static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
158static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400159int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
161static int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700162static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
170static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
171static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
172static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600173static void mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id);
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700174static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
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. */
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700680 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 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;
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700996#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 int count;
998 unsigned long flags;
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700999#endif
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001000 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001002 if(!host) {
1003 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007 scsi_remove_host(host);
1008
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001009 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1010 return;
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1013 /* Check DV thread active */
1014 count = 10 * HZ;
1015 spin_lock_irqsave(&dvtaskQ_lock, flags);
1016 if (dvtaskQ_active) {
1017 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
Nishanth Aravamudan65210182005-11-07 01:01:19 -08001018 while(dvtaskQ_active && --count)
1019 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 } else {
1021 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
1022 }
1023 if (!count)
1024 printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
1025#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
1026 else
1027 printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
1028#endif
1029#endif
1030
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001031 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001033 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001035 if (hd->ScsiLookup != NULL) {
1036 sz1 = hd->ioc->req_depth * sizeof(void *);
1037 kfree(hd->ScsiLookup);
1038 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
1040
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001041 /*
1042 * Free pointer array.
1043 */
1044 kfree(hd->Targets);
1045 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001047 dprintk((MYIOC_s_INFO_FMT
1048 "Free'd ScsiLookup (%d) memory\n",
1049 hd->ioc->name, sz1));
1050
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001051 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001052
1053 /* NULL the Scsi_Host pointer
1054 */
1055 hd->ioc->sh = NULL;
1056
1057 scsi_host_put(host);
1058
1059 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
1063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1064/*
1065 * mptscsih_shutdown - reboot notifier
1066 *
1067 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001068void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001069mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001071 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 struct Scsi_Host *host = ioc->sh;
1073 MPT_SCSI_HOST *hd;
1074
1075 if(!host)
1076 return;
1077
1078 hd = (MPT_SCSI_HOST *)host->hostdata;
1079
1080 /* Flush the cache of this adapter
1081 */
1082 if(hd != NULL)
1083 mptscsih_synchronize_cache(hd, 0);
1084
1085}
1086
1087#ifdef CONFIG_PM
1088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1089/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001090 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 *
1092 *
1093 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001094int
Pavel Machek8d189f72005-04-16 15:25:28 -07001095mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001097 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001098 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099}
1100
1101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1102/*
1103 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1104 *
1105 *
1106 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001107int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108mptscsih_resume(struct pci_dev *pdev)
1109{
1110 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1111 struct Scsi_Host *host = ioc->sh;
1112 MPT_SCSI_HOST *hd;
1113
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001114 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 if(!host)
1117 return 0;
1118
1119 hd = (MPT_SCSI_HOST *)host->hostdata;
1120 if(!hd)
1121 return 0;
1122
1123#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1124 {
1125 unsigned long lflags;
1126 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1127 if (!dvtaskQ_active) {
1128 dvtaskQ_active = 1;
1129 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001130 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001132 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 } else {
1134 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1135 }
1136 }
1137#endif
1138 return 0;
1139}
1140
1141#endif
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1144/**
1145 * mptscsih_info - Return information about MPT adapter
1146 * @SChost: Pointer to Scsi_Host structure
1147 *
1148 * (linux scsi_host_template.info routine)
1149 *
1150 * Returns pointer to buffer where information was written.
1151 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001152const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153mptscsih_info(struct Scsi_Host *SChost)
1154{
1155 MPT_SCSI_HOST *h;
1156 int size = 0;
1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001161 if (h->info_kbuf == NULL)
1162 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1163 return h->info_kbuf;
1164 h->info_kbuf[0] = '\0';
1165
1166 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1167 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001170 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171}
1172
1173struct info_str {
1174 char *buffer;
1175 int length;
1176 int offset;
1177 int pos;
1178};
1179
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180static void
1181mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
1183 if (info->pos + len > info->length)
1184 len = info->length - info->pos;
1185
1186 if (info->pos + len < info->offset) {
1187 info->pos += len;
1188 return;
1189 }
1190
1191 if (info->pos < info->offset) {
1192 data += (info->offset - info->pos);
1193 len -= (info->offset - info->pos);
1194 }
1195
1196 if (len > 0) {
1197 memcpy(info->buffer + info->pos, data, len);
1198 info->pos += len;
1199 }
1200}
1201
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001202static int
1203mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
1205 va_list args;
1206 char buf[81];
1207 int len;
1208
1209 va_start(args, fmt);
1210 len = vsprintf(buf, fmt, args);
1211 va_end(args);
1212
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001213 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 return len;
1215}
1216
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001217static int
1218mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219{
1220 struct info_str info;
1221
1222 info.buffer = pbuf;
1223 info.length = len;
1224 info.offset = offset;
1225 info.pos = 0;
1226
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001227 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1228 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1229 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1230 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1233}
1234
1235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1236/**
1237 * mptscsih_proc_info - Return information about MPT adapter
1238 *
1239 * (linux scsi_host_template.info routine)
1240 *
1241 * buffer: if write, user data; if read, buffer for user
1242 * length: if write, return length;
1243 * offset: if write, 0; if read, the current offset into the buffer from
1244 * the previous read.
1245 * hostno: scsi host number
1246 * func: if write = 1; if read = 0
1247 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001248int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1250 int length, int func)
1251{
1252 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1253 MPT_ADAPTER *ioc = hd->ioc;
1254 int size = 0;
1255
1256 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001257 /*
1258 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 */
1260 } else {
1261 if (start)
1262 *start = buffer;
1263
1264 size = mptscsih_host_info(ioc, buffer, offset, length);
1265 }
1266
1267 return size;
1268}
1269
1270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1271#define ADD_INDEX_LOG(req_ent) do { } while(0)
1272
1273/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1274/**
1275 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1276 * @SCpnt: Pointer to scsi_cmnd structure
1277 * @done: Pointer SCSI mid-layer IO completion function
1278 *
1279 * (linux scsi_host_template.queuecommand routine)
1280 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1281 * from a linux scsi_cmnd request and send it to the IOC.
1282 *
1283 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1284 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001285int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1287{
1288 MPT_SCSI_HOST *hd;
1289 MPT_FRAME_HDR *mf;
1290 SCSIIORequest_t *pScsiReq;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001291 VirtDevice *pTarget = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 int lun;
1293 u32 datalen;
1294 u32 scsictl;
1295 u32 scsidir;
1296 u32 cmd_len;
1297 int my_idx;
1298 int ii;
1299
1300 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 lun = SCpnt->device->lun;
1302 SCpnt->scsi_done = done;
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1305 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1306
1307 if (hd->resetPending) {
1308 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1309 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1310 return SCSI_MLQUEUE_HOST_BUSY;
1311 }
1312
1313 /*
1314 * Put together a MPT SCSI request...
1315 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001316 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1318 hd->ioc->name));
1319 return SCSI_MLQUEUE_HOST_BUSY;
1320 }
1321
1322 pScsiReq = (SCSIIORequest_t *) mf;
1323
1324 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1325
1326 ADD_INDEX_LOG(my_idx);
1327
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001328 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 * Seems we may receive a buffer (datalen>0) even when there
1330 * will be no data transfer! GRRRRR...
1331 */
1332 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1333 datalen = SCpnt->request_bufflen;
1334 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1335 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1336 datalen = SCpnt->request_bufflen;
1337 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1338 } else {
1339 datalen = 0;
1340 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1341 }
1342
1343 /* Default to untagged. Once a target structure has been allocated,
1344 * use the Inquiry data to determine if device supports tagged.
1345 */
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001346 if (pTarget
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
1348 && (SCpnt->device->tagged_supported)) {
1349 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1350 } else {
1351 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1352 }
1353
1354 /* Use the above information to set up the message frame
1355 */
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001356 pScsiReq->TargetID = (u8) pTarget->target_id;
1357 pScsiReq->Bus = pTarget->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 pScsiReq->ChainOffset = 0;
1359 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1360 pScsiReq->CDBLength = SCpnt->cmd_len;
1361 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1362 pScsiReq->Reserved = 0;
1363 pScsiReq->MsgFlags = mpt_msg_flags();
1364 pScsiReq->LUN[0] = 0;
1365 pScsiReq->LUN[1] = lun;
1366 pScsiReq->LUN[2] = 0;
1367 pScsiReq->LUN[3] = 0;
1368 pScsiReq->LUN[4] = 0;
1369 pScsiReq->LUN[5] = 0;
1370 pScsiReq->LUN[6] = 0;
1371 pScsiReq->LUN[7] = 0;
1372 pScsiReq->Control = cpu_to_le32(scsictl);
1373
1374 /*
1375 * Write SCSI CDB into the message
1376 */
1377 cmd_len = SCpnt->cmd_len;
1378 for (ii=0; ii < cmd_len; ii++)
1379 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1380
1381 for (ii=cmd_len; ii < 16; ii++)
1382 pScsiReq->CDB[ii] = 0;
1383
1384 /* DataLength */
1385 pScsiReq->DataLength = cpu_to_le32(datalen);
1386
1387 /* SenseBuffer low address */
1388 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1389 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1390
1391 /* Now add the SG list
1392 * Always have a SGE even if null length.
1393 */
1394 if (datalen == 0) {
1395 /* Add a NULL SGE */
1396 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1397 (dma_addr_t) -1);
1398 } else {
1399 /* Add a 32 or 64 bit SGE */
1400 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1401 goto fail;
1402 }
1403
1404 hd->ScsiLookup[my_idx] = SCpnt;
1405 SCpnt->host_scribble = NULL;
1406
1407#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001408 if (hd->ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001409 int dvStatus = hd->ioc->spi_data.dvStatus[pTarget->target_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 int issueCmd = 1;
1411
1412 if (dvStatus || hd->ioc->spi_data.forceDv) {
1413
1414 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1415 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1416 unsigned long lflags;
1417 /* Schedule DV if necessary */
1418 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1419 if (!dvtaskQ_active) {
1420 dvtaskQ_active = 1;
1421 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001422 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001424 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 } else {
1426 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1427 }
1428 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1429 }
1430
1431 /* Trying to do DV to this target, extend timeout.
1432 * Wait to issue until flag is clear
1433 */
1434 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1435 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1436 issueCmd = 0;
1437 }
1438
1439 /* Set the DV flags.
1440 */
1441 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
1442 mptscsih_set_dvflags(hd, pScsiReq);
1443
1444 if (!issueCmd)
1445 goto fail;
1446 }
1447 }
1448#endif
1449
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001450 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1452 hd->ioc->name, SCpnt, mf, my_idx));
1453 DBG_DUMP_REQUEST_FRAME(mf)
1454 return 0;
1455
1456 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001457 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1459 mpt_free_msg_frame(hd->ioc, mf);
1460 return SCSI_MLQUEUE_HOST_BUSY;
1461}
1462
1463/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1464/*
1465 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1466 * with a SCSI IO request
1467 * @hd: Pointer to the MPT_SCSI_HOST instance
1468 * @req_idx: Index of the SCSI IO request frame.
1469 *
1470 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1471 * No return.
1472 */
1473static void
1474mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1475{
1476 MPT_FRAME_HDR *chain;
1477 unsigned long flags;
1478 int chain_idx;
1479 int next;
1480
1481 /* Get the first chain index and reset
1482 * tracker state.
1483 */
1484 chain_idx = ioc->ReqToChain[req_idx];
1485 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1486
1487 while (chain_idx != MPT_HOST_NO_CHAIN) {
1488
1489 /* Save the next chain buffer index */
1490 next = ioc->ChainToChain[chain_idx];
1491
1492 /* Free this chain buffer and reset
1493 * tracker
1494 */
1495 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1496
1497 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1498 + (chain_idx * ioc->req_sz));
1499
1500 spin_lock_irqsave(&ioc->FreeQlock, flags);
1501 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1502 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1503
1504 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1505 ioc->name, chain_idx));
1506
1507 /* handle next */
1508 chain_idx = next;
1509 }
1510 return;
1511}
1512
1513/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1514/*
1515 * Reset Handling
1516 */
1517
1518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1519/*
1520 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1521 * Fall through to mpt_HardResetHandler if: not operational, too many
1522 * failed TM requests or handshake failure.
1523 *
1524 * @ioc: Pointer to MPT_ADAPTER structure
1525 * @type: Task Management type
1526 * @target: Logical Target ID for reset (if appropriate)
1527 * @lun: Logical Unit for reset (if appropriate)
1528 * @ctx2abort: Context for the task to be aborted (if appropriate)
1529 *
1530 * Remark: Currently invoked from a non-interrupt thread (_bh).
1531 *
1532 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1533 * will be active.
1534 *
1535 * Returns 0 for SUCCESS or -1 if FAILED.
1536 */
1537static int
1538mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1539{
1540 MPT_ADAPTER *ioc;
1541 int rc = -1;
1542 int doTask = 1;
1543 u32 ioc_raw_state;
1544 unsigned long flags;
1545
1546 /* If FW is being reloaded currently, return success to
1547 * the calling function.
1548 */
1549 if (hd == NULL)
1550 return 0;
1551
1552 ioc = hd->ioc;
1553 if (ioc == NULL) {
1554 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1555 return FAILED;
1556 }
1557 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1558
1559 // SJR - CHECKME - Can we avoid this here?
1560 // (mpt_HardResetHandler has this check...)
1561 spin_lock_irqsave(&ioc->diagLock, flags);
1562 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1563 spin_unlock_irqrestore(&ioc->diagLock, flags);
1564 return FAILED;
1565 }
1566 spin_unlock_irqrestore(&ioc->diagLock, flags);
1567
1568 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1569 * If we time out and not bus reset, then we return a FAILED status to the caller.
1570 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1571 * successful. Otherwise, reload the FW.
1572 */
1573 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1574 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001575 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 "Timed out waiting for last TM (%d) to complete! \n",
1577 hd->ioc->name, hd->tmPending));
1578 return FAILED;
1579 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001580 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 "Timed out waiting for last TM (%d) to complete! \n",
1582 hd->ioc->name, hd->tmPending));
1583 return FAILED;
1584 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001585 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 "Timed out waiting for last TM (%d) to complete! \n",
1587 hd->ioc->name, hd->tmPending));
1588 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1589 return FAILED;
1590
1591 doTask = 0;
1592 }
1593 } else {
1594 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1595 hd->tmPending |= (1 << type);
1596 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1597 }
1598
1599 /* Is operational?
1600 */
1601 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1602
1603#ifdef MPT_DEBUG_RESET
1604 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1605 printk(MYIOC_s_WARN_FMT
1606 "TM Handler: IOC Not operational(0x%x)!\n",
1607 hd->ioc->name, ioc_raw_state);
1608 }
1609#endif
1610
1611 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1612 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1613
1614 /* Isse the Task Mgmt request.
1615 */
1616 if (hd->hard_resets < -1)
1617 hd->hard_resets++;
1618 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1619 if (rc) {
1620 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1621 } else {
1622 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1623 }
1624 }
1625
1626 /* Only fall through to the HRH if this is a bus reset
1627 */
1628 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1629 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1630 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1631 hd->ioc->name));
1632 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1633 }
1634
1635 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1636
1637 return rc;
1638}
1639
1640
1641/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1642/*
1643 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1644 * @hd: Pointer to MPT_SCSI_HOST structure
1645 * @type: Task Management type
1646 * @target: Logical Target ID for reset (if appropriate)
1647 * @lun: Logical Unit for reset (if appropriate)
1648 * @ctx2abort: Context for the task to be aborted (if appropriate)
1649 *
1650 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1651 * or a non-interrupt thread. In the former, must not call schedule().
1652 *
1653 * Not all fields are meaningfull for all task types.
1654 *
1655 * Returns 0 for SUCCESS, -999 for "no msg frames",
1656 * else other non-zero value returned.
1657 */
1658static int
1659mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1660{
1661 MPT_FRAME_HDR *mf;
1662 SCSITaskMgmt_t *pScsiTm;
1663 int ii;
1664 int retval;
1665
1666 /* Return Fail to calling function if no message frames available.
1667 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001668 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1670 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001671 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 }
1673 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1674 hd->ioc->name, mf));
1675
1676 /* Format the Request
1677 */
1678 pScsiTm = (SCSITaskMgmt_t *) mf;
1679 pScsiTm->TargetID = target;
1680 pScsiTm->Bus = channel;
1681 pScsiTm->ChainOffset = 0;
1682 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1683
1684 pScsiTm->Reserved = 0;
1685 pScsiTm->TaskType = type;
1686 pScsiTm->Reserved1 = 0;
1687 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1688 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1689
1690 for (ii= 0; ii < 8; ii++) {
1691 pScsiTm->LUN[ii] = 0;
1692 }
1693 pScsiTm->LUN[1] = lun;
1694
1695 for (ii=0; ii < 7; ii++)
1696 pScsiTm->Reserved2[ii] = 0;
1697
1698 pScsiTm->TaskMsgContext = ctx2abort;
1699
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001700 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1701 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1704
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001705 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1707 CAN_SLEEP)) != 0) {
1708 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1709 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1710 hd->ioc, mf));
1711 mpt_free_msg_frame(hd->ioc, mf);
1712 return retval;
1713 }
1714
1715 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1716 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1717 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1718 hd->ioc, mf));
1719 mpt_free_msg_frame(hd->ioc, mf);
1720 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1721 hd->ioc->name));
1722 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1723 }
1724
1725 return retval;
1726}
1727
1728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1729/**
1730 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1731 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1732 *
1733 * (linux scsi_host_template.eh_abort_handler routine)
1734 *
1735 * Returns SUCCESS or FAILED.
1736 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001737int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738mptscsih_abort(struct scsi_cmnd * SCpnt)
1739{
1740 MPT_SCSI_HOST *hd;
1741 MPT_ADAPTER *ioc;
1742 MPT_FRAME_HDR *mf;
1743 u32 ctx2abort;
1744 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001745 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 /* If we can't locate our host adapter structure, return FAILED status.
1748 */
1749 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1750 SCpnt->result = DID_RESET << 16;
1751 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001752 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 "Can't locate host! (sc=%p)\n",
1754 SCpnt));
1755 return FAILED;
1756 }
1757
1758 ioc = hd->ioc;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001759 if (hd->resetPending) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 return FAILED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
1763 if (hd->timeouts < -1)
1764 hd->timeouts++;
1765
1766 /* Find this command
1767 */
1768 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001769 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 * Do OS callback.
1771 */
1772 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001773 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 "Command not in the active list! (sc=%p)\n",
1775 hd->ioc->name, SCpnt));
1776 return SUCCESS;
1777 }
1778
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001779 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1780 hd->ioc->name, SCpnt);
1781 scsi_print_command(SCpnt);
1782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1784 * (the IO to be ABORT'd)
1785 *
1786 * NOTE: Since we do not byteswap MsgContext, we do not
1787 * swap it here either. It is an opaque cookie to
1788 * the controller, so it does not matter. -DaveM
1789 */
1790 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1791 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1792
1793 hd->abortSCpnt = SCpnt;
1794
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001795 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001797 ctx2abort, 2 /* 2 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1800 hd->ioc->name,
1801 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001803 if (retval == 0)
1804 return SUCCESS;
1805
1806 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 hd->tmPending = 0;
1808 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001810 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811}
1812
1813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1814/**
1815 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1816 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1817 *
1818 * (linux scsi_host_template.eh_dev_reset_handler routine)
1819 *
1820 * Returns SUCCESS or FAILED.
1821 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001822int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1824{
1825 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001826 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
1828 /* If we can't locate our host adapter structure, return FAILED status.
1829 */
1830 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001831 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 "Can't locate host! (sc=%p)\n",
1833 SCpnt));
1834 return FAILED;
1835 }
1836
1837 if (hd->resetPending)
1838 return FAILED;
1839
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001840 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001844 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 SCpnt->device->channel, SCpnt->device->id,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001846 0, 0, 5 /* 5 second timeout */);
1847
1848 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1849 hd->ioc->name,
1850 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1851
1852 if (retval == 0)
1853 return SUCCESS;
1854
1855 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 hd->tmPending = 0;
1857 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001859 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860}
1861
1862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1863/**
1864 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1865 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1866 *
1867 * (linux scsi_host_template.eh_bus_reset_handler routine)
1868 *
1869 * Returns SUCCESS or FAILED.
1870 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001871int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1873{
1874 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001875 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
1877 /* If we can't locate our host adapter structure, return FAILED status.
1878 */
1879 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001880 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 "Can't locate host! (sc=%p)\n",
1882 SCpnt ) );
1883 return FAILED;
1884 }
1885
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001886 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001888 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 if (hd->timeouts < -1)
1891 hd->timeouts++;
1892
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001893 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1894 SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001896 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1897 hd->ioc->name,
1898 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1899
1900 if (retval == 0)
1901 return SUCCESS;
1902
1903 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 hd->tmPending = 0;
1905 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001907 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908}
1909
1910/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1911/**
1912 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1913 * new_eh variant
1914 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1915 *
1916 * (linux scsi_host_template.eh_host_reset_handler routine)
1917 *
1918 * Returns SUCCESS or FAILED.
1919 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001920int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1922{
1923 MPT_SCSI_HOST * hd;
1924 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
1926 /* If we can't locate the host to reset, then we failed. */
1927 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001928 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 "Can't locate host! (sc=%p)\n",
1930 SCpnt ) );
1931 return FAILED;
1932 }
1933
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001934 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 hd->ioc->name, SCpnt);
1936
1937 /* If our attempts to reset the host failed, then return a failed
1938 * status. The host will be taken off line by the SCSI mid-layer.
1939 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1941 status = FAILED;
1942 } else {
1943 /* Make sure TM pending is cleared and TM state is set to
1944 * NONE.
1945 */
1946 hd->tmPending = 0;
1947 hd->tmState = TM_STATE_NONE;
1948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001950 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 "Status = %s\n",
1952 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1953
1954 return status;
1955}
1956
1957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1958/**
1959 * mptscsih_tm_pending_wait - wait for pending task management request to
1960 * complete.
1961 * @hd: Pointer to MPT host structure.
1962 *
1963 * Returns {SUCCESS,FAILED}.
1964 */
1965static int
1966mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1967{
1968 unsigned long flags;
1969 int loop_count = 4 * 10; /* Wait 10 seconds */
1970 int status = FAILED;
1971
1972 do {
1973 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1974 if (hd->tmState == TM_STATE_NONE) {
1975 hd->tmState = TM_STATE_IN_PROGRESS;
1976 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001978 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 break;
1980 }
1981 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1982 msleep(250);
1983 } while (--loop_count);
1984
1985 return status;
1986}
1987
1988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1989/**
1990 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1991 * @hd: Pointer to MPT host structure.
1992 *
1993 * Returns {SUCCESS,FAILED}.
1994 */
1995static int
1996mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1997{
1998 unsigned long flags;
1999 int loop_count = 4 * timeout;
2000 int status = FAILED;
2001
2002 do {
2003 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2004 if(hd->tmPending == 0) {
2005 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002006 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 break;
2008 }
2009 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2010 msleep_interruptible(250);
2011 } while (--loop_count);
2012
2013 return status;
2014}
2015
2016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2017/**
2018 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2019 * @ioc: Pointer to MPT_ADAPTER structure
2020 * @mf: Pointer to SCSI task mgmt request frame
2021 * @mr: Pointer to SCSI task mgmt reply frame
2022 *
2023 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2024 * of any SCSI task management request.
2025 * This routine is registered with the MPT (base) driver at driver
2026 * load/init time via the mpt_register() API call.
2027 *
2028 * Returns 1 indicating alloc'd request frame ptr should be freed.
2029 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002030int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2032{
2033 SCSITaskMgmtReply_t *pScsiTmReply;
2034 SCSITaskMgmt_t *pScsiTmReq;
2035 MPT_SCSI_HOST *hd;
2036 unsigned long flags;
2037 u16 iocstatus;
2038 u8 tmType;
2039
2040 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2041 ioc->name, mf, mr));
2042 if (ioc->sh) {
2043 /* Depending on the thread, a timer is activated for
2044 * the TM request. Delete this timer on completion of TM.
2045 * Decrement count of outstanding TM requests.
2046 */
2047 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2048 } else {
2049 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2050 ioc->name));
2051 return 1;
2052 }
2053
2054 if (mr == NULL) {
2055 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2056 ioc->name, mf));
2057 return 1;
2058 } else {
2059 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2060 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2061
2062 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2063 tmType = pScsiTmReq->TaskType;
2064
2065 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2066 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2067 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2068
2069 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2070 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2071 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2072 /* Error? (anything non-zero?) */
2073 if (iocstatus) {
2074
2075 /* clear flags and continue.
2076 */
2077 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2078 hd->abortSCpnt = NULL;
2079
2080 /* If an internal command is present
2081 * or the TM failed - reload the FW.
2082 * FC FW may respond FAILED to an ABORT
2083 */
2084 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2085 if ((hd->cmdPtr) ||
2086 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2087 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2088 printk((KERN_WARNING
2089 " Firmware Reload FAILED!!\n"));
2090 }
2091 }
2092 }
2093 } else {
2094 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2095
2096 hd->abortSCpnt = NULL;
2097
2098 }
2099 }
2100
2101 spin_lock_irqsave(&ioc->FreeQlock, flags);
2102 hd->tmPending = 0;
2103 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2104 hd->tmState = TM_STATE_NONE;
2105
2106 return 1;
2107}
2108
2109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2110/*
2111 * This is anyones guess quite frankly.
2112 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002113int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2115 sector_t capacity, int geom[])
2116{
2117 int heads;
2118 int sectors;
2119 sector_t cylinders;
2120 ulong dummy;
2121
2122 heads = 64;
2123 sectors = 32;
2124
2125 dummy = heads * sectors;
2126 cylinders = capacity;
2127 sector_div(cylinders,dummy);
2128
2129 /*
2130 * Handle extended translation size for logical drives
2131 * > 1Gb
2132 */
2133 if ((ulong)capacity >= 0x200000) {
2134 heads = 255;
2135 sectors = 63;
2136 dummy = heads * sectors;
2137 cylinders = capacity;
2138 sector_div(cylinders,dummy);
2139 }
2140
2141 /* return result */
2142 geom[0] = heads;
2143 geom[1] = sectors;
2144 geom[2] = cylinders;
2145
2146 dprintk((KERN_NOTICE
2147 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2148 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2149
2150 return 0;
2151}
2152
2153/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2154/*
2155 * OS entry point to allow host driver to alloc memory
2156 * for each scsi device. Called once per device the bus scan.
2157 * Return non-zero if allocation fails.
2158 * Init memory once per id (not LUN).
2159 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002160int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161mptscsih_slave_alloc(struct scsi_device *device)
2162{
2163 struct Scsi_Host *host = device->host;
2164 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2165 VirtDevice *vdev;
2166 uint target = device->id;
2167
2168 if (hd == NULL)
2169 return -ENODEV;
2170
2171 if ((vdev = hd->Targets[target]) != NULL)
2172 goto out;
2173
2174 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
2175 if (!vdev) {
2176 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2177 hd->ioc->name, sizeof(VirtDevice));
2178 return -ENOMEM;
2179 }
2180
2181 memset(vdev, 0, sizeof(VirtDevice));
2182 vdev->tflags = MPT_TARGET_FLAGS_Q_YES;
2183 vdev->ioc_id = hd->ioc->id;
2184 vdev->target_id = device->id;
2185 vdev->bus_id = device->channel;
2186 vdev->raidVolume = 0;
2187 hd->Targets[device->id] = vdev;
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002188 if (hd->ioc->bus_type == SPI) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002189 if (hd->ioc->raid_data.isRaid & (1 << device->id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 vdev->raidVolume = 1;
2191 ddvtprintk((KERN_INFO
2192 "RAID Volume @ id %d\n", device->id));
2193 }
2194 } else {
2195 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2196 }
2197
2198 out:
2199 vdev->num_luns++;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002200 device->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 return 0;
2202}
2203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204/*
2205 * OS entry point to allow for host driver to free allocated memory
2206 * Called if no device present or device being unloaded
2207 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002208void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209mptscsih_slave_destroy(struct scsi_device *device)
2210{
2211 struct Scsi_Host *host = device->host;
2212 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2213 VirtDevice *vdev;
2214 uint target = device->id;
2215 uint lun = device->lun;
2216
2217 if (hd == NULL)
2218 return;
2219
2220 mptscsih_search_running_cmds(hd, target, lun);
2221
2222 vdev = hd->Targets[target];
2223 vdev->luns[0] &= ~(1 << lun);
2224 if (--vdev->num_luns)
2225 return;
2226
2227 kfree(hd->Targets[target]);
2228 hd->Targets[target] = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002229
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002230 if (hd->ioc->bus_type == SPI) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002231 if (mptscsih_is_phys_disk(hd->ioc, target)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2233 } else {
2234 hd->ioc->spi_data.dvStatus[target] =
2235 MPT_SCSICFG_NEGOTIATE;
2236
2237 if (!hd->negoNvram) {
2238 hd->ioc->spi_data.dvStatus[target] |=
2239 MPT_SCSICFG_DV_NOT_DONE;
2240 }
2241 }
2242 }
2243}
2244
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2246/*
2247 * mptscsih_change_queue_depth - This function will set a devices queue depth
2248 * @sdev: per scsi_device pointer
2249 * @qdepth: requested queue depth
2250 *
2251 * Adding support for new 'change_queue_depth' api.
2252*/
2253int
2254mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255{
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002256 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2257 VirtDevice *pTarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 int max_depth;
2259 int tagged;
2260
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002261 if (hd == NULL)
2262 return 0;
2263 if (!(pTarget = hd->Targets[sdev->id]))
2264 return 0;
2265
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002266 if (hd->ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2268 if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
2269 max_depth = 1;
2270 else if (((pTarget->inq_data[0] & 0x1f) == 0x00) &&
2271 (pTarget->minSyncFactor <= MPT_ULTRA160 ))
2272 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2273 else
2274 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2275 } else {
2276 /* error case - No Inq. Data */
2277 max_depth = 1;
2278 }
2279 } else
2280 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2281
2282 if (qdepth > max_depth)
2283 qdepth = max_depth;
2284 if (qdepth == 1)
2285 tagged = 0;
2286 else
2287 tagged = MSG_SIMPLE_TAG;
2288
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002289 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2290 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291}
2292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293/*
2294 * OS entry point to adjust the queue_depths on a per-device basis.
2295 * Called once per device the bus scan. Use it to force the queue_depth
2296 * member to 1 if a device does not support Q tags.
2297 * Return non-zero if fails.
2298 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002299int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300mptscsih_slave_configure(struct scsi_device *device)
2301{
2302 struct Scsi_Host *sh = device->host;
2303 VirtDevice *pTarget;
2304 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2305
2306 if ((hd == NULL) || (hd->Targets == NULL)) {
2307 return 0;
2308 }
2309
2310 dsprintk((MYIOC_s_INFO_FMT
2311 "device @ %p, id=%d, LUN=%d, channel=%d\n",
2312 hd->ioc->name, device, device->id, device->lun, device->channel));
2313 dsprintk((MYIOC_s_INFO_FMT
2314 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2315 hd->ioc->name, device->sdtr, device->wdtr,
2316 device->ppr, device->inquiry_len));
2317
2318 if (device->id > sh->max_id) {
2319 /* error case, should never happen */
2320 scsi_adjust_queue_depth(device, 0, 1);
2321 goto slave_configure_exit;
2322 }
2323
2324 pTarget = hd->Targets[device->id];
2325
2326 if (pTarget == NULL) {
2327 /* Driver doesn't know about this device.
2328 * Kernel may generate a "Dummy Lun 0" which
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002329 * may become a real Lun if a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 * "scsi add-single-device" command is executed
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002331 * while the driver is active (hot-plug a
2332 * device). LSI Raid controllers need
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 * queue_depth set to DEV_HIGH for this reason.
2334 */
2335 scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
2336 MPT_SCSI_CMD_PER_DEV_HIGH);
2337 goto slave_configure_exit;
2338 }
2339
2340 mptscsih_initTarget(hd, device->channel, device->id, device->lun,
2341 device->inquiry, device->inquiry_len );
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002342 mptscsih_change_queue_depth(device, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
2344 dsprintk((MYIOC_s_INFO_FMT
2345 "Queue depth=%d, tflags=%x\n",
2346 hd->ioc->name, device->queue_depth, pTarget->tflags));
2347
2348 dsprintk((MYIOC_s_INFO_FMT
2349 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2350 hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor));
2351
2352slave_configure_exit:
2353
2354 dsprintk((MYIOC_s_INFO_FMT
2355 "tagged %d, simple %d, ordered %d\n",
2356 hd->ioc->name,device->tagged_supported, device->simple_tags,
2357 device->ordered_tags));
2358
2359 return 0;
2360}
2361
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2363/*
2364 * Private routines...
2365 */
2366
2367/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2368/* Utility function to copy sense data from the scsi_cmnd buffer
2369 * to the FC and SCSI target structures.
2370 *
2371 */
2372static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002373mptscsih_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 -07002374{
2375 VirtDevice *target;
2376 SCSIIORequest_t *pReq;
2377 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
2378 int index;
2379
2380 /* Get target structure
2381 */
2382 pReq = (SCSIIORequest_t *) mf;
2383 index = (int) pReq->TargetID;
2384 target = hd->Targets[index];
2385
2386 if (sense_count) {
2387 u8 *sense_data;
2388 int req_index;
2389
2390 /* Copy the sense received into the scsi command block. */
2391 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2392 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2393 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2394
2395 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2396 */
2397 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2398 if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
2399 int idx;
2400 MPT_ADAPTER *ioc = hd->ioc;
2401
2402 idx = ioc->eventContext % ioc->eventLogSize;
2403 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2404 ioc->events[idx].eventContext = ioc->eventContext;
2405
2406 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2407 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
2408 (pReq->Bus << 8) || pReq->TargetID;
2409
2410 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2411
2412 ioc->eventContext++;
2413 }
2414 }
2415 } else {
2416 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2417 hd->ioc->name));
2418 }
2419}
2420
2421static u32
2422SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2423{
2424 MPT_SCSI_HOST *hd;
2425 int i;
2426
2427 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2428
2429 for (i = 0; i < hd->ioc->req_depth; i++) {
2430 if (hd->ScsiLookup[i] == sc) {
2431 return i;
2432 }
2433 }
2434
2435 return -1;
2436}
2437
2438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002439int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2441{
2442 MPT_SCSI_HOST *hd;
2443 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002444 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
2446 dtmprintk((KERN_WARNING MYNAM
2447 ": IOC %s_reset routed to SCSI host driver!\n",
2448 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2449 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2450
2451 /* If a FW reload request arrives after base installed but
2452 * before all scsi hosts have been attached, then an alt_ioc
2453 * may have a NULL sh pointer.
2454 */
2455 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2456 return 0;
2457 else
2458 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2459
2460 if (reset_phase == MPT_IOC_SETUP_RESET) {
2461 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2462
2463 /* Clean Up:
2464 * 1. Set Hard Reset Pending Flag
2465 * All new commands go to doneQ
2466 */
2467 hd->resetPending = 1;
2468
2469 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2470 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2471
2472 /* 2. Flush running commands
2473 * Clean ScsiLookup (and associated memory)
2474 * AND clean mytaskQ
2475 */
2476
2477 /* 2b. Reply to OS all known outstanding I/O commands.
2478 */
2479 mptscsih_flush_running_cmds(hd);
2480
2481 /* 2c. If there was an internal command that
2482 * has not completed, configuration or io request,
2483 * free these resources.
2484 */
2485 if (hd->cmdPtr) {
2486 del_timer(&hd->timer);
2487 mpt_free_msg_frame(ioc, hd->cmdPtr);
2488 }
2489
2490 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2491
2492 } else {
2493 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2494
2495 /* Once a FW reload begins, all new OS commands are
2496 * redirected to the doneQ w/ a reset status.
2497 * Init all control structures.
2498 */
2499
2500 /* ScsiLookup initialization
2501 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002502 for (ii=0; ii < hd->ioc->req_depth; ii++)
2503 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
2505 /* 2. Chain Buffer initialization
2506 */
2507
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002508 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002510 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2512 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2513 }
2514
2515 /* 5. Enable new commands to be posted
2516 */
2517 spin_lock_irqsave(&ioc->FreeQlock, flags);
2518 hd->tmPending = 0;
2519 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2520 hd->resetPending = 0;
2521 hd->tmState = TM_STATE_NONE;
2522
2523 /* 6. If there was an internal command,
2524 * wake this process up.
2525 */
2526 if (hd->cmdPtr) {
2527 /*
2528 * Wake up the original calling thread
2529 */
2530 hd->pLocal = &hd->localReply;
2531 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002532 hd->scandv_wait_done = 1;
2533 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 hd->cmdPtr = NULL;
2535 }
2536
2537 /* 7. Set flag to force DV and re-read IOC Page 3
2538 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002539 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2541 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2542 }
2543
2544 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2545
2546 }
2547
2548 return 1; /* currently means nothing really */
2549}
2550
2551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002552/* work queue thread to clear the persitency table */
2553static void
2554mptscsih_sas_persist_clear_table(void * arg)
2555{
2556 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
2557
2558 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2559}
2560
2561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002562int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2564{
2565 MPT_SCSI_HOST *hd;
2566 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2567
2568 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2569 ioc->name, event));
2570
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002571 if (ioc->sh == NULL ||
2572 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2573 return 1;
2574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 switch (event) {
2576 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2577 /* FIXME! */
2578 break;
2579 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2580 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002581 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002582 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 break;
2584 case MPI_EVENT_LOGOUT: /* 09 */
2585 /* FIXME! */
2586 break;
2587
2588 /*
2589 * CHECKME! Don't think we need to do
2590 * anything for these, but...
2591 */
2592 case MPI_EVENT_RESCAN: /* 06 */
2593 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2594 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2595 /*
2596 * CHECKME! Falling thru...
2597 */
2598 break;
2599
2600 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002601 {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07002602#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002603 pMpiEventDataRaid_t pRaidEventData =
2604 (pMpiEventDataRaid_t) pEvReply->Data;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002605 /* Domain Validation Needed */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002606 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002607 pRaidEventData->ReasonCode ==
2608 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2609 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002611 break;
2612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002614 /* Persistent table is full. */
2615 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2616 INIT_WORK(&mptscsih_persistTask,
2617 mptscsih_sas_persist_clear_table,(void *)ioc);
2618 schedule_work(&mptscsih_persistTask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 break;
2620
2621 case MPI_EVENT_NONE: /* 00 */
2622 case MPI_EVENT_LOG_DATA: /* 01 */
2623 case MPI_EVENT_STATE_CHANGE: /* 02 */
2624 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2625 default:
2626 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2627 break;
2628 }
2629
2630 return 1; /* currently means nothing really */
2631}
2632
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2634/*
2635 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2636 * @hd: Pointer to MPT_SCSI_HOST structure
2637 * @bus_id: Bus number (?)
2638 * @target_id: SCSI target id
2639 * @lun: SCSI LUN id
2640 * @data: Pointer to data
2641 * @dlen: Number of INQUIRY bytes
2642 *
2643 * NOTE: It's only SAFE to call this routine if data points to
2644 * sane & valid STANDARD INQUIRY data!
2645 *
2646 * Allocate and initialize memory for this target.
2647 * Save inquiry data.
2648 *
2649 */
2650static void
2651mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
2652{
2653 int indexed_lun, lun_index;
2654 VirtDevice *vdev;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002655 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 char data_56;
2657
2658 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
2659 hd->ioc->name, bus_id, target_id, lun, hd));
2660
2661 /*
2662 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2663 * (i.e. The targer is capable of supporting the specified peripheral device type
2664 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002665 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 * capable of supporting a physical device on this logical unit). This is to work
2667 * around a bug in th emid-layer in some distributions in which the mid-layer will
2668 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2669 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002670 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 /* Is LUN supported? If so, upper 2 bits will be 0
2674 * in first byte of inquiry data.
2675 */
2676 if (data[0] & 0xe0)
2677 return;
2678
2679 if ((vdev = hd->Targets[target_id]) == NULL) {
2680 return;
2681 }
2682
2683 lun_index = (lun >> 5); /* 32 luns per lun_index */
2684 indexed_lun = (lun % 32);
2685 vdev->luns[lun_index] |= (1 << indexed_lun);
2686
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002687 if (hd->ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2689 /* Treat all Processors as SAF-TE if
2690 * command line option is set */
2691 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2692 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2693 }else if ((data[0] == TYPE_PROCESSOR) &&
2694 !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2695 if ( dlen > 49 ) {
2696 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2697 if ( data[44] == 'S' &&
2698 data[45] == 'A' &&
2699 data[46] == 'F' &&
2700 data[47] == '-' &&
2701 data[48] == 'T' &&
2702 data[49] == 'E' ) {
2703 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2704 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2705 }
2706 }
2707 }
2708 if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2709 if ( dlen > 8 ) {
2710 memcpy (vdev->inq_data, data, 8);
2711 } else {
2712 memcpy (vdev->inq_data, data, dlen);
2713 }
2714
2715 /* If have not done DV, set the DV flag.
2716 */
2717 pSpi = &hd->ioc->spi_data;
2718 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2719 if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
2720 pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
2721 }
2722
2723 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2724
2725
2726 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2727 if (dlen > 56) {
2728 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2729 /* Update the target capabilities
2730 */
2731 data_56 = data[56];
2732 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2733 }
2734 }
2735 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2736 } else {
2737 /* Initial Inquiry may not request enough data bytes to
2738 * obtain byte 57. DV will; if target doesn't return
2739 * at least 57 bytes, data[56] will be zero. */
2740 if (dlen > 56) {
2741 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2742 /* Update the target capabilities
2743 */
2744 data_56 = data[56];
2745 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2746 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2747 }
2748 }
2749 }
2750 }
2751}
2752
2753/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2754/*
2755 * Update the target negotiation parameters based on the
2756 * the Inquiry data, adapter capabilities, and NVRAM settings.
2757 *
2758 */
2759static void
2760mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
2761{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002762 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 int id = (int) target->target_id;
2764 int nvram;
2765 VirtDevice *vdev;
2766 int ii;
2767 u8 width = MPT_NARROW;
2768 u8 factor = MPT_ASYNC;
2769 u8 offset = 0;
2770 u8 version, nfactor;
2771 u8 noQas = 1;
2772
2773 target->negoFlags = pspi_data->noQas;
2774
2775 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2776 * support. If available, default QAS to off and allow enabling.
2777 * If not available, default QAS to on, turn off for non-disks.
2778 */
2779
2780 /* Set flags based on Inquiry data
2781 */
2782 version = target->inq_data[2] & 0x07;
2783 if (version < 2) {
2784 width = 0;
2785 factor = MPT_ULTRA2;
2786 offset = pspi_data->maxSyncOffset;
2787 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2788 } else {
2789 if (target->inq_data[7] & 0x20) {
2790 width = 1;
2791 }
2792
2793 if (target->inq_data[7] & 0x10) {
2794 factor = pspi_data->minSyncFactor;
2795 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2796 /* bits 2 & 3 show Clocking support */
2797 if ((byte56 & 0x0C) == 0)
2798 factor = MPT_ULTRA2;
2799 else {
2800 if ((byte56 & 0x03) == 0)
2801 factor = MPT_ULTRA160;
2802 else {
2803 factor = MPT_ULTRA320;
2804 if (byte56 & 0x02)
2805 {
2806 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2807 noQas = 0;
2808 }
2809 if (target->inq_data[0] == TYPE_TAPE) {
2810 if (byte56 & 0x01)
2811 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2812 }
2813 }
2814 }
2815 } else {
2816 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2817 noQas = 0;
2818 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002819
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 offset = pspi_data->maxSyncOffset;
2821
2822 /* If RAID, never disable QAS
2823 * else if non RAID, do not disable
2824 * QAS if bit 1 is set
2825 * bit 1 QAS support, non-raid only
2826 * bit 0 IU support
2827 */
2828 if (target->raidVolume == 1) {
2829 noQas = 0;
2830 }
2831 } else {
2832 factor = MPT_ASYNC;
2833 offset = 0;
2834 }
2835 }
2836
2837 if ( (target->inq_data[7] & 0x02) == 0) {
2838 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2839 }
2840
2841 /* Update tflags based on NVRAM settings. (SCSI only)
2842 */
2843 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2844 nvram = pspi_data->nvram[id];
2845 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2846
2847 if (width)
2848 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2849
2850 if (offset > 0) {
2851 /* Ensure factor is set to the
2852 * maximum of: adapter, nvram, inquiry
2853 */
2854 if (nfactor) {
2855 if (nfactor < pspi_data->minSyncFactor )
2856 nfactor = pspi_data->minSyncFactor;
2857
2858 factor = max(factor, nfactor);
2859 if (factor == MPT_ASYNC)
2860 offset = 0;
2861 } else {
2862 offset = 0;
2863 factor = MPT_ASYNC;
2864 }
2865 } else {
2866 factor = MPT_ASYNC;
2867 }
2868 }
2869
2870 /* Make sure data is consistent
2871 */
2872 if ((!width) && (factor < MPT_ULTRA2)) {
2873 factor = MPT_ULTRA2;
2874 }
2875
2876 /* Save the data to the target structure.
2877 */
2878 target->minSyncFactor = factor;
2879 target->maxOffset = offset;
2880 target->maxWidth = width;
2881
2882 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2883
2884 /* Disable unused features.
2885 */
2886 if (!width)
2887 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2888
2889 if (!offset)
2890 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2891
2892 if ( factor > MPT_ULTRA320 )
2893 noQas = 0;
2894
2895 /* GEM, processor WORKAROUND
2896 */
2897 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2898 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2899 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2900 } else {
2901 if (noQas && (pspi_data->noQas == 0)) {
2902 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2903 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2904
2905 /* Disable QAS in a mixed configuration case
2906 */
2907
2908 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2909 for (ii = 0; ii < id; ii++) {
2910 if ( (vdev = hd->Targets[ii]) ) {
2911 vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2912 mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 }
2915 }
2916 }
2917
2918 /* Write SDP1 on this I/O to this target */
2919 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2920 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2921 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2922 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2923 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2924 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2925 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2926 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2927 }
2928}
2929
2930/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931/*
2932 * If no Target, bus reset on 1st I/O. Set the flag to
2933 * prevent any future negotiations to this device.
2934 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002935static void
2936mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937{
2938
2939 if ((hd->Targets) && (hd->Targets[target_id] == NULL))
2940 hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
2941
2942 return;
2943}
2944
2945/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2946/*
2947 * SCSI Config Page functionality ...
2948 */
2949/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2950/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
2951 * based on width, factor and offset parameters.
2952 * @width: bus width
2953 * @factor: sync factor
2954 * @offset: sync offset
2955 * @requestedPtr: pointer to requested values (updated)
2956 * @configurationPtr: pointer to configuration values (updated)
2957 * @flags: flags to block WDTR or SDTR negotiation
2958 *
2959 * Return: None.
2960 *
2961 * Remark: Called by writeSDP1 and _dv_params
2962 */
2963static void
2964mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
2965{
2966 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
2967 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
2968
2969 *configurationPtr = 0;
2970 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
2971 *requestedPtr |= (offset << 16) | (factor << 8);
2972
2973 if (width && offset && !nowide && !nosync) {
2974 if (factor < MPT_ULTRA160) {
2975 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
2976 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
2977 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
2978 if (flags & MPT_TAPE_NEGO_IDP)
2979 *requestedPtr |= 0x08000000;
2980 } else if (factor < MPT_ULTRA2) {
2981 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
2982 }
2983 }
2984
2985 if (nowide)
2986 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
2987
2988 if (nosync)
2989 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
2990
2991 return;
2992}
2993
2994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2995/* mptscsih_writeSDP1 - write SCSI Device Page 1
2996 * @hd: Pointer to a SCSI Host Strucutre
2997 * @portnum: IOC port number
2998 * @target_id: writeSDP1 for single ID
2999 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3000 *
3001 * Return: -EFAULT if read of config page header fails
3002 * or 0 if success.
3003 *
3004 * Remark: If a target has been found, the settings from the
3005 * target structure are used, else the device is set
3006 * to async/narrow.
3007 *
3008 * Remark: Called during init and after a FW reload.
3009 * Remark: We do not wait for a return, write pages sequentially.
3010 */
3011static int
3012mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3013{
3014 MPT_ADAPTER *ioc = hd->ioc;
3015 Config_t *pReq;
3016 SCSIDevicePage1_t *pData;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003017 VirtDevice *pTarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 MPT_FRAME_HDR *mf;
3019 dma_addr_t dataDma;
3020 u16 req_idx;
3021 u32 frameOffset;
3022 u32 requested, configuration, flagsLength;
3023 int ii, nvram;
3024 int id = 0, maxid = 0;
3025 u8 width;
3026 u8 factor;
3027 u8 offset;
3028 u8 bus = 0;
3029 u8 negoFlags;
3030 u8 maxwidth, maxoffset, maxfactor;
3031
3032 if (ioc->spi_data.sdp1length == 0)
3033 return 0;
3034
3035 if (flags & MPT_SCSICFG_ALL_IDS) {
3036 id = 0;
3037 maxid = ioc->sh->max_id - 1;
3038 } else if (ioc->sh) {
3039 id = target_id;
3040 maxid = min_t(int, id, ioc->sh->max_id - 1);
3041 }
3042
3043 for (; id <= maxid; id++) {
3044
3045 if (id == ioc->pfacts[portnum].PortSCSIID)
3046 continue;
3047
3048 /* Use NVRAM to get adapter and target maximums
3049 * Data over-riden by target structure information, if present
3050 */
3051 maxwidth = ioc->spi_data.maxBusWidth;
3052 maxoffset = ioc->spi_data.maxSyncOffset;
3053 maxfactor = ioc->spi_data.minSyncFactor;
3054 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3055 nvram = ioc->spi_data.nvram[id];
3056
3057 if (maxwidth)
3058 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3059
3060 if (maxoffset > 0) {
3061 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3062 if (maxfactor == 0) {
3063 /* Key for async */
3064 maxfactor = MPT_ASYNC;
3065 maxoffset = 0;
3066 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3067 maxfactor = ioc->spi_data.minSyncFactor;
3068 }
3069 } else
3070 maxfactor = MPT_ASYNC;
3071 }
3072
3073 /* Set the negotiation flags.
3074 */
3075 negoFlags = ioc->spi_data.noQas;
3076 if (!maxwidth)
3077 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3078
3079 if (!maxoffset)
3080 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3081
3082 if (flags & MPT_SCSICFG_USE_NVRAM) {
3083 width = maxwidth;
3084 factor = maxfactor;
3085 offset = maxoffset;
3086 } else {
3087 width = 0;
3088 factor = MPT_ASYNC;
3089 offset = 0;
3090 //negoFlags = 0;
3091 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3092 }
3093
3094 /* If id is not a raid volume, get the updated
3095 * transmission settings from the target structure.
3096 */
3097 if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3098 width = pTarget->maxWidth;
3099 factor = pTarget->minSyncFactor;
3100 offset = pTarget->maxOffset;
3101 negoFlags = pTarget->negoFlags;
3102 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003103
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3105 /* Force to async and narrow if DV has not been executed
3106 * for this ID
3107 */
3108 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3109 width = 0;
3110 factor = MPT_ASYNC;
3111 offset = 0;
3112 }
3113#endif
3114
3115 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003116 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
3118 mptscsih_setDevicePage1Flags(width, factor, offset,
3119 &requested, &configuration, negoFlags);
3120 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3121 target_id, width, factor, offset, negoFlags, requested, configuration));
3122
3123 /* Get a MF for this command.
3124 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003125 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003126 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3127 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 return -EAGAIN;
3129 }
3130
3131 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3132 hd->ioc->name, mf, id, requested, configuration));
3133
3134
3135 /* Set the request and the data pointers.
3136 * Request takes: 36 bytes (32 bit SGE)
3137 * SCSI Device Page 1 requires 16 bytes
3138 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3139 * and MF size >= 64 bytes.
3140 * Place data at end of MF.
3141 */
3142 pReq = (Config_t *)mf;
3143
3144 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3145 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3146
3147 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3148 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3149
3150 /* Complete the request frame (same for all requests).
3151 */
3152 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3153 pReq->Reserved = 0;
3154 pReq->ChainOffset = 0;
3155 pReq->Function = MPI_FUNCTION_CONFIG;
3156 pReq->ExtPageLength = 0;
3157 pReq->ExtPageType = 0;
3158 pReq->MsgFlags = 0;
3159 for (ii=0; ii < 8; ii++) {
3160 pReq->Reserved2[ii] = 0;
3161 }
3162 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3163 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3164 pReq->Header.PageNumber = 1;
3165 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3166 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3167
3168 /* Add a SGE to the config request.
3169 */
3170 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3171
3172 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3173
3174 /* Set up the common data portion
3175 */
3176 pData->Header.PageVersion = pReq->Header.PageVersion;
3177 pData->Header.PageLength = pReq->Header.PageLength;
3178 pData->Header.PageNumber = pReq->Header.PageNumber;
3179 pData->Header.PageType = pReq->Header.PageType;
3180 pData->RequestedParameters = cpu_to_le32(requested);
3181 pData->Reserved = 0;
3182 pData->Configuration = cpu_to_le32(configuration);
3183
3184 dprintk((MYIOC_s_INFO_FMT
3185 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3186 ioc->name, id, (id | (bus<<8)),
3187 requested, configuration));
3188
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003189 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 }
3191
3192 return 0;
3193}
3194
3195/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3196/* mptscsih_writeIOCPage4 - write IOC Page 4
3197 * @hd: Pointer to a SCSI Host Structure
3198 * @target_id: write IOC Page4 for this ID & Bus
3199 *
3200 * Return: -EAGAIN if unable to obtain a Message Frame
3201 * or 0 if success.
3202 *
3203 * Remark: We do not wait for a return, write pages sequentially.
3204 */
3205static int
3206mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3207{
3208 MPT_ADAPTER *ioc = hd->ioc;
3209 Config_t *pReq;
3210 IOCPage4_t *IOCPage4Ptr;
3211 MPT_FRAME_HDR *mf;
3212 dma_addr_t dataDma;
3213 u16 req_idx;
3214 u32 frameOffset;
3215 u32 flagsLength;
3216 int ii;
3217
3218 /* Get a MF for this command.
3219 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003220 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003221 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 ioc->name));
3223 return -EAGAIN;
3224 }
3225
3226 /* Set the request and the data pointers.
3227 * Place data at end of MF.
3228 */
3229 pReq = (Config_t *)mf;
3230
3231 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3232 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3233
3234 /* Complete the request frame (same for all requests).
3235 */
3236 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3237 pReq->Reserved = 0;
3238 pReq->ChainOffset = 0;
3239 pReq->Function = MPI_FUNCTION_CONFIG;
3240 pReq->ExtPageLength = 0;
3241 pReq->ExtPageType = 0;
3242 pReq->MsgFlags = 0;
3243 for (ii=0; ii < 8; ii++) {
3244 pReq->Reserved2[ii] = 0;
3245 }
3246
3247 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3248 dataDma = ioc->spi_data.IocPg4_dma;
3249 ii = IOCPage4Ptr->ActiveSEP++;
3250 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3251 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3252 pReq->Header = IOCPage4Ptr->Header;
3253 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3254
3255 /* Add a SGE to the config request.
3256 */
3257 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3258 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3259
3260 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3261
3262 dinitprintk((MYIOC_s_INFO_FMT
3263 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3264 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3265
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003266 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
3268 return 0;
3269}
3270
3271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3272/*
3273 * Bus Scan and Domain Validation functionality ...
3274 */
3275
3276/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3277/*
3278 * mptscsih_scandv_complete - Scan and DV callback routine registered
3279 * to Fustion MPT (base) driver.
3280 *
3281 * @ioc: Pointer to MPT_ADAPTER structure
3282 * @mf: Pointer to original MPT request frame
3283 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3284 *
3285 * This routine is called from mpt.c::mpt_interrupt() at the completion
3286 * of any SCSI IO request.
3287 * This routine is registered with the Fusion MPT (base) driver at driver
3288 * load/init time via the mpt_register() API call.
3289 *
3290 * Returns 1 indicating alloc'd request frame ptr should be freed.
3291 *
3292 * Remark: Sets a completion code and (possibly) saves sense data
3293 * in the IOC member localReply structure.
3294 * Used ONLY for DV and other internal commands.
3295 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003296int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3298{
3299 MPT_SCSI_HOST *hd;
3300 SCSIIORequest_t *pReq;
3301 int completionCode;
3302 u16 req_idx;
3303
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003304 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3305
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 if ((mf == NULL) ||
3307 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3308 printk(MYIOC_s_ERR_FMT
3309 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3310 ioc->name, mf?"BAD":"NULL", (void *) mf);
3311 goto wakeup;
3312 }
3313
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 del_timer(&hd->timer);
3315 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3316 hd->ScsiLookup[req_idx] = NULL;
3317 pReq = (SCSIIORequest_t *) mf;
3318
3319 if (mf != hd->cmdPtr) {
3320 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3321 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3322 }
3323 hd->cmdPtr = NULL;
3324
3325 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3326 hd->ioc->name, mf, mr, req_idx));
3327
3328 hd->pLocal = &hd->localReply;
3329 hd->pLocal->scsiStatus = 0;
3330
3331 /* If target struct exists, clear sense valid flag.
3332 */
3333 if (mr == NULL) {
3334 completionCode = MPT_SCANDV_GOOD;
3335 } else {
3336 SCSIIOReply_t *pReply;
3337 u16 status;
3338 u8 scsi_status;
3339
3340 pReply = (SCSIIOReply_t *) mr;
3341
3342 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3343 scsi_status = pReply->SCSIStatus;
3344
3345 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3346 status, pReply->SCSIState, scsi_status,
3347 le32_to_cpu(pReply->IOCLogInfo)));
3348
3349 switch(status) {
3350
3351 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3352 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3353 break;
3354
3355 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3356 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3357 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3358 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3359 completionCode = MPT_SCANDV_DID_RESET;
3360 break;
3361
3362 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3363 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3364 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3365 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3366 ConfigReply_t *pr = (ConfigReply_t *)mr;
3367 completionCode = MPT_SCANDV_GOOD;
3368 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3369 hd->pLocal->header.PageLength = pr->Header.PageLength;
3370 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3371 hd->pLocal->header.PageType = pr->Header.PageType;
3372
3373 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3374 /* If the RAID Volume request is successful,
3375 * return GOOD, else indicate that
3376 * some type of error occurred.
3377 */
3378 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003379 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 completionCode = MPT_SCANDV_GOOD;
3381 else
3382 completionCode = MPT_SCANDV_SOME_ERROR;
3383
3384 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3385 u8 *sense_data;
3386 int sz;
3387
3388 /* save sense data in global structure
3389 */
3390 completionCode = MPT_SCANDV_SENSE;
3391 hd->pLocal->scsiStatus = scsi_status;
3392 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3393 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3394
3395 sz = min_t(int, pReq->SenseBufferLength,
3396 SCSI_STD_SENSE_BYTES);
3397 memcpy(hd->pLocal->sense, sense_data, sz);
3398
3399 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3400 sense_data));
3401 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3402 if (pReq->CDB[0] == INQUIRY)
3403 completionCode = MPT_SCANDV_ISSUE_SENSE;
3404 else
3405 completionCode = MPT_SCANDV_DID_RESET;
3406 }
3407 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3408 completionCode = MPT_SCANDV_DID_RESET;
3409 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3410 completionCode = MPT_SCANDV_DID_RESET;
3411 else {
3412 completionCode = MPT_SCANDV_GOOD;
3413 hd->pLocal->scsiStatus = scsi_status;
3414 }
3415 break;
3416
3417 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3418 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3419 completionCode = MPT_SCANDV_DID_RESET;
3420 else
3421 completionCode = MPT_SCANDV_SOME_ERROR;
3422 break;
3423
3424 default:
3425 completionCode = MPT_SCANDV_SOME_ERROR;
3426 break;
3427
3428 } /* switch(status) */
3429
3430 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3431 completionCode));
3432 } /* end of address reply case */
3433
3434 hd->pLocal->completion = completionCode;
3435
3436 /* MF and RF are freed in mpt_interrupt
3437 */
3438wakeup:
3439 /* Free Chain buffers (will never chain) in scan or dv */
3440 //mptscsih_freeChainBuffers(ioc, req_idx);
3441
3442 /*
3443 * Wake up the original calling thread
3444 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003445 hd->scandv_wait_done = 1;
3446 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447
3448 return 1;
3449}
3450
3451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3452/* mptscsih_timer_expired - Call back for timer process.
3453 * Used only for dv functionality.
3454 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3455 *
3456 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003457void
3458mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
3460 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3461
3462 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3463
3464 if (hd->cmdPtr) {
3465 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3466
3467 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3468 /* Desire to issue a task management request here.
3469 * TM requests MUST be single threaded.
3470 * If old eh code and no TM current, issue request.
3471 * If new eh code, do nothing. Wait for OS cmd timeout
3472 * for bus reset.
3473 */
3474 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3475 } else {
3476 /* Perform a FW reload */
3477 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3478 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3479 }
3480 }
3481 } else {
3482 /* This should NEVER happen */
3483 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3484 }
3485
3486 /* No more processing.
3487 * TM call will generate an interrupt for SCSI TM Management.
3488 * The FW will reply to all outstanding commands, callback will finish cleanup.
3489 * Hard reset clean-up will free all resources.
3490 */
3491 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3492
3493 return;
3494}
3495
3496#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3497/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3498/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3499 * @hd: Pointer to scsi host structure
3500 * @action: What do be done.
3501 * @id: Logical target id.
3502 * @bus: Target locations bus.
3503 *
3504 * Returns: < 0 on a fatal error
3505 * 0 on success
3506 *
3507 * Remark: Wait to return until reply processed by the ISR.
3508 */
3509static int
3510mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3511{
3512 MpiRaidActionRequest_t *pReq;
3513 MPT_FRAME_HDR *mf;
3514 int in_isr;
3515
3516 in_isr = in_interrupt();
3517 if (in_isr) {
3518 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3519 hd->ioc->name));
3520 return -EPERM;
3521 }
3522
3523 /* Get and Populate a free Frame
3524 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003525 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3527 hd->ioc->name));
3528 return -EAGAIN;
3529 }
3530 pReq = (MpiRaidActionRequest_t *)mf;
3531 pReq->Action = action;
3532 pReq->Reserved1 = 0;
3533 pReq->ChainOffset = 0;
3534 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3535 pReq->VolumeID = io->id;
3536 pReq->VolumeBus = io->bus;
3537 pReq->PhysDiskNum = io->physDiskNum;
3538 pReq->MsgFlags = 0;
3539 pReq->Reserved2 = 0;
3540 pReq->ActionDataWord = 0; /* Reserved for this action */
3541 //pReq->ActionDataSGE = 0;
3542
3543 mpt_add_sge((char *)&pReq->ActionDataSGE,
3544 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3545
3546 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3547 hd->ioc->name, action, io->id));
3548
3549 hd->pLocal = NULL;
3550 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003551 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
3553 /* Save cmd pointer, for resource free if timeout or
3554 * FW reload occurs
3555 */
3556 hd->cmdPtr = mf;
3557
3558 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003559 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3560 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
3562 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3563 return -1;
3564
3565 return 0;
3566}
3567#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3568
3569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3570/**
3571 * mptscsih_do_cmd - Do internal command.
3572 * @hd: MPT_SCSI_HOST pointer
3573 * @io: INTERNAL_CMD pointer.
3574 *
3575 * Issue the specified internally generated command and do command
3576 * specific cleanup. For bus scan / DV only.
3577 * NOTES: If command is Inquiry and status is good,
3578 * initialize a target structure, save the data
3579 *
3580 * Remark: Single threaded access only.
3581 *
3582 * Return:
3583 * < 0 if an illegal command or no resources
3584 *
3585 * 0 if good
3586 *
3587 * > 0 if command complete but some type of completion error.
3588 */
3589static int
3590mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3591{
3592 MPT_FRAME_HDR *mf;
3593 SCSIIORequest_t *pScsiReq;
3594 SCSIIORequest_t ReqCopy;
3595 int my_idx, ii, dir;
3596 int rc, cmdTimeout;
3597 int in_isr;
3598 char cmdLen;
3599 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3600 char cmd = io->cmd;
3601
3602 in_isr = in_interrupt();
3603 if (in_isr) {
3604 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3605 hd->ioc->name));
3606 return -EPERM;
3607 }
3608
3609
3610 /* Set command specific information
3611 */
3612 switch (cmd) {
3613 case INQUIRY:
3614 cmdLen = 6;
3615 dir = MPI_SCSIIO_CONTROL_READ;
3616 CDB[0] = cmd;
3617 CDB[4] = io->size;
3618 cmdTimeout = 10;
3619 break;
3620
3621 case TEST_UNIT_READY:
3622 cmdLen = 6;
3623 dir = MPI_SCSIIO_CONTROL_READ;
3624 cmdTimeout = 10;
3625 break;
3626
3627 case START_STOP:
3628 cmdLen = 6;
3629 dir = MPI_SCSIIO_CONTROL_READ;
3630 CDB[0] = cmd;
3631 CDB[4] = 1; /*Spin up the disk */
3632 cmdTimeout = 15;
3633 break;
3634
3635 case REQUEST_SENSE:
3636 cmdLen = 6;
3637 CDB[0] = cmd;
3638 CDB[4] = io->size;
3639 dir = MPI_SCSIIO_CONTROL_READ;
3640 cmdTimeout = 10;
3641 break;
3642
3643 case READ_BUFFER:
3644 cmdLen = 10;
3645 dir = MPI_SCSIIO_CONTROL_READ;
3646 CDB[0] = cmd;
3647 if (io->flags & MPT_ICFLAG_ECHO) {
3648 CDB[1] = 0x0A;
3649 } else {
3650 CDB[1] = 0x02;
3651 }
3652
3653 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3654 CDB[1] |= 0x01;
3655 }
3656 CDB[6] = (io->size >> 16) & 0xFF;
3657 CDB[7] = (io->size >> 8) & 0xFF;
3658 CDB[8] = io->size & 0xFF;
3659 cmdTimeout = 10;
3660 break;
3661
3662 case WRITE_BUFFER:
3663 cmdLen = 10;
3664 dir = MPI_SCSIIO_CONTROL_WRITE;
3665 CDB[0] = cmd;
3666 if (io->flags & MPT_ICFLAG_ECHO) {
3667 CDB[1] = 0x0A;
3668 } else {
3669 CDB[1] = 0x02;
3670 }
3671 CDB[6] = (io->size >> 16) & 0xFF;
3672 CDB[7] = (io->size >> 8) & 0xFF;
3673 CDB[8] = io->size & 0xFF;
3674 cmdTimeout = 10;
3675 break;
3676
3677 case RESERVE:
3678 cmdLen = 6;
3679 dir = MPI_SCSIIO_CONTROL_READ;
3680 CDB[0] = cmd;
3681 cmdTimeout = 10;
3682 break;
3683
3684 case RELEASE:
3685 cmdLen = 6;
3686 dir = MPI_SCSIIO_CONTROL_READ;
3687 CDB[0] = cmd;
3688 cmdTimeout = 10;
3689 break;
3690
3691 case SYNCHRONIZE_CACHE:
3692 cmdLen = 10;
3693 dir = MPI_SCSIIO_CONTROL_READ;
3694 CDB[0] = cmd;
3695// CDB[1] = 0x02; /* set immediate bit */
3696 cmdTimeout = 10;
3697 break;
3698
3699 default:
3700 /* Error Case */
3701 return -EFAULT;
3702 }
3703
3704 /* Get and Populate a free Frame
3705 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003706 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3708 hd->ioc->name));
3709 return -EBUSY;
3710 }
3711
3712 pScsiReq = (SCSIIORequest_t *) mf;
3713
3714 /* Get the request index */
3715 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3716 ADD_INDEX_LOG(my_idx); /* for debug */
3717
3718 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3719 pScsiReq->TargetID = io->physDiskNum;
3720 pScsiReq->Bus = 0;
3721 pScsiReq->ChainOffset = 0;
3722 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3723 } else {
3724 pScsiReq->TargetID = io->id;
3725 pScsiReq->Bus = io->bus;
3726 pScsiReq->ChainOffset = 0;
3727 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3728 }
3729
3730 pScsiReq->CDBLength = cmdLen;
3731 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3732
3733 pScsiReq->Reserved = 0;
3734
3735 pScsiReq->MsgFlags = mpt_msg_flags();
3736 /* MsgContext set in mpt_get_msg_fram call */
3737
3738 for (ii=0; ii < 8; ii++)
3739 pScsiReq->LUN[ii] = 0;
3740 pScsiReq->LUN[1] = io->lun;
3741
3742 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3743 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3744 else
3745 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3746
3747 if (cmd == REQUEST_SENSE) {
3748 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3749 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3750 hd->ioc->name, cmd));
3751 }
3752
3753 for (ii=0; ii < 16; ii++)
3754 pScsiReq->CDB[ii] = CDB[ii];
3755
3756 pScsiReq->DataLength = cpu_to_le32(io->size);
3757 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3758 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3759
3760 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3761 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3762
3763 if (dir == MPI_SCSIIO_CONTROL_READ) {
3764 mpt_add_sge((char *) &pScsiReq->SGL,
3765 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3766 io->data_dma);
3767 } else {
3768 mpt_add_sge((char *) &pScsiReq->SGL,
3769 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3770 io->data_dma);
3771 }
3772
3773 /* The ISR will free the request frame, but we need
3774 * the information to initialize the target. Duplicate.
3775 */
3776 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3777
3778 /* Issue this command after:
3779 * finish init
3780 * add timer
3781 * Wait until the reply has been received
3782 * ScsiScanDvCtx callback function will
3783 * set hd->pLocal;
3784 * set scandv_wait_done and call wake_up
3785 */
3786 hd->pLocal = NULL;
3787 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003788 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
3790 /* Save cmd pointer, for resource free if timeout or
3791 * FW reload occurs
3792 */
3793 hd->cmdPtr = mf;
3794
3795 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003796 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3797 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
3799 if (hd->pLocal) {
3800 rc = hd->pLocal->completion;
3801 hd->pLocal->skip = 0;
3802
3803 /* Always set fatal error codes in some cases.
3804 */
3805 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3806 rc = -ENXIO;
3807 else if (rc == MPT_SCANDV_SOME_ERROR)
3808 rc = -rc;
3809 } else {
3810 rc = -EFAULT;
3811 /* This should never happen. */
3812 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3813 hd->ioc->name));
3814 }
3815
3816 return rc;
3817}
3818
3819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3820/**
3821 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3822 * @hd: Pointer to MPT_SCSI_HOST structure
3823 * @portnum: IOC port number
3824 *
3825 * Uses the ISR, but with special processing.
3826 * MUST be single-threaded.
3827 *
3828 * Return: 0 on completion
3829 */
3830static int
3831mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
3832{
3833 MPT_ADAPTER *ioc= hd->ioc;
3834 VirtDevice *pTarget;
3835 SCSIDevicePage1_t *pcfg1Data = NULL;
3836 INTERNAL_CMD iocmd;
3837 CONFIGPARMS cfg;
3838 dma_addr_t cfg1_dma_addr = -1;
3839 ConfigPageHeader_t header1;
3840 int bus = 0;
3841 int id = 0;
3842 int lun;
3843 int indexed_lun, lun_index;
3844 int hostId = ioc->pfacts[portnum].PortSCSIID;
3845 int max_id;
3846 int requested, configuration, data;
3847 int doConfig = 0;
3848 u8 flags, factor;
3849
3850 max_id = ioc->sh->max_id - 1;
3851
3852 /* Following parameters will not change
3853 * in this routine.
3854 */
3855 iocmd.cmd = SYNCHRONIZE_CACHE;
3856 iocmd.flags = 0;
3857 iocmd.physDiskNum = -1;
3858 iocmd.data = NULL;
3859 iocmd.data_dma = -1;
3860 iocmd.size = 0;
3861 iocmd.rsvd = iocmd.rsvd2 = 0;
3862
3863 /* No SCSI hosts
3864 */
3865 if (hd->Targets == NULL)
3866 return 0;
3867
3868 /* Skip the host
3869 */
3870 if (id == hostId)
3871 id++;
3872
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003873 /* Write SDP1 for all SPI devices
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 * Alloc memory and set up config buffer
3875 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003876 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 if (ioc->spi_data.sdp1length > 0) {
3878 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3879 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3880
3881 if (pcfg1Data != NULL) {
3882 doConfig = 1;
3883 header1.PageVersion = ioc->spi_data.sdp1version;
3884 header1.PageLength = ioc->spi_data.sdp1length;
3885 header1.PageNumber = 1;
3886 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02003887 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 cfg.physAddr = cfg1_dma_addr;
3889 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3890 cfg.dir = 1;
3891 cfg.timeout = 0;
3892 }
3893 }
3894 }
3895
3896 /* loop through all devices on this port
3897 */
3898 while (bus < MPT_MAX_BUS) {
3899 iocmd.bus = bus;
3900 iocmd.id = id;
3901 pTarget = hd->Targets[(int)id];
3902
3903 if (doConfig) {
3904
3905 /* Set the negotiation flags */
3906 if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3907 flags = pTarget->negoFlags;
3908 } else {
3909 flags = hd->ioc->spi_data.noQas;
3910 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3911 data = hd->ioc->spi_data.nvram[id];
3912
3913 if (data & MPT_NVRAM_WIDE_DISABLE)
3914 flags |= MPT_TARGET_NO_NEGO_WIDE;
3915
3916 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
3917 if ((factor == 0) || (factor == MPT_ASYNC))
3918 flags |= MPT_TARGET_NO_NEGO_SYNC;
3919 }
3920 }
3921
3922 /* Force to async, narrow */
3923 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3924 &configuration, flags);
3925 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3926 "offset=0 negoFlags=%x request=%x config=%x\n",
3927 id, flags, requested, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02003928 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 pcfg1Data->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003930 pcfg1Data->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 cfg.pageAddr = (bus<<8) | id;
3932 mpt_config(hd->ioc, &cfg);
3933 }
3934
3935 /* If target Ptr NULL or if this target is NOT a disk, skip.
3936 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003937 if ((pTarget) && (pTarget->inq_data[0] == TYPE_DISK)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 for (lun=0; lun <= MPT_LAST_LUN; lun++) {
3939 /* If LUN present, issue the command
3940 */
3941 lun_index = (lun >> 5); /* 32 luns per lun_index */
3942 indexed_lun = (lun % 32);
3943 if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
3944 iocmd.lun = lun;
3945 (void) mptscsih_do_cmd(hd, &iocmd);
3946 }
3947 }
3948 }
3949
3950 /* get next relevant device */
3951 id++;
3952
3953 if (id == hostId)
3954 id++;
3955
3956 if (id > max_id) {
3957 id = 0;
3958 bus++;
3959 }
3960 }
3961
3962 if (pcfg1Data) {
3963 pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
3964 }
3965
3966 return 0;
3967}
3968
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07003969/* Search IOC page 3 to determine if this is hidden physical disk
3970 */
3971/* Search IOC page 3 to determine if this is hidden physical disk
3972 */
3973static int
3974mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
3975{
3976 int i;
3977
3978 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
3979 return 0;
3980
3981 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3982 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
3983 return 1;
3984 }
3985
3986 return 0;
3987}
3988
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3991/**
3992 * mptscsih_domainValidation - Top level handler for domain validation.
3993 * @hd: Pointer to MPT_SCSI_HOST structure.
3994 *
3995 * Uses the ISR, but with special processing.
3996 * Called from schedule, should not be in interrupt mode.
3997 * While thread alive, do dv for all devices needing dv
3998 *
3999 * Return: None.
4000 */
4001static void
4002mptscsih_domainValidation(void *arg)
4003{
4004 MPT_SCSI_HOST *hd;
4005 MPT_ADAPTER *ioc;
4006 unsigned long flags;
4007 int id, maxid, dvStatus, did;
4008 int ii, isPhysDisk;
4009
4010 spin_lock_irqsave(&dvtaskQ_lock, flags);
4011 dvtaskQ_active = 1;
4012 if (dvtaskQ_release) {
4013 dvtaskQ_active = 0;
4014 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4015 return;
4016 }
4017 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4018
4019 /* For this ioc, loop through all devices and do dv to each device.
4020 * When complete with this ioc, search through the ioc list, and
4021 * for each scsi ioc found, do dv for all devices. Exit when no
4022 * device needs dv.
4023 */
4024 did = 1;
4025 while (did) {
4026 did = 0;
4027 list_for_each_entry(ioc, &ioc_list, list) {
4028 spin_lock_irqsave(&dvtaskQ_lock, flags);
4029 if (dvtaskQ_release) {
4030 dvtaskQ_active = 0;
4031 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4032 return;
4033 }
4034 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4035
4036 msleep(250);
4037
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004038 /* DV only to SPI adapters */
4039 if (ioc->bus_type != SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 continue;
4041
4042 /* Make sure everything looks ok */
4043 if (ioc->sh == NULL)
4044 continue;
4045
4046 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4047 if (hd == NULL)
4048 continue;
4049
4050 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4051 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004052 if (ioc->raid_data.pIocPg3) {
4053 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4054 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055
4056 while (numPDisk) {
4057 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4058 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4059
4060 pPDisk++;
4061 numPDisk--;
4062 }
4063 }
4064 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4065 }
4066
4067 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4068
4069 for (id = 0; id < maxid; id++) {
4070 spin_lock_irqsave(&dvtaskQ_lock, flags);
4071 if (dvtaskQ_release) {
4072 dvtaskQ_active = 0;
4073 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4074 return;
4075 }
4076 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4077 dvStatus = hd->ioc->spi_data.dvStatus[id];
4078
4079 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4080 did++;
4081 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4082 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4083
4084 msleep(250);
4085
4086 /* If hidden phys disk, block IO's to all
4087 * raid volumes
4088 * else, process normally
4089 */
4090 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4091 if (isPhysDisk) {
4092 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004093 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4095 }
4096 }
4097 }
4098
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004099 if(mpt_alt_ioc_wait(hd->ioc)!=0) {
4100 ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
4101 hd->ioc->name));
4102 continue;
4103 }
4104
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 if (mptscsih_doDv(hd, 0, id) == 1) {
4106 /* Untagged device was busy, try again
4107 */
4108 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4109 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4110 } else {
4111 /* DV is complete. Clear flags.
4112 */
4113 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4114 }
4115
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004116 spin_lock(&hd->ioc->initializing_hba_lock);
4117 hd->ioc->initializing_hba_lock_flag=0;
4118 spin_unlock(&hd->ioc->initializing_hba_lock);
4119
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 if (isPhysDisk) {
4121 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004122 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4124 }
4125 }
4126 }
4127
4128 if (hd->ioc->spi_data.noQas)
4129 mptscsih_qas_check(hd, id);
4130 }
4131 }
4132 }
4133 }
4134
4135 spin_lock_irqsave(&dvtaskQ_lock, flags);
4136 dvtaskQ_active = 0;
4137 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4138
4139 return;
4140}
4141
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142/* Write SDP1 if no QAS has been enabled
4143 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004144static void
4145mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146{
4147 VirtDevice *pTarget;
4148 int ii;
4149
4150 if (hd->Targets == NULL)
4151 return;
4152
4153 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4154 if (ii == id)
4155 continue;
4156
4157 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4158 continue;
4159
4160 pTarget = hd->Targets[ii];
4161
4162 if ((pTarget != NULL) && (!pTarget->raidVolume)) {
4163 if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4164 pTarget->negoFlags |= hd->ioc->spi_data.noQas;
4165 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4166 mptscsih_writeSDP1(hd, 0, ii, 0);
4167 }
4168 } else {
4169 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4170 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4171 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4172 }
4173 }
4174 }
4175 return;
4176}
4177
4178
4179
4180#define MPT_GET_NVRAM_VALS 0x01
4181#define MPT_UPDATE_MAX 0x02
4182#define MPT_SET_MAX 0x04
4183#define MPT_SET_MIN 0x08
4184#define MPT_FALLBACK 0x10
4185#define MPT_SAVE 0x20
4186
4187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4188/**
4189 * mptscsih_doDv - Perform domain validation to a target.
4190 * @hd: Pointer to MPT_SCSI_HOST structure.
4191 * @portnum: IOC port number.
4192 * @target: Physical ID of this target
4193 *
4194 * Uses the ISR, but with special processing.
4195 * MUST be single-threaded.
4196 * Test will exit if target is at async & narrow.
4197 *
4198 * Return: None.
4199 */
4200static int
4201mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4202{
4203 MPT_ADAPTER *ioc = hd->ioc;
4204 VirtDevice *pTarget;
4205 SCSIDevicePage1_t *pcfg1Data;
4206 SCSIDevicePage0_t *pcfg0Data;
4207 u8 *pbuf1;
4208 u8 *pbuf2;
4209 u8 *pDvBuf;
4210 dma_addr_t dvbuf_dma = -1;
4211 dma_addr_t buf1_dma = -1;
4212 dma_addr_t buf2_dma = -1;
4213 dma_addr_t cfg1_dma_addr = -1;
4214 dma_addr_t cfg0_dma_addr = -1;
4215 ConfigPageHeader_t header1;
4216 ConfigPageHeader_t header0;
4217 DVPARAMETERS dv;
4218 INTERNAL_CMD iocmd;
4219 CONFIGPARMS cfg;
4220 int dv_alloc = 0;
4221 int rc, sz = 0;
4222 int bufsize = 0;
4223 int dataBufSize = 0;
4224 int echoBufSize = 0;
4225 int notDone;
4226 int patt;
4227 int repeat;
4228 int retcode = 0;
4229 int nfactor = MPT_ULTRA320;
4230 char firstPass = 1;
4231 char doFallback = 0;
4232 char readPage0;
4233 char bus, lun;
4234 char inq0 = 0;
4235
4236 if (ioc->spi_data.sdp1length == 0)
4237 return 0;
4238
4239 if (ioc->spi_data.sdp0length == 0)
4240 return 0;
4241
4242 /* If multiple buses are used, require that the initiator
4243 * id be the same on all buses.
4244 */
4245 if (id == ioc->pfacts[0].PortSCSIID)
4246 return 0;
4247
4248 lun = 0;
4249 bus = (u8) bus_number;
4250 ddvtprintk((MYIOC_s_NOTE_FMT
4251 "DV started: bus=%d, id=%d dv @ %p\n",
4252 ioc->name, bus, id, &dv));
4253
4254 /* Prep DV structure
4255 */
4256 memset (&dv, 0, sizeof(DVPARAMETERS));
4257 dv.id = id;
4258
4259 /* Populate tmax with the current maximum
4260 * transfer parameters for this target.
4261 * Exit if narrow and async.
4262 */
4263 dv.cmd = MPT_GET_NVRAM_VALS;
4264 mptscsih_dv_parms(hd, &dv, NULL);
4265
4266 /* Prep SCSI IO structure
4267 */
4268 iocmd.id = id;
4269 iocmd.bus = bus;
4270 iocmd.lun = lun;
4271 iocmd.flags = 0;
4272 iocmd.physDiskNum = -1;
4273 iocmd.rsvd = iocmd.rsvd2 = 0;
4274
4275 pTarget = hd->Targets[id];
4276
4277 /* Use tagged commands if possible.
4278 */
4279 if (pTarget) {
4280 if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
4281 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4282 else {
4283 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4284 return 0;
4285
4286 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4287 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4288 return 0;
4289 }
4290 }
4291
4292 /* Prep cfg structure
4293 */
4294 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004295 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
4297 /* Prep SDP0 header
4298 */
4299 header0.PageVersion = ioc->spi_data.sdp0version;
4300 header0.PageLength = ioc->spi_data.sdp0length;
4301 header0.PageNumber = 0;
4302 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4303
4304 /* Prep SDP1 header
4305 */
4306 header1.PageVersion = ioc->spi_data.sdp1version;
4307 header1.PageLength = ioc->spi_data.sdp1length;
4308 header1.PageNumber = 1;
4309 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4310
4311 if (header0.PageLength & 1)
4312 dv_alloc = (header0.PageLength * 4) + 4;
4313
4314 dv_alloc += (2048 + (header1.PageLength * 4));
4315
4316 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4317 if (pDvBuf == NULL)
4318 return 0;
4319
4320 sz = 0;
4321 pbuf1 = (u8 *)pDvBuf;
4322 buf1_dma = dvbuf_dma;
4323 sz +=1024;
4324
4325 pbuf2 = (u8 *) (pDvBuf + sz);
4326 buf2_dma = dvbuf_dma + sz;
4327 sz +=1024;
4328
4329 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4330 cfg0_dma_addr = dvbuf_dma + sz;
4331 sz += header0.PageLength * 4;
4332
4333 /* 8-byte alignment
4334 */
4335 if (header0.PageLength & 1)
4336 sz += 4;
4337
4338 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4339 cfg1_dma_addr = dvbuf_dma + sz;
4340
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004341 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 */
4343 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004344 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4346 /* Set the factor from nvram */
4347 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4348 if (nfactor < pspi_data->minSyncFactor )
4349 nfactor = pspi_data->minSyncFactor;
4350
4351 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4352 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4353
4354 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4355 ioc->name, bus, id, lun));
4356
4357 dv.cmd = MPT_SET_MAX;
4358 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004359 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
4361 /* Save the final negotiated settings to
4362 * SCSI device page 1.
4363 */
4364 cfg.physAddr = cfg1_dma_addr;
4365 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4366 cfg.dir = 1;
4367 mpt_config(hd->ioc, &cfg);
4368 goto target_done;
4369 }
4370 }
4371 }
4372
4373 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004374 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 /* Search IOC page 3 for matching id
4376 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004377 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4378 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
4380 while (numPDisk) {
4381 if (pPDisk->PhysDiskID == id) {
4382 /* match */
4383 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4384 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4385
4386 /* Quiesce the IM
4387 */
4388 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4389 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4390 goto target_done;
4391 }
4392 break;
4393 }
4394 pPDisk++;
4395 numPDisk--;
4396 }
4397 }
4398
4399 /* RAID Volume ID's may double for a physical device. If RAID but
4400 * not a physical ID as well, skip DV.
4401 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004402 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 goto target_done;
4404
4405
4406 /* Basic Test.
4407 * Async & Narrow - Inquiry
4408 * Async & Narrow - Inquiry
4409 * Maximum transfer rate - Inquiry
4410 * Compare buffers:
4411 * If compare, test complete.
4412 * If miscompare and first pass, repeat
4413 * If miscompare and not first pass, fall back and repeat
4414 */
4415 hd->pLocal = NULL;
4416 readPage0 = 0;
4417 sz = SCSI_MAX_INQUIRY_BYTES;
4418 rc = MPT_SCANDV_GOOD;
4419 while (1) {
4420 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4421 retcode = 0;
4422 dv.cmd = MPT_SET_MIN;
4423 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4424
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004425 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 cfg.physAddr = cfg1_dma_addr;
4427 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4428 cfg.dir = 1;
4429 if (mpt_config(hd->ioc, &cfg) != 0)
4430 goto target_done;
4431
4432 /* Wide - narrow - wide workaround case
4433 */
4434 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4435 /* Send an untagged command to reset disk Qs corrupted
4436 * when a parity error occurs on a Request Sense.
4437 */
4438 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4439 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4440 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4441
4442 iocmd.cmd = REQUEST_SENSE;
4443 iocmd.data_dma = buf1_dma;
4444 iocmd.data = pbuf1;
4445 iocmd.size = 0x12;
4446 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4447 goto target_done;
4448 else {
4449 if (hd->pLocal == NULL)
4450 goto target_done;
4451 rc = hd->pLocal->completion;
4452 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4453 dv.max.width = 0;
4454 doFallback = 0;
4455 } else
4456 goto target_done;
4457 }
4458 } else
4459 goto target_done;
4460 }
4461
4462 iocmd.cmd = INQUIRY;
4463 iocmd.data_dma = buf1_dma;
4464 iocmd.data = pbuf1;
4465 iocmd.size = sz;
4466 memset(pbuf1, 0x00, sz);
4467 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4468 goto target_done;
4469 else {
4470 if (hd->pLocal == NULL)
4471 goto target_done;
4472 rc = hd->pLocal->completion;
4473 if (rc == MPT_SCANDV_GOOD) {
4474 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4475 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4476 retcode = 1;
4477 else
4478 retcode = 0;
4479
4480 goto target_done;
4481 }
4482 } else if (rc == MPT_SCANDV_SENSE) {
4483 ;
4484 } else {
4485 /* If first command doesn't complete
4486 * with a good status or with a check condition,
4487 * exit.
4488 */
4489 goto target_done;
4490 }
4491 }
4492
4493 /* Reset the size for disks
4494 */
4495 inq0 = (*pbuf1) & 0x1F;
4496 if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
4497 sz = 0x40;
4498 iocmd.size = sz;
4499 }
4500
4501 /* Another GEM workaround. Check peripheral device type,
4502 * if PROCESSOR, quit DV.
4503 */
4504 if (inq0 == TYPE_PROCESSOR) {
4505 mptscsih_initTarget(hd,
4506 bus,
4507 id,
4508 lun,
4509 pbuf1,
4510 sz);
4511 goto target_done;
4512 }
4513
4514 if (inq0 > 0x08)
4515 goto target_done;
4516
4517 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4518 goto target_done;
4519
4520 if (sz == 0x40) {
4521 if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
4522 && (pTarget->minSyncFactor > 0x09)) {
4523 if ((pbuf1[56] & 0x04) == 0)
4524 ;
4525 else if ((pbuf1[56] & 0x01) == 1) {
4526 pTarget->minSyncFactor =
4527 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4528 } else {
4529 pTarget->minSyncFactor =
4530 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4531 }
4532
4533 dv.max.factor = pTarget->minSyncFactor;
4534
4535 if ((pbuf1[56] & 0x02) == 0) {
4536 pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
4537 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004538 ddvprintk((MYIOC_s_NOTE_FMT
4539 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 ioc->name, id, pbuf1[56]));
4541 }
4542 }
4543 }
4544
4545 if (doFallback)
4546 dv.cmd = MPT_FALLBACK;
4547 else
4548 dv.cmd = MPT_SET_MAX;
4549
4550 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4551 if (mpt_config(hd->ioc, &cfg) != 0)
4552 goto target_done;
4553
4554 if ((!dv.now.width) && (!dv.now.offset))
4555 goto target_done;
4556
4557 iocmd.cmd = INQUIRY;
4558 iocmd.data_dma = buf2_dma;
4559 iocmd.data = pbuf2;
4560 iocmd.size = sz;
4561 memset(pbuf2, 0x00, sz);
4562 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4563 goto target_done;
4564 else if (hd->pLocal == NULL)
4565 goto target_done;
4566 else {
4567 /* Save the return code.
4568 * If this is the first pass,
4569 * read SCSI Device Page 0
4570 * and update the target max parameters.
4571 */
4572 rc = hd->pLocal->completion;
4573 doFallback = 0;
4574 if (rc == MPT_SCANDV_GOOD) {
4575 if (!readPage0) {
4576 u32 sdp0_info;
4577 u32 sdp0_nego;
4578
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004579 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 cfg.physAddr = cfg0_dma_addr;
4581 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4582 cfg.dir = 0;
4583
4584 if (mpt_config(hd->ioc, &cfg) != 0)
4585 goto target_done;
4586
4587 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4588 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4589
4590 /* Quantum and Fujitsu workarounds.
4591 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4592 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4593 * Resetart with a request for U160.
4594 */
4595 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4596 doFallback = 1;
4597 } else {
4598 dv.cmd = MPT_UPDATE_MAX;
4599 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4600 /* Update the SCSI device page 1 area
4601 */
4602 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4603 readPage0 = 1;
4604 }
4605 }
4606
4607 /* Quantum workaround. Restart this test will the fallback
4608 * flag set.
4609 */
4610 if (doFallback == 0) {
4611 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4612 if (!firstPass)
4613 doFallback = 1;
4614 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004615 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4617 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4618 mptscsih_initTarget(hd,
4619 bus,
4620 id,
4621 lun,
4622 pbuf1,
4623 sz);
4624 break; /* test complete */
4625 }
4626 }
4627
4628
4629 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4630 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004631 else if ((rc == MPT_SCANDV_DID_RESET) ||
4632 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 (rc == MPT_SCANDV_FALLBACK))
4634 doFallback = 1; /* set fallback flag */
4635 else
4636 goto target_done;
4637
4638 firstPass = 0;
4639 }
4640 }
4641 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4642
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004643 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 goto target_done;
4645
4646 inq0 = (*pbuf1) & 0x1F;
4647
4648 /* Continue only for disks
4649 */
4650 if (inq0 != 0)
4651 goto target_done;
4652
4653 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4654 goto target_done;
4655
4656 /* Start the Enhanced Test.
4657 * 0) issue TUR to clear out check conditions
4658 * 1) read capacity of echo (regular) buffer
4659 * 2) reserve device
4660 * 3) do write-read-compare data pattern test
4661 * 4) release
4662 * 5) update nego parms to target struct
4663 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004664 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 cfg.physAddr = cfg1_dma_addr;
4666 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4667 cfg.dir = 1;
4668
4669 iocmd.cmd = TEST_UNIT_READY;
4670 iocmd.data_dma = -1;
4671 iocmd.data = NULL;
4672 iocmd.size = 0;
4673 notDone = 1;
4674 while (notDone) {
4675 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4676 goto target_done;
4677
4678 if (hd->pLocal == NULL)
4679 goto target_done;
4680
4681 rc = hd->pLocal->completion;
4682 if (rc == MPT_SCANDV_GOOD)
4683 notDone = 0;
4684 else if (rc == MPT_SCANDV_SENSE) {
4685 u8 skey = hd->pLocal->sense[2] & 0x0F;
4686 u8 asc = hd->pLocal->sense[12];
4687 u8 ascq = hd->pLocal->sense[13];
4688 ddvprintk((MYIOC_s_INFO_FMT
4689 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4690 ioc->name, skey, asc, ascq));
4691
4692 if (skey == UNIT_ATTENTION)
4693 notDone++; /* repeat */
4694 else if ((skey == NOT_READY) &&
4695 (asc == 0x04)&&(ascq == 0x01)) {
4696 /* wait then repeat */
4697 mdelay (2000);
4698 notDone++;
4699 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4700 /* no medium, try read test anyway */
4701 notDone = 0;
4702 } else {
4703 /* All other errors are fatal.
4704 */
4705 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4706 ioc->name));
4707 goto target_done;
4708 }
4709 } else
4710 goto target_done;
4711 }
4712
4713 iocmd.cmd = READ_BUFFER;
4714 iocmd.data_dma = buf1_dma;
4715 iocmd.data = pbuf1;
4716 iocmd.size = 4;
4717 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4718
4719 dataBufSize = 0;
4720 echoBufSize = 0;
4721 for (patt = 0; patt < 2; patt++) {
4722 if (patt == 0)
4723 iocmd.flags |= MPT_ICFLAG_ECHO;
4724 else
4725 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4726
4727 notDone = 1;
4728 while (notDone) {
4729 bufsize = 0;
4730
4731 /* If not ready after 8 trials,
4732 * give up on this device.
4733 */
4734 if (notDone > 8)
4735 goto target_done;
4736
4737 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4738 goto target_done;
4739 else if (hd->pLocal == NULL)
4740 goto target_done;
4741 else {
4742 rc = hd->pLocal->completion;
4743 ddvprintk(("ReadBuffer Comp Code %d", rc));
4744 ddvprintk((" buff: %0x %0x %0x %0x\n",
4745 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4746
4747 if (rc == MPT_SCANDV_GOOD) {
4748 notDone = 0;
4749 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4750 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004751 if (pbuf1[0] & 0x01)
4752 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 } else {
4754 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4755 }
4756 } else if (rc == MPT_SCANDV_SENSE) {
4757 u8 skey = hd->pLocal->sense[2] & 0x0F;
4758 u8 asc = hd->pLocal->sense[12];
4759 u8 ascq = hd->pLocal->sense[13];
4760 ddvprintk((MYIOC_s_INFO_FMT
4761 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4762 ioc->name, skey, asc, ascq));
4763 if (skey == ILLEGAL_REQUEST) {
4764 notDone = 0;
4765 } else if (skey == UNIT_ATTENTION) {
4766 notDone++; /* repeat */
4767 } else if ((skey == NOT_READY) &&
4768 (asc == 0x04)&&(ascq == 0x01)) {
4769 /* wait then repeat */
4770 mdelay (2000);
4771 notDone++;
4772 } else {
4773 /* All other errors are fatal.
4774 */
4775 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4776 ioc->name));
4777 goto target_done;
4778 }
4779 } else {
4780 /* All other errors are fatal
4781 */
4782 goto target_done;
4783 }
4784 }
4785 }
4786
4787 if (iocmd.flags & MPT_ICFLAG_ECHO)
4788 echoBufSize = bufsize;
4789 else
4790 dataBufSize = bufsize;
4791 }
4792 sz = 0;
4793 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4794
4795 /* Use echo buffers if possible,
4796 * Exit if both buffers are 0.
4797 */
4798 if (echoBufSize > 0) {
4799 iocmd.flags |= MPT_ICFLAG_ECHO;
4800 if (dataBufSize > 0)
4801 bufsize = min(echoBufSize, dataBufSize);
4802 else
4803 bufsize = echoBufSize;
4804 } else if (dataBufSize == 0)
4805 goto target_done;
4806
4807 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4808 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4809
4810 /* Data buffers for write-read-compare test max 1K.
4811 */
4812 sz = min(bufsize, 1024);
4813
4814 /* --- loop ----
4815 * On first pass, always issue a reserve.
4816 * On additional loops, only if a reset has occurred.
4817 * iocmd.flags indicates if echo or regular buffer
4818 */
4819 for (patt = 0; patt < 4; patt++) {
4820 ddvprintk(("Pattern %d\n", patt));
4821 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4822 iocmd.cmd = TEST_UNIT_READY;
4823 iocmd.data_dma = -1;
4824 iocmd.data = NULL;
4825 iocmd.size = 0;
4826 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4827 goto target_done;
4828
4829 iocmd.cmd = RELEASE;
4830 iocmd.data_dma = -1;
4831 iocmd.data = NULL;
4832 iocmd.size = 0;
4833 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4834 goto target_done;
4835 else if (hd->pLocal == NULL)
4836 goto target_done;
4837 else {
4838 rc = hd->pLocal->completion;
4839 ddvprintk(("Release rc %d\n", rc));
4840 if (rc == MPT_SCANDV_GOOD)
4841 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4842 else
4843 goto target_done;
4844 }
4845 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4846 }
4847 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4848
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004849 if (iocmd.flags & MPT_ICFLAG_EBOS)
4850 goto skip_Reserve;
4851
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 repeat = 5;
4853 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4854 iocmd.cmd = RESERVE;
4855 iocmd.data_dma = -1;
4856 iocmd.data = NULL;
4857 iocmd.size = 0;
4858 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4859 goto target_done;
4860 else if (hd->pLocal == NULL)
4861 goto target_done;
4862 else {
4863 rc = hd->pLocal->completion;
4864 if (rc == MPT_SCANDV_GOOD) {
4865 iocmd.flags |= MPT_ICFLAG_RESERVED;
4866 } else if (rc == MPT_SCANDV_SENSE) {
4867 /* Wait if coming ready
4868 */
4869 u8 skey = hd->pLocal->sense[2] & 0x0F;
4870 u8 asc = hd->pLocal->sense[12];
4871 u8 ascq = hd->pLocal->sense[13];
4872 ddvprintk((MYIOC_s_INFO_FMT
4873 "DV: Reserve Failed: ", ioc->name));
4874 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4875 skey, asc, ascq));
4876
4877 if ((skey == NOT_READY) && (asc == 0x04)&&
4878 (ascq == 0x01)) {
4879 /* wait then repeat */
4880 mdelay (2000);
4881 notDone++;
4882 } else {
4883 ddvprintk((MYIOC_s_INFO_FMT
4884 "DV: Reserved Failed.", ioc->name));
4885 goto target_done;
4886 }
4887 } else {
4888 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4889 ioc->name));
4890 goto target_done;
4891 }
4892 }
4893 }
4894
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004895skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4897 iocmd.cmd = WRITE_BUFFER;
4898 iocmd.data_dma = buf1_dma;
4899 iocmd.data = pbuf1;
4900 iocmd.size = sz;
4901 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4902 goto target_done;
4903 else if (hd->pLocal == NULL)
4904 goto target_done;
4905 else {
4906 rc = hd->pLocal->completion;
4907 if (rc == MPT_SCANDV_GOOD)
4908 ; /* Issue read buffer */
4909 else if (rc == MPT_SCANDV_DID_RESET) {
4910 /* If using echo buffers, reset to data buffers.
4911 * Else do Fallback and restart
4912 * this test (re-issue reserve
4913 * because of bus reset).
4914 */
4915 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4916 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4917 } else {
4918 dv.cmd = MPT_FALLBACK;
4919 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4920
4921 if (mpt_config(hd->ioc, &cfg) != 0)
4922 goto target_done;
4923
4924 if ((!dv.now.width) && (!dv.now.offset))
4925 goto target_done;
4926 }
4927
4928 iocmd.flags |= MPT_ICFLAG_DID_RESET;
4929 patt = -1;
4930 continue;
4931 } else if (rc == MPT_SCANDV_SENSE) {
4932 /* Restart data test if UA, else quit.
4933 */
4934 u8 skey = hd->pLocal->sense[2] & 0x0F;
4935 ddvprintk((MYIOC_s_INFO_FMT
4936 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
4937 hd->pLocal->sense[12], hd->pLocal->sense[13]));
4938 if (skey == UNIT_ATTENTION) {
4939 patt = -1;
4940 continue;
4941 } else if (skey == ILLEGAL_REQUEST) {
4942 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4943 if (dataBufSize >= bufsize) {
4944 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4945 patt = -1;
4946 continue;
4947 }
4948 }
4949 goto target_done;
4950 }
4951 else
4952 goto target_done;
4953 } else {
4954 /* fatal error */
4955 goto target_done;
4956 }
4957 }
4958
4959 iocmd.cmd = READ_BUFFER;
4960 iocmd.data_dma = buf2_dma;
4961 iocmd.data = pbuf2;
4962 iocmd.size = sz;
4963 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4964 goto target_done;
4965 else if (hd->pLocal == NULL)
4966 goto target_done;
4967 else {
4968 rc = hd->pLocal->completion;
4969 if (rc == MPT_SCANDV_GOOD) {
4970 /* If buffers compare,
4971 * go to next pattern,
4972 * else, do a fallback and restart
4973 * data transfer test.
4974 */
4975 if (memcmp (pbuf1, pbuf2, sz) == 0) {
4976 ; /* goto next pattern */
4977 } else {
4978 /* Miscompare with Echo buffer, go to data buffer,
4979 * if that buffer exists.
4980 * Miscompare with Data buffer, check first 4 bytes,
4981 * some devices return capacity. Exit in this case.
4982 */
4983 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4984 if (dataBufSize >= bufsize)
4985 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4986 else
4987 goto target_done;
4988 } else {
4989 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
4990 /* Argh. Device returning wrong data.
4991 * Quit DV for this device.
4992 */
4993 goto target_done;
4994 }
4995
4996 /* Had an actual miscompare. Slow down.*/
4997 dv.cmd = MPT_FALLBACK;
4998 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4999
5000 if (mpt_config(hd->ioc, &cfg) != 0)
5001 goto target_done;
5002
5003 if ((!dv.now.width) && (!dv.now.offset))
5004 goto target_done;
5005 }
5006
5007 patt = -1;
5008 continue;
5009 }
5010 } else if (rc == MPT_SCANDV_DID_RESET) {
5011 /* Do Fallback and restart
5012 * this test (re-issue reserve
5013 * because of bus reset).
5014 */
5015 dv.cmd = MPT_FALLBACK;
5016 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5017
5018 if (mpt_config(hd->ioc, &cfg) != 0)
5019 goto target_done;
5020
5021 if ((!dv.now.width) && (!dv.now.offset))
5022 goto target_done;
5023
5024 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5025 patt = -1;
5026 continue;
5027 } else if (rc == MPT_SCANDV_SENSE) {
5028 /* Restart data test if UA, else quit.
5029 */
5030 u8 skey = hd->pLocal->sense[2] & 0x0F;
5031 ddvprintk((MYIOC_s_INFO_FMT
5032 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5033 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5034 if (skey == UNIT_ATTENTION) {
5035 patt = -1;
5036 continue;
5037 }
5038 else
5039 goto target_done;
5040 } else {
5041 /* fatal error */
5042 goto target_done;
5043 }
5044 }
5045
5046 } /* --- end of patt loop ---- */
5047
5048target_done:
5049 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5050 iocmd.cmd = RELEASE;
5051 iocmd.data_dma = -1;
5052 iocmd.data = NULL;
5053 iocmd.size = 0;
5054 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5055 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5056 ioc->name, id);
5057 else if (hd->pLocal) {
5058 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5059 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5060 } else {
5061 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5062 ioc->name, id);
5063 }
5064 }
5065
5066
5067 /* Set if cfg1_dma_addr contents is valid
5068 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005069 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 /* If disk, not U320, disable QAS
5071 */
5072 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5073 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005074 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5076 }
5077
5078 dv.cmd = MPT_SAVE;
5079 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5080
5081 /* Double writes to SDP1 can cause problems,
5082 * skip save of the final negotiated settings to
5083 * SCSI device page 1.
5084 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005085 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 cfg.physAddr = cfg1_dma_addr;
5087 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5088 cfg.dir = 1;
5089 mpt_config(hd->ioc, &cfg);
5090 */
5091 }
5092
5093 /* If this is a RAID Passthrough, enable internal IOs
5094 */
5095 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5096 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5097 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5098 }
5099
5100 /* Done with the DV scan of the current target
5101 */
5102 if (pDvBuf)
5103 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5104
5105 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5106 ioc->name, id));
5107
5108 return retcode;
5109}
5110
5111/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5112/* mptscsih_dv_parms - perform a variety of operations on the
5113 * parameters used for negotiation.
5114 * @hd: Pointer to a SCSI host.
5115 * @dv: Pointer to a structure that contains the maximum and current
5116 * negotiated parameters.
5117 */
5118static void
5119mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5120{
5121 VirtDevice *pTarget;
5122 SCSIDevicePage0_t *pPage0;
5123 SCSIDevicePage1_t *pPage1;
5124 int val = 0, data, configuration;
5125 u8 width = 0;
5126 u8 offset = 0;
5127 u8 factor = 0;
5128 u8 negoFlags = 0;
5129 u8 cmd = dv->cmd;
5130 u8 id = dv->id;
5131
5132 switch (cmd) {
5133 case MPT_GET_NVRAM_VALS:
5134 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5135 hd->ioc->name));
5136 /* Get the NVRAM values and save in tmax
5137 * If not an LVD bus, the adapter minSyncFactor has been
5138 * already throttled back.
5139 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005140 negoFlags = hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
5142 width = pTarget->maxWidth;
5143 offset = pTarget->maxOffset;
5144 factor = pTarget->minSyncFactor;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005145 negoFlags |= pTarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 } else {
5147 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5148 data = hd->ioc->spi_data.nvram[id];
5149 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5150 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5151 factor = MPT_ASYNC;
5152 else {
5153 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5154 if ((factor == 0) || (factor == MPT_ASYNC)){
5155 factor = MPT_ASYNC;
5156 offset = 0;
5157 }
5158 }
5159 } else {
5160 width = MPT_NARROW;
5161 offset = 0;
5162 factor = MPT_ASYNC;
5163 }
5164
5165 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 if (!width)
5167 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5168
5169 if (!offset)
5170 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5171 }
5172
5173 /* limit by adapter capabilities */
5174 width = min(width, hd->ioc->spi_data.maxBusWidth);
5175 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5176 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5177
5178 /* Check Consistency */
5179 if (offset && (factor < MPT_ULTRA2) && !width)
5180 factor = MPT_ULTRA2;
5181
5182 dv->max.width = width;
5183 dv->max.offset = offset;
5184 dv->max.factor = factor;
5185 dv->max.flags = negoFlags;
5186 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5187 id, width, factor, offset, negoFlags));
5188 break;
5189
5190 case MPT_UPDATE_MAX:
5191 ddvprintk((MYIOC_s_NOTE_FMT
5192 "Updating with SDP0 Data: ", hd->ioc->name));
5193 /* Update tmax values with those from Device Page 0.*/
5194 pPage0 = (SCSIDevicePage0_t *) pPage;
5195 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005196 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5198 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5199 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5200 }
5201
5202 dv->now.width = dv->max.width;
5203 dv->now.offset = dv->max.offset;
5204 dv->now.factor = dv->max.factor;
5205 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5206 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5207 break;
5208
5209 case MPT_SET_MAX:
5210 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5211 hd->ioc->name));
5212 /* Set current to the max values. Update the config page.*/
5213 dv->now.width = dv->max.width;
5214 dv->now.offset = dv->max.offset;
5215 dv->now.factor = dv->max.factor;
5216 dv->now.flags = dv->max.flags;
5217
5218 pPage1 = (SCSIDevicePage1_t *)pPage;
5219 if (pPage1) {
5220 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5221 dv->now.offset, &val, &configuration, dv->now.flags);
5222 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5223 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005224 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005226 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 }
5228
Christoph Hellwig637fa992005-08-18 16:25:44 +02005229 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5231 break;
5232
5233 case MPT_SET_MIN:
5234 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5235 hd->ioc->name));
5236 /* Set page to asynchronous and narrow
5237 * Do not update now, breaks fallback routine. */
5238 width = MPT_NARROW;
5239 offset = 0;
5240 factor = MPT_ASYNC;
5241 negoFlags = dv->max.flags;
5242
5243 pPage1 = (SCSIDevicePage1_t *)pPage;
5244 if (pPage1) {
5245 mptscsih_setDevicePage1Flags (width, factor,
5246 offset, &val, &configuration, negoFlags);
5247 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5248 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005249 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005251 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 }
5253 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5254 id, width, factor, offset, val, configuration, negoFlags));
5255 break;
5256
5257 case MPT_FALLBACK:
5258 ddvprintk((MYIOC_s_NOTE_FMT
5259 "Fallback: Start: offset %d, factor %x, width %d \n",
5260 hd->ioc->name, dv->now.offset,
5261 dv->now.factor, dv->now.width));
5262 width = dv->now.width;
5263 offset = dv->now.offset;
5264 factor = dv->now.factor;
5265 if ((offset) && (dv->max.width)) {
5266 if (factor < MPT_ULTRA160)
5267 factor = MPT_ULTRA160;
5268 else if (factor < MPT_ULTRA2) {
5269 factor = MPT_ULTRA2;
5270 width = MPT_WIDE;
5271 } else if ((factor == MPT_ULTRA2) && width) {
5272 factor = MPT_ULTRA2;
5273 width = MPT_NARROW;
5274 } else if (factor < MPT_ULTRA) {
5275 factor = MPT_ULTRA;
5276 width = MPT_WIDE;
5277 } else if ((factor == MPT_ULTRA) && width) {
5278 width = MPT_NARROW;
5279 } else if (factor < MPT_FAST) {
5280 factor = MPT_FAST;
5281 width = MPT_WIDE;
5282 } else if ((factor == MPT_FAST) && width) {
5283 factor = MPT_FAST;
5284 width = MPT_NARROW;
5285 } else if (factor < MPT_SCSI) {
5286 factor = MPT_SCSI;
5287 width = MPT_WIDE;
5288 } else if ((factor == MPT_SCSI) && width) {
5289 factor = MPT_SCSI;
5290 width = MPT_NARROW;
5291 } else {
5292 factor = MPT_ASYNC;
5293 offset = 0;
5294 }
5295
5296 } else if (offset) {
5297 width = MPT_NARROW;
5298 if (factor < MPT_ULTRA)
5299 factor = MPT_ULTRA;
5300 else if (factor < MPT_FAST)
5301 factor = MPT_FAST;
5302 else if (factor < MPT_SCSI)
5303 factor = MPT_SCSI;
5304 else {
5305 factor = MPT_ASYNC;
5306 offset = 0;
5307 }
5308
5309 } else {
5310 width = MPT_NARROW;
5311 factor = MPT_ASYNC;
5312 }
5313 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5314 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5315
5316 dv->now.width = width;
5317 dv->now.offset = offset;
5318 dv->now.factor = factor;
5319 dv->now.flags = dv->max.flags;
5320
5321 pPage1 = (SCSIDevicePage1_t *)pPage;
5322 if (pPage1) {
5323 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5324 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005325 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 id, width, offset, factor, dv->now.flags, val, configuration));
5327
Christoph Hellwig637fa992005-08-18 16:25:44 +02005328 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005330 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 }
5332
5333 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5334 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5335 break;
5336
5337 case MPT_SAVE:
5338 ddvprintk((MYIOC_s_NOTE_FMT
5339 "Saving to Target structure: ", hd->ioc->name));
5340 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5341 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5342
5343 /* Save these values to target structures
5344 * or overwrite nvram (phys disks only).
5345 */
5346
5347 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
5348 pTarget->maxWidth = dv->now.width;
5349 pTarget->maxOffset = dv->now.offset;
5350 pTarget->minSyncFactor = dv->now.factor;
5351 pTarget->negoFlags = dv->now.flags;
5352 } else {
5353 /* Preserv all flags, use
5354 * read-modify-write algorithm
5355 */
5356 if (hd->ioc->spi_data.nvram) {
5357 data = hd->ioc->spi_data.nvram[id];
5358
5359 if (dv->now.width)
5360 data &= ~MPT_NVRAM_WIDE_DISABLE;
5361 else
5362 data |= MPT_NVRAM_WIDE_DISABLE;
5363
5364 if (!dv->now.offset)
5365 factor = MPT_ASYNC;
5366
5367 data &= ~MPT_NVRAM_SYNC_MASK;
5368 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5369
5370 hd->ioc->spi_data.nvram[id] = data;
5371 }
5372 }
5373 break;
5374 }
5375}
5376
5377/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5378/* mptscsih_fillbuf - fill a buffer with a special data pattern
5379 * cleanup. For bus scan only.
5380 *
5381 * @buffer: Pointer to data buffer to be filled.
5382 * @size: Number of bytes to fill
5383 * @index: Pattern index
5384 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5385 */
5386static void
5387mptscsih_fillbuf(char *buffer, int size, int index, int width)
5388{
5389 char *ptr = buffer;
5390 int ii;
5391 char byte;
5392 short val;
5393
5394 switch (index) {
5395 case 0:
5396
5397 if (width) {
5398 /* Pattern: 0000 FFFF 0000 FFFF
5399 */
5400 for (ii=0; ii < size; ii++, ptr++) {
5401 if (ii & 0x02)
5402 *ptr = 0xFF;
5403 else
5404 *ptr = 0x00;
5405 }
5406 } else {
5407 /* Pattern: 00 FF 00 FF
5408 */
5409 for (ii=0; ii < size; ii++, ptr++) {
5410 if (ii & 0x01)
5411 *ptr = 0xFF;
5412 else
5413 *ptr = 0x00;
5414 }
5415 }
5416 break;
5417
5418 case 1:
5419 if (width) {
5420 /* Pattern: 5555 AAAA 5555 AAAA 5555
5421 */
5422 for (ii=0; ii < size; ii++, ptr++) {
5423 if (ii & 0x02)
5424 *ptr = 0xAA;
5425 else
5426 *ptr = 0x55;
5427 }
5428 } else {
5429 /* Pattern: 55 AA 55 AA 55
5430 */
5431 for (ii=0; ii < size; ii++, ptr++) {
5432 if (ii & 0x01)
5433 *ptr = 0xAA;
5434 else
5435 *ptr = 0x55;
5436 }
5437 }
5438 break;
5439
5440 case 2:
5441 /* Pattern: 00 01 02 03 04 05
5442 * ... FE FF 00 01..
5443 */
5444 for (ii=0; ii < size; ii++, ptr++)
5445 *ptr = (char) ii;
5446 break;
5447
5448 case 3:
5449 if (width) {
5450 /* Wide Pattern: FFFE 0001 FFFD 0002
5451 * ... 4000 DFFF 8000 EFFF
5452 */
5453 byte = 0;
5454 for (ii=0; ii < size/2; ii++) {
5455 /* Create the base pattern
5456 */
5457 val = (1 << byte);
5458 /* every 64 (0x40) bytes flip the pattern
5459 * since we fill 2 bytes / iteration,
5460 * test for ii = 0x20
5461 */
5462 if (ii & 0x20)
5463 val = ~(val);
5464
5465 if (ii & 0x01) {
5466 *ptr = (char)( (val & 0xFF00) >> 8);
5467 ptr++;
5468 *ptr = (char)(val & 0xFF);
5469 byte++;
5470 byte &= 0x0F;
5471 } else {
5472 val = ~val;
5473 *ptr = (char)( (val & 0xFF00) >> 8);
5474 ptr++;
5475 *ptr = (char)(val & 0xFF);
5476 }
5477
5478 ptr++;
5479 }
5480 } else {
5481 /* Narrow Pattern: FE 01 FD 02 FB 04
5482 * .. 7F 80 01 FE 02 FD ... 80 7F
5483 */
5484 byte = 0;
5485 for (ii=0; ii < size; ii++, ptr++) {
5486 /* Base pattern - first 32 bytes
5487 */
5488 if (ii & 0x01) {
5489 *ptr = (1 << byte);
5490 byte++;
5491 byte &= 0x07;
5492 } else {
5493 *ptr = (char) (~(1 << byte));
5494 }
5495
5496 /* Flip the pattern every 32 bytes
5497 */
5498 if (ii & 0x20)
5499 *ptr = ~(*ptr);
5500 }
5501 }
5502 break;
5503 }
5504}
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005505
5506/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5507/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
5508 * Else set the NEED_DV flag after Read Capacity Issued (disks)
5509 * or Mode Sense (cdroms).
5510 *
5511 * Tapes, initTarget will set this flag on completion of Inquiry command.
5512 * Called only if DV_NOT_DONE flag is set
5513 */
5514static void
5515mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
5516{
5517 MPT_ADAPTER *ioc = hd->ioc;
5518 u8 cmd;
5519 SpiCfgData *pSpi;
5520
5521 ddvtprintk((MYIOC_s_NOTE_FMT
5522 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
5523 hd->ioc->name, pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0]));
5524
5525 if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
5526 return;
5527
5528 cmd = pReq->CDB[0];
5529
5530 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
5531 pSpi = &ioc->spi_data;
5532 if ((ioc->raid_data.isRaid & (1 << pReq->TargetID)) && ioc->raid_data.pIocPg3) {
5533 /* Set NEED_DV for all hidden disks
5534 */
5535 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5536 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5537
5538 while (numPDisk) {
5539 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
5540 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
5541 pPDisk++;
5542 numPDisk--;
5543 }
5544 }
5545 pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
5546 ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
5547 }
5548}
5549
5550/* mptscsih_raid_set_dv_flags()
5551 *
5552 * New or replaced disk. Set DV flag and schedule DV.
5553 */
5554static void
5555mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
5556{
5557 MPT_ADAPTER *ioc = hd->ioc;
5558 SpiCfgData *pSpi = &ioc->spi_data;
5559 Ioc3PhysDisk_t *pPDisk;
5560 int numPDisk;
5561
5562 if (hd->negoNvram != 0)
5563 return;
5564
5565 ddvtprintk(("DV requested for phys disk id %d\n", id));
5566 if (ioc->raid_data.pIocPg3) {
5567 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5568 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5569 while (numPDisk) {
5570 if (id == pPDisk->PhysDiskNum) {
5571 pSpi->dvStatus[pPDisk->PhysDiskID] =
5572 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
5573 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
5574 ddvtprintk(("NEED_DV set for phys disk id %d\n",
5575 pPDisk->PhysDiskID));
5576 break;
5577 }
5578 pPDisk++;
5579 numPDisk--;
5580 }
5581
5582 if (numPDisk == 0) {
5583 /* The physical disk that needs DV was not found
5584 * in the stored IOC Page 3. The driver must reload
5585 * this page. DV routine will set the NEED_DV flag for
5586 * all phys disks that have DV_NOT_DONE set.
5587 */
5588 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
5589 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
5590 }
5591 }
5592}
5593
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5595
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005596EXPORT_SYMBOL(mptscsih_remove);
5597EXPORT_SYMBOL(mptscsih_shutdown);
5598#ifdef CONFIG_PM
5599EXPORT_SYMBOL(mptscsih_suspend);
5600EXPORT_SYMBOL(mptscsih_resume);
5601#endif
5602EXPORT_SYMBOL(mptscsih_proc_info);
5603EXPORT_SYMBOL(mptscsih_info);
5604EXPORT_SYMBOL(mptscsih_qcmd);
5605EXPORT_SYMBOL(mptscsih_slave_alloc);
5606EXPORT_SYMBOL(mptscsih_slave_destroy);
5607EXPORT_SYMBOL(mptscsih_slave_configure);
5608EXPORT_SYMBOL(mptscsih_abort);
5609EXPORT_SYMBOL(mptscsih_dev_reset);
5610EXPORT_SYMBOL(mptscsih_bus_reset);
5611EXPORT_SYMBOL(mptscsih_host_reset);
5612EXPORT_SYMBOL(mptscsih_bios_param);
5613EXPORT_SYMBOL(mptscsih_io_done);
5614EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5615EXPORT_SYMBOL(mptscsih_scandv_complete);
5616EXPORT_SYMBOL(mptscsih_event_process);
5617EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005618EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005619EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/