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