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