blob: d6ccd6aa43487efc0ca7d5f5af0c0b266deeac70 [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/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002031static void
2032mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2033{
2034 char *desc;
2035
2036 switch (response_code) {
2037 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2038 desc = "The task completed.";
2039 break;
2040 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2041 desc = "The IOC received an invalid frame status.";
2042 break;
2043 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2044 desc = "The task type is not supported.";
2045 break;
2046 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2047 desc = "The requested task failed.";
2048 break;
2049 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2050 desc = "The task completed successfully.";
2051 break;
2052 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2053 desc = "The LUN request is invalid.";
2054 break;
2055 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2056 desc = "The task is in the IOC queue and has not been sent to target.";
2057 break;
2058 default:
2059 desc = "unknown";
2060 break;
2061 }
2062 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2063 ioc->name, response_code, desc);
2064}
2065
2066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067/**
2068 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2069 * @ioc: Pointer to MPT_ADAPTER structure
2070 * @mf: Pointer to SCSI task mgmt request frame
2071 * @mr: Pointer to SCSI task mgmt reply frame
2072 *
2073 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2074 * of any SCSI task management request.
2075 * This routine is registered with the MPT (base) driver at driver
2076 * load/init time via the mpt_register() API call.
2077 *
2078 * Returns 1 indicating alloc'd request frame ptr should be freed.
2079 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002080int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2082{
2083 SCSITaskMgmtReply_t *pScsiTmReply;
2084 SCSITaskMgmt_t *pScsiTmReq;
2085 MPT_SCSI_HOST *hd;
2086 unsigned long flags;
2087 u16 iocstatus;
2088 u8 tmType;
2089
2090 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2091 ioc->name, mf, mr));
2092 if (ioc->sh) {
2093 /* Depending on the thread, a timer is activated for
2094 * the TM request. Delete this timer on completion of TM.
2095 * Decrement count of outstanding TM requests.
2096 */
2097 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2098 } else {
2099 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2100 ioc->name));
2101 return 1;
2102 }
2103
2104 if (mr == NULL) {
2105 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2106 ioc->name, mf));
2107 return 1;
2108 } else {
2109 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2110 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2111
2112 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2113 tmType = pScsiTmReq->TaskType;
2114
Moore, Eric9f63bb72006-01-16 18:53:26 -07002115 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2116 pScsiTmReply->ResponseCode)
2117 mptscsih_taskmgmt_response_code(ioc,
2118 pScsiTmReply->ResponseCode);
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2121 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2122 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2123
2124 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2125 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2126 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2127 /* Error? (anything non-zero?) */
2128 if (iocstatus) {
2129
2130 /* clear flags and continue.
2131 */
2132 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2133 hd->abortSCpnt = NULL;
2134
2135 /* If an internal command is present
2136 * or the TM failed - reload the FW.
2137 * FC FW may respond FAILED to an ABORT
2138 */
2139 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2140 if ((hd->cmdPtr) ||
2141 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2142 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2143 printk((KERN_WARNING
2144 " Firmware Reload FAILED!!\n"));
2145 }
2146 }
2147 }
2148 } else {
2149 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2150
2151 hd->abortSCpnt = NULL;
2152
2153 }
2154 }
2155
2156 spin_lock_irqsave(&ioc->FreeQlock, flags);
2157 hd->tmPending = 0;
2158 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2159 hd->tmState = TM_STATE_NONE;
2160
2161 return 1;
2162}
2163
2164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2165/*
2166 * This is anyones guess quite frankly.
2167 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002168int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2170 sector_t capacity, int geom[])
2171{
2172 int heads;
2173 int sectors;
2174 sector_t cylinders;
2175 ulong dummy;
2176
2177 heads = 64;
2178 sectors = 32;
2179
2180 dummy = heads * sectors;
2181 cylinders = capacity;
2182 sector_div(cylinders,dummy);
2183
2184 /*
2185 * Handle extended translation size for logical drives
2186 * > 1Gb
2187 */
2188 if ((ulong)capacity >= 0x200000) {
2189 heads = 255;
2190 sectors = 63;
2191 dummy = heads * sectors;
2192 cylinders = capacity;
2193 sector_div(cylinders,dummy);
2194 }
2195
2196 /* return result */
2197 geom[0] = heads;
2198 geom[1] = sectors;
2199 geom[2] = cylinders;
2200
2201 dprintk((KERN_NOTICE
2202 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2203 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2204
2205 return 0;
2206}
2207
2208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2209/*
2210 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002211 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002214int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002215mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002217 VirtTarget *vtarget;
2218
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002219 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002220 if (!vtarget)
2221 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002222 starget->hostdata = vtarget;
2223 return 0;
2224}
2225
2226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2227/*
2228 * OS entry point to allow host driver to alloc memory
2229 * for each scsi device. Called once per device the bus scan.
2230 * Return non-zero if allocation fails.
2231 */
2232int
2233mptscsih_slave_alloc(struct scsi_device *sdev)
2234{
2235 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002237 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002239 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002241 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (!vdev) {
2243 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2244 hd->ioc->name, sizeof(VirtDevice));
2245 return -ENOMEM;
2246 }
2247
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 vdev->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002249 vdev->target_id = sdev->id;
2250 vdev->bus_id = sdev->channel;
2251 vdev->lun = sdev->lun;
2252 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002254 starget = scsi_target(sdev);
2255 vtarget = starget->hostdata;
2256 vdev->vtarget = vtarget;
2257
2258 if (vtarget->num_luns == 0) {
2259 hd->Targets[sdev->id] = vtarget;
2260 vtarget->ioc_id = hd->ioc->id;
2261 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2262 vtarget->target_id = sdev->id;
2263 vtarget->bus_id = sdev->channel;
2264 if (hd->ioc->bus_type == SPI) {
2265 if (hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2266 vtarget->raidVolume = 1;
2267 ddvtprintk((KERN_INFO
2268 "RAID Volume @ id %d\n", sdev->id));
2269 }
2270 } else {
2271 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2272 }
2273 }
2274 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 return 0;
2276}
2277
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278/*
2279 * OS entry point to allow for host driver to free allocated memory
2280 * Called if no device present or device being unloaded
2281 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002282void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002283mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002285 if (starget->hostdata)
2286 kfree(starget->hostdata);
2287 starget->hostdata = NULL;
2288}
2289
2290/*
2291 * OS entry point to allow for host driver to free allocated memory
2292 * Called if no device present or device being unloaded
2293 */
2294void
2295mptscsih_slave_destroy(struct scsi_device *sdev)
2296{
2297 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002299 VirtTarget *vtarget;
2300 VirtDevice *vdevice;
2301 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002303 starget = scsi_target(sdev);
2304 vtarget = starget->hostdata;
2305 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002307 mptscsih_search_running_cmds(hd, vdevice);
2308 vtarget->luns[0] &= ~(1 << vdevice->lun);
2309 vtarget->num_luns--;
2310 if (vtarget->num_luns == 0) {
2311 mptscsih_negotiate_to_asyn_narrow(hd, vtarget);
2312 if (hd->ioc->bus_type == SPI) {
2313 if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
2314 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2315 } else {
2316 hd->ioc->spi_data.dvStatus[vtarget->target_id] =
2317 MPT_SCSICFG_NEGOTIATE;
2318 if (!hd->negoNvram) {
2319 hd->ioc->spi_data.dvStatus[vtarget->target_id] |=
2320 MPT_SCSICFG_DV_NOT_DONE;
2321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 }
2323 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002326 mptscsih_synchronize_cache(hd, vdevice);
2327 kfree(vdevice);
2328 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329}
2330
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2332/*
2333 * mptscsih_change_queue_depth - This function will set a devices queue depth
2334 * @sdev: per scsi_device pointer
2335 * @qdepth: requested queue depth
2336 *
2337 * Adding support for new 'change_queue_depth' api.
2338*/
2339int
2340mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002342 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2343 VirtTarget *vtarget;
2344 struct scsi_target *starget;
2345 int max_depth;
2346 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002348 starget = scsi_target(sdev);
2349 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002350
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002351 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002352 if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2353 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 max_depth = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002355 else if (((vtarget->inq_data[0] & 0x1f) == 0x00) &&
2356 (vtarget->minSyncFactor <= MPT_ULTRA160 ))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2358 else
2359 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2360 } else {
2361 /* error case - No Inq. Data */
2362 max_depth = 1;
2363 }
2364 } else
2365 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2366
2367 if (qdepth > max_depth)
2368 qdepth = max_depth;
2369 if (qdepth == 1)
2370 tagged = 0;
2371 else
2372 tagged = MSG_SIMPLE_TAG;
2373
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002374 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2375 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376}
2377
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378/*
2379 * OS entry point to adjust the queue_depths on a per-device basis.
2380 * Called once per device the bus scan. Use it to force the queue_depth
2381 * member to 1 if a device does not support Q tags.
2382 * Return non-zero if fails.
2383 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002384int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002385mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002387 struct Scsi_Host *sh = sdev->host;
2388 VirtTarget *vtarget;
2389 VirtDevice *vdevice;
2390 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002394 starget = scsi_target(sdev);
2395 vtarget = starget->hostdata;
2396 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398 dsprintk((MYIOC_s_INFO_FMT
2399 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002400 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2401 if (hd->ioc->bus_type == SPI)
2402 dsprintk((MYIOC_s_INFO_FMT
2403 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2404 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2405 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002409 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 goto slave_configure_exit;
2411 }
2412
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002413 vdevice->configured_lun=1;
2414 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2415 indexed_lun = (vdevice->lun % 32);
2416 vtarget->luns[lun_index] |= (1 << indexed_lun);
2417 mptscsih_initTarget(hd, vtarget, sdev->lun, sdev->inquiry,
2418 sdev->inquiry_len );
2419 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
2421 dsprintk((MYIOC_s_INFO_FMT
2422 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002423 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002425 if (hd->ioc->bus_type == SPI)
2426 dsprintk((MYIOC_s_INFO_FMT
2427 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2428 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2429 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431slave_configure_exit:
2432
2433 dsprintk((MYIOC_s_INFO_FMT
2434 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002435 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2436 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 return 0;
2439}
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2442/*
2443 * Private routines...
2444 */
2445
2446/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2447/* Utility function to copy sense data from the scsi_cmnd buffer
2448 * to the FC and SCSI target structures.
2449 *
2450 */
2451static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002452mptscsih_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 -07002453{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002454 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 SCSIIORequest_t *pReq;
2456 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
2458 /* Get target structure
2459 */
2460 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002461 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
2463 if (sense_count) {
2464 u8 *sense_data;
2465 int req_index;
2466
2467 /* Copy the sense received into the scsi command block. */
2468 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2469 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2470 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2471
2472 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2473 */
2474 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002475 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 int idx;
2477 MPT_ADAPTER *ioc = hd->ioc;
2478
2479 idx = ioc->eventContext % ioc->eventLogSize;
2480 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2481 ioc->events[idx].eventContext = ioc->eventContext;
2482
2483 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2484 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002485 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2488
2489 ioc->eventContext++;
2490 }
2491 }
2492 } else {
2493 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2494 hd->ioc->name));
2495 }
2496}
2497
2498static u32
2499SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2500{
2501 MPT_SCSI_HOST *hd;
2502 int i;
2503
2504 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2505
2506 for (i = 0; i < hd->ioc->req_depth; i++) {
2507 if (hd->ScsiLookup[i] == sc) {
2508 return i;
2509 }
2510 }
2511
2512 return -1;
2513}
2514
2515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002516int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2518{
2519 MPT_SCSI_HOST *hd;
2520 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002521 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 dtmprintk((KERN_WARNING MYNAM
2524 ": IOC %s_reset routed to SCSI host driver!\n",
2525 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2526 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2527
2528 /* If a FW reload request arrives after base installed but
2529 * before all scsi hosts have been attached, then an alt_ioc
2530 * may have a NULL sh pointer.
2531 */
2532 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2533 return 0;
2534 else
2535 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2536
2537 if (reset_phase == MPT_IOC_SETUP_RESET) {
2538 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2539
2540 /* Clean Up:
2541 * 1. Set Hard Reset Pending Flag
2542 * All new commands go to doneQ
2543 */
2544 hd->resetPending = 1;
2545
2546 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2547 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2548
2549 /* 2. Flush running commands
2550 * Clean ScsiLookup (and associated memory)
2551 * AND clean mytaskQ
2552 */
2553
2554 /* 2b. Reply to OS all known outstanding I/O commands.
2555 */
2556 mptscsih_flush_running_cmds(hd);
2557
2558 /* 2c. If there was an internal command that
2559 * has not completed, configuration or io request,
2560 * free these resources.
2561 */
2562 if (hd->cmdPtr) {
2563 del_timer(&hd->timer);
2564 mpt_free_msg_frame(ioc, hd->cmdPtr);
2565 }
2566
2567 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2568
2569 } else {
2570 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2571
2572 /* Once a FW reload begins, all new OS commands are
2573 * redirected to the doneQ w/ a reset status.
2574 * Init all control structures.
2575 */
2576
2577 /* ScsiLookup initialization
2578 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002579 for (ii=0; ii < hd->ioc->req_depth; ii++)
2580 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582 /* 2. Chain Buffer initialization
2583 */
2584
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002585 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002587 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2589 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2590 }
2591
2592 /* 5. Enable new commands to be posted
2593 */
2594 spin_lock_irqsave(&ioc->FreeQlock, flags);
2595 hd->tmPending = 0;
2596 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2597 hd->resetPending = 0;
2598 hd->tmState = TM_STATE_NONE;
2599
2600 /* 6. If there was an internal command,
2601 * wake this process up.
2602 */
2603 if (hd->cmdPtr) {
2604 /*
2605 * Wake up the original calling thread
2606 */
2607 hd->pLocal = &hd->localReply;
2608 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002609 hd->scandv_wait_done = 1;
2610 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 hd->cmdPtr = NULL;
2612 }
2613
Michael Reed05e8ec12006-01-13 14:31:54 -06002614 /* 7. SPI: Set flag to force DV and re-read IOC Page 3
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002616 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2618 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2619 }
2620
Michael Reed05e8ec12006-01-13 14:31:54 -06002621 /* 7. FC: Rescan for blocked rports which might have returned.
2622 */
2623 else if (ioc->bus_type == FC) {
2624 int work_count;
2625 unsigned long flags;
2626
2627 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2628 work_count = ++ioc->fc_rescan_work_count;
2629 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2630 if (work_count == 1)
2631 schedule_work(&ioc->fc_rescan_work);
2632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2634
2635 }
2636
2637 return 1; /* currently means nothing really */
2638}
2639
2640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002641int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2643{
2644 MPT_SCSI_HOST *hd;
2645 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
Michael Reed05e8ec12006-01-13 14:31:54 -06002646 int work_count;
2647 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
2649 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2650 ioc->name, event));
2651
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002652 if (ioc->sh == NULL ||
2653 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2654 return 1;
2655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 switch (event) {
2657 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2658 /* FIXME! */
2659 break;
2660 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2661 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002662 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002663 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 break;
2665 case MPI_EVENT_LOGOUT: /* 09 */
2666 /* FIXME! */
2667 break;
2668
Michael Reed05e8ec12006-01-13 14:31:54 -06002669 case MPI_EVENT_RESCAN: /* 06 */
2670 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2671 work_count = ++ioc->fc_rescan_work_count;
2672 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2673 if (work_count == 1)
2674 schedule_work(&ioc->fc_rescan_work);
2675 break;
2676
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 /*
2678 * CHECKME! Don't think we need to do
2679 * anything for these, but...
2680 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2682 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2683 /*
2684 * CHECKME! Falling thru...
2685 */
2686 break;
2687
2688 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002689 {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07002690#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002691 pMpiEventDataRaid_t pRaidEventData =
2692 (pMpiEventDataRaid_t) pEvReply->Data;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002693 /* Domain Validation Needed */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002694 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002695 pRaidEventData->ReasonCode ==
2696 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2697 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002699 break;
2700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 case MPI_EVENT_NONE: /* 00 */
2703 case MPI_EVENT_LOG_DATA: /* 01 */
2704 case MPI_EVENT_STATE_CHANGE: /* 02 */
2705 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2706 default:
2707 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2708 break;
2709 }
2710
2711 return 1; /* currently means nothing really */
2712}
2713
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2715/*
2716 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2717 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002718 * @vtarget: per target private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 * @lun: SCSI LUN id
2720 * @data: Pointer to data
2721 * @dlen: Number of INQUIRY bytes
2722 *
2723 * NOTE: It's only SAFE to call this routine if data points to
2724 * sane & valid STANDARD INQUIRY data!
2725 *
2726 * Allocate and initialize memory for this target.
2727 * Save inquiry data.
2728 *
2729 */
2730static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002731mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002733 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 char data_56;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002735 int inq_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002738 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740 /*
2741 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2742 * (i.e. The targer is capable of supporting the specified peripheral device type
2743 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002744 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 * capable of supporting a physical device on this logical unit). This is to work
2746 * around a bug in th emid-layer in some distributions in which the mid-layer will
2747 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2748 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002749 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002751
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 /* Is LUN supported? If so, upper 2 bits will be 0
2753 * in first byte of inquiry data.
2754 */
2755 if (data[0] & 0xe0)
2756 return;
2757
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002758 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002761 if (data)
2762 vtarget->type = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002764 if (hd->ioc->bus_type != SPI)
2765 return;
2766
2767 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2768 /* Treat all Processors as SAF-TE if
2769 * command line option is set */
2770 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2771 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
2772 }else if ((data[0] == TYPE_PROCESSOR) &&
2773 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2774 if ( dlen > 49 ) {
2775 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2776 if ( data[44] == 'S' &&
2777 data[45] == 'A' &&
2778 data[46] == 'F' &&
2779 data[47] == '-' &&
2780 data[48] == 'T' &&
2781 data[49] == 'E' ) {
2782 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2783 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 }
2785 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002786 }
2787 if (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2788 inq_len = dlen < 8 ? dlen : 8;
2789 memcpy (vtarget->inq_data, data, inq_len);
2790 /* If have not done DV, set the DV flag.
2791 */
2792 pSpi = &hd->ioc->spi_data;
2793 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2794 if (pSpi->dvStatus[vtarget->target_id] & MPT_SCSICFG_DV_NOT_DONE)
2795 pSpi->dvStatus[vtarget->target_id] |= MPT_SCSICFG_NEED_DV;
2796 }
2797 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002799 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2800 if (dlen > 56) {
2801 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2802 /* Update the target capabilities
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002804 data_56 = data[56];
2805 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002807 }
2808 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
2809 } else {
2810 /* Initial Inquiry may not request enough data bytes to
2811 * obtain byte 57. DV will; if target doesn't return
2812 * at least 57 bytes, data[56] will be zero. */
2813 if (dlen > 56) {
2814 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2815 /* Update the target capabilities
2816 */
2817 data_56 = data[56];
2818 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
2819 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 }
2821 }
2822 }
2823}
2824
2825/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2826/*
2827 * Update the target negotiation parameters based on the
2828 * the Inquiry data, adapter capabilities, and NVRAM settings.
2829 *
2830 */
2831static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002832mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, char byte56)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002834 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 int id = (int) target->target_id;
2836 int nvram;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002837 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 int ii;
2839 u8 width = MPT_NARROW;
2840 u8 factor = MPT_ASYNC;
2841 u8 offset = 0;
2842 u8 version, nfactor;
2843 u8 noQas = 1;
2844
2845 target->negoFlags = pspi_data->noQas;
2846
2847 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2848 * support. If available, default QAS to off and allow enabling.
2849 * If not available, default QAS to on, turn off for non-disks.
2850 */
2851
2852 /* Set flags based on Inquiry data
2853 */
2854 version = target->inq_data[2] & 0x07;
2855 if (version < 2) {
2856 width = 0;
2857 factor = MPT_ULTRA2;
2858 offset = pspi_data->maxSyncOffset;
2859 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2860 } else {
2861 if (target->inq_data[7] & 0x20) {
2862 width = 1;
2863 }
2864
2865 if (target->inq_data[7] & 0x10) {
2866 factor = pspi_data->minSyncFactor;
2867 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2868 /* bits 2 & 3 show Clocking support */
2869 if ((byte56 & 0x0C) == 0)
2870 factor = MPT_ULTRA2;
2871 else {
2872 if ((byte56 & 0x03) == 0)
2873 factor = MPT_ULTRA160;
2874 else {
2875 factor = MPT_ULTRA320;
2876 if (byte56 & 0x02)
2877 {
2878 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2879 noQas = 0;
2880 }
2881 if (target->inq_data[0] == TYPE_TAPE) {
2882 if (byte56 & 0x01)
2883 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2884 }
2885 }
2886 }
2887 } else {
2888 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2889 noQas = 0;
2890 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002891
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 offset = pspi_data->maxSyncOffset;
2893
2894 /* If RAID, never disable QAS
2895 * else if non RAID, do not disable
2896 * QAS if bit 1 is set
2897 * bit 1 QAS support, non-raid only
2898 * bit 0 IU support
2899 */
2900 if (target->raidVolume == 1) {
2901 noQas = 0;
2902 }
2903 } else {
2904 factor = MPT_ASYNC;
2905 offset = 0;
2906 }
2907 }
2908
2909 if ( (target->inq_data[7] & 0x02) == 0) {
2910 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2911 }
2912
2913 /* Update tflags based on NVRAM settings. (SCSI only)
2914 */
2915 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2916 nvram = pspi_data->nvram[id];
2917 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2918
2919 if (width)
2920 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2921
2922 if (offset > 0) {
2923 /* Ensure factor is set to the
2924 * maximum of: adapter, nvram, inquiry
2925 */
2926 if (nfactor) {
2927 if (nfactor < pspi_data->minSyncFactor )
2928 nfactor = pspi_data->minSyncFactor;
2929
2930 factor = max(factor, nfactor);
2931 if (factor == MPT_ASYNC)
2932 offset = 0;
2933 } else {
2934 offset = 0;
2935 factor = MPT_ASYNC;
2936 }
2937 } else {
2938 factor = MPT_ASYNC;
2939 }
2940 }
2941
2942 /* Make sure data is consistent
2943 */
2944 if ((!width) && (factor < MPT_ULTRA2)) {
2945 factor = MPT_ULTRA2;
2946 }
2947
2948 /* Save the data to the target structure.
2949 */
2950 target->minSyncFactor = factor;
2951 target->maxOffset = offset;
2952 target->maxWidth = width;
2953
2954 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2955
2956 /* Disable unused features.
2957 */
2958 if (!width)
2959 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2960
2961 if (!offset)
2962 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2963
2964 if ( factor > MPT_ULTRA320 )
2965 noQas = 0;
2966
2967 /* GEM, processor WORKAROUND
2968 */
2969 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2970 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2971 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2972 } else {
2973 if (noQas && (pspi_data->noQas == 0)) {
2974 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2975 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2976
2977 /* Disable QAS in a mixed configuration case
2978 */
2979
2980 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2981 for (ii = 0; ii < id; ii++) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002982 if ( (vtarget = hd->Targets[ii]) ) {
2983 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2984 mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 }
2987 }
2988 }
2989
2990 /* Write SDP1 on this I/O to this target */
2991 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2992 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2993 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2994 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2995 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2996 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2997 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2998 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2999 }
3000}
3001
3002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003/*
3004 * If no Target, bus reset on 1st I/O. Set the flag to
3005 * prevent any future negotiations to this device.
3006 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003007static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003008mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003010 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003012 if ((vdev = sc->device->hostdata) != NULL)
3013 hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return;
3015}
3016
3017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3018/*
3019 * SCSI Config Page functionality ...
3020 */
3021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3022/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
3023 * based on width, factor and offset parameters.
3024 * @width: bus width
3025 * @factor: sync factor
3026 * @offset: sync offset
3027 * @requestedPtr: pointer to requested values (updated)
3028 * @configurationPtr: pointer to configuration values (updated)
3029 * @flags: flags to block WDTR or SDTR negotiation
3030 *
3031 * Return: None.
3032 *
3033 * Remark: Called by writeSDP1 and _dv_params
3034 */
3035static void
3036mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3037{
3038 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3039 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3040
3041 *configurationPtr = 0;
3042 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3043 *requestedPtr |= (offset << 16) | (factor << 8);
3044
3045 if (width && offset && !nowide && !nosync) {
3046 if (factor < MPT_ULTRA160) {
3047 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3048 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3049 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3050 if (flags & MPT_TAPE_NEGO_IDP)
3051 *requestedPtr |= 0x08000000;
3052 } else if (factor < MPT_ULTRA2) {
3053 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3054 }
3055 }
3056
3057 if (nowide)
3058 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3059
3060 if (nosync)
3061 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3062
3063 return;
3064}
3065
3066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3067/* mptscsih_writeSDP1 - write SCSI Device Page 1
3068 * @hd: Pointer to a SCSI Host Strucutre
3069 * @portnum: IOC port number
3070 * @target_id: writeSDP1 for single ID
3071 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3072 *
3073 * Return: -EFAULT if read of config page header fails
3074 * or 0 if success.
3075 *
3076 * Remark: If a target has been found, the settings from the
3077 * target structure are used, else the device is set
3078 * to async/narrow.
3079 *
3080 * Remark: Called during init and after a FW reload.
3081 * Remark: We do not wait for a return, write pages sequentially.
3082 */
3083static int
3084mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3085{
3086 MPT_ADAPTER *ioc = hd->ioc;
3087 Config_t *pReq;
3088 SCSIDevicePage1_t *pData;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003089 VirtTarget *vtarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 MPT_FRAME_HDR *mf;
3091 dma_addr_t dataDma;
3092 u16 req_idx;
3093 u32 frameOffset;
3094 u32 requested, configuration, flagsLength;
3095 int ii, nvram;
3096 int id = 0, maxid = 0;
3097 u8 width;
3098 u8 factor;
3099 u8 offset;
3100 u8 bus = 0;
3101 u8 negoFlags;
3102 u8 maxwidth, maxoffset, maxfactor;
3103
3104 if (ioc->spi_data.sdp1length == 0)
3105 return 0;
3106
3107 if (flags & MPT_SCSICFG_ALL_IDS) {
3108 id = 0;
3109 maxid = ioc->sh->max_id - 1;
3110 } else if (ioc->sh) {
3111 id = target_id;
3112 maxid = min_t(int, id, ioc->sh->max_id - 1);
3113 }
3114
3115 for (; id <= maxid; id++) {
3116
3117 if (id == ioc->pfacts[portnum].PortSCSIID)
3118 continue;
3119
3120 /* Use NVRAM to get adapter and target maximums
3121 * Data over-riden by target structure information, if present
3122 */
3123 maxwidth = ioc->spi_data.maxBusWidth;
3124 maxoffset = ioc->spi_data.maxSyncOffset;
3125 maxfactor = ioc->spi_data.minSyncFactor;
3126 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3127 nvram = ioc->spi_data.nvram[id];
3128
3129 if (maxwidth)
3130 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3131
3132 if (maxoffset > 0) {
3133 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3134 if (maxfactor == 0) {
3135 /* Key for async */
3136 maxfactor = MPT_ASYNC;
3137 maxoffset = 0;
3138 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3139 maxfactor = ioc->spi_data.minSyncFactor;
3140 }
3141 } else
3142 maxfactor = MPT_ASYNC;
3143 }
3144
3145 /* Set the negotiation flags.
3146 */
3147 negoFlags = ioc->spi_data.noQas;
3148 if (!maxwidth)
3149 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3150
3151 if (!maxoffset)
3152 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3153
3154 if (flags & MPT_SCSICFG_USE_NVRAM) {
3155 width = maxwidth;
3156 factor = maxfactor;
3157 offset = maxoffset;
3158 } else {
3159 width = 0;
3160 factor = MPT_ASYNC;
3161 offset = 0;
3162 //negoFlags = 0;
3163 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3164 }
3165
3166 /* If id is not a raid volume, get the updated
3167 * transmission settings from the target structure.
3168 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003169 if (hd->Targets && (vtarget = hd->Targets[id]) && !vtarget->raidVolume) {
3170 width = vtarget->maxWidth;
3171 factor = vtarget->minSyncFactor;
3172 offset = vtarget->maxOffset;
3173 negoFlags = vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003175
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3177 /* Force to async and narrow if DV has not been executed
3178 * for this ID
3179 */
3180 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3181 width = 0;
3182 factor = MPT_ASYNC;
3183 offset = 0;
3184 }
3185#endif
3186
3187 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003188 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190 mptscsih_setDevicePage1Flags(width, factor, offset,
3191 &requested, &configuration, negoFlags);
3192 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3193 target_id, width, factor, offset, negoFlags, requested, configuration));
3194
3195 /* Get a MF for this command.
3196 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003197 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003198 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3199 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 return -EAGAIN;
3201 }
3202
3203 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3204 hd->ioc->name, mf, id, requested, configuration));
3205
3206
3207 /* Set the request and the data pointers.
3208 * Request takes: 36 bytes (32 bit SGE)
3209 * SCSI Device Page 1 requires 16 bytes
3210 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3211 * and MF size >= 64 bytes.
3212 * Place data at end of MF.
3213 */
3214 pReq = (Config_t *)mf;
3215
3216 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3217 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3218
3219 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3220 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3221
3222 /* Complete the request frame (same for all requests).
3223 */
3224 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3225 pReq->Reserved = 0;
3226 pReq->ChainOffset = 0;
3227 pReq->Function = MPI_FUNCTION_CONFIG;
3228 pReq->ExtPageLength = 0;
3229 pReq->ExtPageType = 0;
3230 pReq->MsgFlags = 0;
3231 for (ii=0; ii < 8; ii++) {
3232 pReq->Reserved2[ii] = 0;
3233 }
3234 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3235 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3236 pReq->Header.PageNumber = 1;
3237 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3238 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3239
3240 /* Add a SGE to the config request.
3241 */
3242 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3243
3244 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3245
3246 /* Set up the common data portion
3247 */
3248 pData->Header.PageVersion = pReq->Header.PageVersion;
3249 pData->Header.PageLength = pReq->Header.PageLength;
3250 pData->Header.PageNumber = pReq->Header.PageNumber;
3251 pData->Header.PageType = pReq->Header.PageType;
3252 pData->RequestedParameters = cpu_to_le32(requested);
3253 pData->Reserved = 0;
3254 pData->Configuration = cpu_to_le32(configuration);
3255
3256 dprintk((MYIOC_s_INFO_FMT
3257 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3258 ioc->name, id, (id | (bus<<8)),
3259 requested, configuration));
3260
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003261 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 }
3263
3264 return 0;
3265}
3266
3267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3268/* mptscsih_writeIOCPage4 - write IOC Page 4
3269 * @hd: Pointer to a SCSI Host Structure
3270 * @target_id: write IOC Page4 for this ID & Bus
3271 *
3272 * Return: -EAGAIN if unable to obtain a Message Frame
3273 * or 0 if success.
3274 *
3275 * Remark: We do not wait for a return, write pages sequentially.
3276 */
3277static int
3278mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3279{
3280 MPT_ADAPTER *ioc = hd->ioc;
3281 Config_t *pReq;
3282 IOCPage4_t *IOCPage4Ptr;
3283 MPT_FRAME_HDR *mf;
3284 dma_addr_t dataDma;
3285 u16 req_idx;
3286 u32 frameOffset;
3287 u32 flagsLength;
3288 int ii;
3289
3290 /* Get a MF for this command.
3291 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003292 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003293 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 ioc->name));
3295 return -EAGAIN;
3296 }
3297
3298 /* Set the request and the data pointers.
3299 * Place data at end of MF.
3300 */
3301 pReq = (Config_t *)mf;
3302
3303 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3304 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3305
3306 /* Complete the request frame (same for all requests).
3307 */
3308 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3309 pReq->Reserved = 0;
3310 pReq->ChainOffset = 0;
3311 pReq->Function = MPI_FUNCTION_CONFIG;
3312 pReq->ExtPageLength = 0;
3313 pReq->ExtPageType = 0;
3314 pReq->MsgFlags = 0;
3315 for (ii=0; ii < 8; ii++) {
3316 pReq->Reserved2[ii] = 0;
3317 }
3318
3319 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3320 dataDma = ioc->spi_data.IocPg4_dma;
3321 ii = IOCPage4Ptr->ActiveSEP++;
3322 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3323 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3324 pReq->Header = IOCPage4Ptr->Header;
3325 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3326
3327 /* Add a SGE to the config request.
3328 */
3329 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3330 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3331
3332 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3333
3334 dinitprintk((MYIOC_s_INFO_FMT
3335 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3336 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3337
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003338 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 return 0;
3341}
3342
3343/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3344/*
3345 * Bus Scan and Domain Validation functionality ...
3346 */
3347
3348/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3349/*
3350 * mptscsih_scandv_complete - Scan and DV callback routine registered
3351 * to Fustion MPT (base) driver.
3352 *
3353 * @ioc: Pointer to MPT_ADAPTER structure
3354 * @mf: Pointer to original MPT request frame
3355 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3356 *
3357 * This routine is called from mpt.c::mpt_interrupt() at the completion
3358 * of any SCSI IO request.
3359 * This routine is registered with the Fusion MPT (base) driver at driver
3360 * load/init time via the mpt_register() API call.
3361 *
3362 * Returns 1 indicating alloc'd request frame ptr should be freed.
3363 *
3364 * Remark: Sets a completion code and (possibly) saves sense data
3365 * in the IOC member localReply structure.
3366 * Used ONLY for DV and other internal commands.
3367 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003368int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3370{
3371 MPT_SCSI_HOST *hd;
3372 SCSIIORequest_t *pReq;
3373 int completionCode;
3374 u16 req_idx;
3375
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003376 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3377
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 if ((mf == NULL) ||
3379 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3380 printk(MYIOC_s_ERR_FMT
3381 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3382 ioc->name, mf?"BAD":"NULL", (void *) mf);
3383 goto wakeup;
3384 }
3385
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 del_timer(&hd->timer);
3387 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3388 hd->ScsiLookup[req_idx] = NULL;
3389 pReq = (SCSIIORequest_t *) mf;
3390
3391 if (mf != hd->cmdPtr) {
3392 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3393 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3394 }
3395 hd->cmdPtr = NULL;
3396
3397 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3398 hd->ioc->name, mf, mr, req_idx));
3399
3400 hd->pLocal = &hd->localReply;
3401 hd->pLocal->scsiStatus = 0;
3402
3403 /* If target struct exists, clear sense valid flag.
3404 */
3405 if (mr == NULL) {
3406 completionCode = MPT_SCANDV_GOOD;
3407 } else {
3408 SCSIIOReply_t *pReply;
3409 u16 status;
3410 u8 scsi_status;
3411
3412 pReply = (SCSIIOReply_t *) mr;
3413
3414 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3415 scsi_status = pReply->SCSIStatus;
3416
3417 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3418 status, pReply->SCSIState, scsi_status,
3419 le32_to_cpu(pReply->IOCLogInfo)));
3420
3421 switch(status) {
3422
3423 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3424 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3425 break;
3426
3427 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3428 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3429 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3430 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3431 completionCode = MPT_SCANDV_DID_RESET;
3432 break;
3433
3434 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3435 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3436 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3437 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3438 ConfigReply_t *pr = (ConfigReply_t *)mr;
3439 completionCode = MPT_SCANDV_GOOD;
3440 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3441 hd->pLocal->header.PageLength = pr->Header.PageLength;
3442 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3443 hd->pLocal->header.PageType = pr->Header.PageType;
3444
3445 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3446 /* If the RAID Volume request is successful,
3447 * return GOOD, else indicate that
3448 * some type of error occurred.
3449 */
3450 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003451 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 completionCode = MPT_SCANDV_GOOD;
3453 else
3454 completionCode = MPT_SCANDV_SOME_ERROR;
3455
3456 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3457 u8 *sense_data;
3458 int sz;
3459
3460 /* save sense data in global structure
3461 */
3462 completionCode = MPT_SCANDV_SENSE;
3463 hd->pLocal->scsiStatus = scsi_status;
3464 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3465 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3466
3467 sz = min_t(int, pReq->SenseBufferLength,
3468 SCSI_STD_SENSE_BYTES);
3469 memcpy(hd->pLocal->sense, sense_data, sz);
3470
3471 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3472 sense_data));
3473 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3474 if (pReq->CDB[0] == INQUIRY)
3475 completionCode = MPT_SCANDV_ISSUE_SENSE;
3476 else
3477 completionCode = MPT_SCANDV_DID_RESET;
3478 }
3479 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3480 completionCode = MPT_SCANDV_DID_RESET;
3481 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3482 completionCode = MPT_SCANDV_DID_RESET;
3483 else {
3484 completionCode = MPT_SCANDV_GOOD;
3485 hd->pLocal->scsiStatus = scsi_status;
3486 }
3487 break;
3488
3489 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3490 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3491 completionCode = MPT_SCANDV_DID_RESET;
3492 else
3493 completionCode = MPT_SCANDV_SOME_ERROR;
3494 break;
3495
3496 default:
3497 completionCode = MPT_SCANDV_SOME_ERROR;
3498 break;
3499
3500 } /* switch(status) */
3501
3502 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3503 completionCode));
3504 } /* end of address reply case */
3505
3506 hd->pLocal->completion = completionCode;
3507
3508 /* MF and RF are freed in mpt_interrupt
3509 */
3510wakeup:
3511 /* Free Chain buffers (will never chain) in scan or dv */
3512 //mptscsih_freeChainBuffers(ioc, req_idx);
3513
3514 /*
3515 * Wake up the original calling thread
3516 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003517 hd->scandv_wait_done = 1;
3518 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 return 1;
3521}
3522
3523/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3524/* mptscsih_timer_expired - Call back for timer process.
3525 * Used only for dv functionality.
3526 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3527 *
3528 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003529void
3530mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531{
3532 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3533
3534 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3535
3536 if (hd->cmdPtr) {
3537 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3538
3539 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3540 /* Desire to issue a task management request here.
3541 * TM requests MUST be single threaded.
3542 * If old eh code and no TM current, issue request.
3543 * If new eh code, do nothing. Wait for OS cmd timeout
3544 * for bus reset.
3545 */
3546 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3547 } else {
3548 /* Perform a FW reload */
3549 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3550 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3551 }
3552 }
3553 } else {
3554 /* This should NEVER happen */
3555 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3556 }
3557
3558 /* No more processing.
3559 * TM call will generate an interrupt for SCSI TM Management.
3560 * The FW will reply to all outstanding commands, callback will finish cleanup.
3561 * Hard reset clean-up will free all resources.
3562 */
3563 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3564
3565 return;
3566}
3567
3568#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3570/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3571 * @hd: Pointer to scsi host structure
3572 * @action: What do be done.
3573 * @id: Logical target id.
3574 * @bus: Target locations bus.
3575 *
3576 * Returns: < 0 on a fatal error
3577 * 0 on success
3578 *
3579 * Remark: Wait to return until reply processed by the ISR.
3580 */
3581static int
3582mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3583{
3584 MpiRaidActionRequest_t *pReq;
3585 MPT_FRAME_HDR *mf;
3586 int in_isr;
3587
3588 in_isr = in_interrupt();
3589 if (in_isr) {
3590 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3591 hd->ioc->name));
3592 return -EPERM;
3593 }
3594
3595 /* Get and Populate a free Frame
3596 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003597 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3599 hd->ioc->name));
3600 return -EAGAIN;
3601 }
3602 pReq = (MpiRaidActionRequest_t *)mf;
3603 pReq->Action = action;
3604 pReq->Reserved1 = 0;
3605 pReq->ChainOffset = 0;
3606 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3607 pReq->VolumeID = io->id;
3608 pReq->VolumeBus = io->bus;
3609 pReq->PhysDiskNum = io->physDiskNum;
3610 pReq->MsgFlags = 0;
3611 pReq->Reserved2 = 0;
3612 pReq->ActionDataWord = 0; /* Reserved for this action */
3613 //pReq->ActionDataSGE = 0;
3614
3615 mpt_add_sge((char *)&pReq->ActionDataSGE,
3616 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3617
3618 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3619 hd->ioc->name, action, io->id));
3620
3621 hd->pLocal = NULL;
3622 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003623 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624
3625 /* Save cmd pointer, for resource free if timeout or
3626 * FW reload occurs
3627 */
3628 hd->cmdPtr = mf;
3629
3630 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003631 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3632 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633
3634 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3635 return -1;
3636
3637 return 0;
3638}
3639#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3640
3641/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3642/**
3643 * mptscsih_do_cmd - Do internal command.
3644 * @hd: MPT_SCSI_HOST pointer
3645 * @io: INTERNAL_CMD pointer.
3646 *
3647 * Issue the specified internally generated command and do command
3648 * specific cleanup. For bus scan / DV only.
3649 * NOTES: If command is Inquiry and status is good,
3650 * initialize a target structure, save the data
3651 *
3652 * Remark: Single threaded access only.
3653 *
3654 * Return:
3655 * < 0 if an illegal command or no resources
3656 *
3657 * 0 if good
3658 *
3659 * > 0 if command complete but some type of completion error.
3660 */
3661static int
3662mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3663{
3664 MPT_FRAME_HDR *mf;
3665 SCSIIORequest_t *pScsiReq;
3666 SCSIIORequest_t ReqCopy;
3667 int my_idx, ii, dir;
3668 int rc, cmdTimeout;
3669 int in_isr;
3670 char cmdLen;
3671 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3672 char cmd = io->cmd;
3673
3674 in_isr = in_interrupt();
3675 if (in_isr) {
3676 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3677 hd->ioc->name));
3678 return -EPERM;
3679 }
3680
3681
3682 /* Set command specific information
3683 */
3684 switch (cmd) {
3685 case INQUIRY:
3686 cmdLen = 6;
3687 dir = MPI_SCSIIO_CONTROL_READ;
3688 CDB[0] = cmd;
3689 CDB[4] = io->size;
3690 cmdTimeout = 10;
3691 break;
3692
3693 case TEST_UNIT_READY:
3694 cmdLen = 6;
3695 dir = MPI_SCSIIO_CONTROL_READ;
3696 cmdTimeout = 10;
3697 break;
3698
3699 case START_STOP:
3700 cmdLen = 6;
3701 dir = MPI_SCSIIO_CONTROL_READ;
3702 CDB[0] = cmd;
3703 CDB[4] = 1; /*Spin up the disk */
3704 cmdTimeout = 15;
3705 break;
3706
3707 case REQUEST_SENSE:
3708 cmdLen = 6;
3709 CDB[0] = cmd;
3710 CDB[4] = io->size;
3711 dir = MPI_SCSIIO_CONTROL_READ;
3712 cmdTimeout = 10;
3713 break;
3714
3715 case READ_BUFFER:
3716 cmdLen = 10;
3717 dir = MPI_SCSIIO_CONTROL_READ;
3718 CDB[0] = cmd;
3719 if (io->flags & MPT_ICFLAG_ECHO) {
3720 CDB[1] = 0x0A;
3721 } else {
3722 CDB[1] = 0x02;
3723 }
3724
3725 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3726 CDB[1] |= 0x01;
3727 }
3728 CDB[6] = (io->size >> 16) & 0xFF;
3729 CDB[7] = (io->size >> 8) & 0xFF;
3730 CDB[8] = io->size & 0xFF;
3731 cmdTimeout = 10;
3732 break;
3733
3734 case WRITE_BUFFER:
3735 cmdLen = 10;
3736 dir = MPI_SCSIIO_CONTROL_WRITE;
3737 CDB[0] = cmd;
3738 if (io->flags & MPT_ICFLAG_ECHO) {
3739 CDB[1] = 0x0A;
3740 } else {
3741 CDB[1] = 0x02;
3742 }
3743 CDB[6] = (io->size >> 16) & 0xFF;
3744 CDB[7] = (io->size >> 8) & 0xFF;
3745 CDB[8] = io->size & 0xFF;
3746 cmdTimeout = 10;
3747 break;
3748
3749 case RESERVE:
3750 cmdLen = 6;
3751 dir = MPI_SCSIIO_CONTROL_READ;
3752 CDB[0] = cmd;
3753 cmdTimeout = 10;
3754 break;
3755
3756 case RELEASE:
3757 cmdLen = 6;
3758 dir = MPI_SCSIIO_CONTROL_READ;
3759 CDB[0] = cmd;
3760 cmdTimeout = 10;
3761 break;
3762
3763 case SYNCHRONIZE_CACHE:
3764 cmdLen = 10;
3765 dir = MPI_SCSIIO_CONTROL_READ;
3766 CDB[0] = cmd;
3767// CDB[1] = 0x02; /* set immediate bit */
3768 cmdTimeout = 10;
3769 break;
3770
3771 default:
3772 /* Error Case */
3773 return -EFAULT;
3774 }
3775
3776 /* Get and Populate a free Frame
3777 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003778 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3780 hd->ioc->name));
3781 return -EBUSY;
3782 }
3783
3784 pScsiReq = (SCSIIORequest_t *) mf;
3785
3786 /* Get the request index */
3787 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3788 ADD_INDEX_LOG(my_idx); /* for debug */
3789
3790 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3791 pScsiReq->TargetID = io->physDiskNum;
3792 pScsiReq->Bus = 0;
3793 pScsiReq->ChainOffset = 0;
3794 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3795 } else {
3796 pScsiReq->TargetID = io->id;
3797 pScsiReq->Bus = io->bus;
3798 pScsiReq->ChainOffset = 0;
3799 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3800 }
3801
3802 pScsiReq->CDBLength = cmdLen;
3803 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3804
3805 pScsiReq->Reserved = 0;
3806
3807 pScsiReq->MsgFlags = mpt_msg_flags();
3808 /* MsgContext set in mpt_get_msg_fram call */
3809
3810 for (ii=0; ii < 8; ii++)
3811 pScsiReq->LUN[ii] = 0;
3812 pScsiReq->LUN[1] = io->lun;
3813
3814 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3815 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3816 else
3817 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3818
3819 if (cmd == REQUEST_SENSE) {
3820 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3821 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3822 hd->ioc->name, cmd));
3823 }
3824
3825 for (ii=0; ii < 16; ii++)
3826 pScsiReq->CDB[ii] = CDB[ii];
3827
3828 pScsiReq->DataLength = cpu_to_le32(io->size);
3829 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3830 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3831
3832 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3833 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3834
3835 if (dir == MPI_SCSIIO_CONTROL_READ) {
3836 mpt_add_sge((char *) &pScsiReq->SGL,
3837 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3838 io->data_dma);
3839 } else {
3840 mpt_add_sge((char *) &pScsiReq->SGL,
3841 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3842 io->data_dma);
3843 }
3844
3845 /* The ISR will free the request frame, but we need
3846 * the information to initialize the target. Duplicate.
3847 */
3848 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3849
3850 /* Issue this command after:
3851 * finish init
3852 * add timer
3853 * Wait until the reply has been received
3854 * ScsiScanDvCtx callback function will
3855 * set hd->pLocal;
3856 * set scandv_wait_done and call wake_up
3857 */
3858 hd->pLocal = NULL;
3859 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003860 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
3862 /* Save cmd pointer, for resource free if timeout or
3863 * FW reload occurs
3864 */
3865 hd->cmdPtr = mf;
3866
3867 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003868 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3869 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
3871 if (hd->pLocal) {
3872 rc = hd->pLocal->completion;
3873 hd->pLocal->skip = 0;
3874
3875 /* Always set fatal error codes in some cases.
3876 */
3877 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3878 rc = -ENXIO;
3879 else if (rc == MPT_SCANDV_SOME_ERROR)
3880 rc = -rc;
3881 } else {
3882 rc = -EFAULT;
3883 /* This should never happen. */
3884 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3885 hd->ioc->name));
3886 }
3887
3888 return rc;
3889}
3890
3891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3892/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003893 * mptscsih_negotiate_to_asyn_narrow - Restore devices to default state
3894 * @hd: Pointer to a SCSI HOST structure
3895 * @vtarget: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 *
3897 * Uses the ISR, but with special processing.
3898 * MUST be single-threaded.
3899 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003901static void
3902mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903{
3904 MPT_ADAPTER *ioc= hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003905 SCSIDevicePage1_t *pcfg1Data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 CONFIGPARMS cfg;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003907 dma_addr_t cfg1_dma_addr;
3908 ConfigPageHeader_t header;
3909 int id;
3910 int requested, configuration, data,i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 u8 flags, factor;
3912
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003913 if (ioc->bus_type != SPI)
3914 return;
3915
3916 if (!ioc->spi_data.sdp1length)
3917 return;
3918
3919 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3920 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3921
3922 if (pcfg1Data == NULL)
3923 return;
3924
3925 header.PageVersion = ioc->spi_data.sdp1version;
3926 header.PageLength = ioc->spi_data.sdp1length;
3927 header.PageNumber = 1;
3928 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3929 cfg.cfghdr.hdr = &header;
3930 cfg.physAddr = cfg1_dma_addr;
3931 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3932 cfg.dir = 1;
3933 cfg.timeout = 0;
3934
3935 if (vtarget->raidVolume && ioc->raid_data.pIocPg3) {
3936 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3937 id = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID;
3938 flags = hd->ioc->spi_data.noQas;
3939 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3940 data = hd->ioc->spi_data.nvram[id];
3941 if (data & MPT_NVRAM_WIDE_DISABLE)
3942 flags |= MPT_TARGET_NO_NEGO_WIDE;
3943 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
3944 if ((factor == 0) || (factor == MPT_ASYNC))
3945 flags |= MPT_TARGET_NO_NEGO_SYNC;
3946 }
3947 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3948 &configuration, flags);
3949 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3950 "offset=0 negoFlags=%x request=%x config=%x\n",
3951 id, flags, requested, configuration));
3952 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3953 pcfg1Data->Reserved = 0;
3954 pcfg1Data->Configuration = cpu_to_le32(configuration);
3955 cfg.pageAddr = (vtarget->bus_id<<8) | id;
3956 mpt_config(hd->ioc, &cfg);
3957 }
3958 } else {
3959 flags = vtarget->negoFlags;
3960 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3961 &configuration, flags);
3962 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3963 "offset=0 negoFlags=%x request=%x config=%x\n",
3964 vtarget->target_id, flags, requested, configuration));
3965 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3966 pcfg1Data->Reserved = 0;
3967 pcfg1Data->Configuration = cpu_to_le32(configuration);
3968 cfg.pageAddr = (vtarget->bus_id<<8) | vtarget->target_id;
3969 mpt_config(hd->ioc, &cfg);
3970 }
3971
3972 if (pcfg1Data)
3973 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr);
3974}
3975
3976/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3977/**
3978 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3979 * @hd: Pointer to a SCSI HOST structure
3980 * @vtarget: per device private data
3981 * @lun: lun
3982 *
3983 * Uses the ISR, but with special processing.
3984 * MUST be single-threaded.
3985 *
3986 */
3987static void
3988mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3989{
3990 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992 /* Following parameters will not change
3993 * in this routine.
3994 */
3995 iocmd.cmd = SYNCHRONIZE_CACHE;
3996 iocmd.flags = 0;
3997 iocmd.physDiskNum = -1;
3998 iocmd.data = NULL;
3999 iocmd.data_dma = -1;
4000 iocmd.size = 0;
4001 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004002 iocmd.bus = vdevice->bus_id;
4003 iocmd.id = vdevice->target_id;
4004 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004006 if ((vdevice->vtarget->type & TYPE_DISK) &&
4007 (vdevice->configured_lun))
4008 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009}
4010
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07004011/* Search IOC page 3 to determine if this is hidden physical disk
4012 */
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07004013static int
4014mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
4015{
4016 int i;
4017
4018 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
4019 return 0;
4020
4021 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
4022 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
4023 return 1;
4024 }
4025
4026 return 0;
4027}
4028
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
4030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4031/**
4032 * mptscsih_domainValidation - Top level handler for domain validation.
4033 * @hd: Pointer to MPT_SCSI_HOST structure.
4034 *
4035 * Uses the ISR, but with special processing.
4036 * Called from schedule, should not be in interrupt mode.
4037 * While thread alive, do dv for all devices needing dv
4038 *
4039 * Return: None.
4040 */
4041static void
4042mptscsih_domainValidation(void *arg)
4043{
4044 MPT_SCSI_HOST *hd;
4045 MPT_ADAPTER *ioc;
4046 unsigned long flags;
4047 int id, maxid, dvStatus, did;
4048 int ii, isPhysDisk;
4049
4050 spin_lock_irqsave(&dvtaskQ_lock, flags);
4051 dvtaskQ_active = 1;
4052 if (dvtaskQ_release) {
4053 dvtaskQ_active = 0;
4054 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4055 return;
4056 }
4057 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4058
4059 /* For this ioc, loop through all devices and do dv to each device.
4060 * When complete with this ioc, search through the ioc list, and
4061 * for each scsi ioc found, do dv for all devices. Exit when no
4062 * device needs dv.
4063 */
4064 did = 1;
4065 while (did) {
4066 did = 0;
4067 list_for_each_entry(ioc, &ioc_list, list) {
4068 spin_lock_irqsave(&dvtaskQ_lock, flags);
4069 if (dvtaskQ_release) {
4070 dvtaskQ_active = 0;
4071 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4072 return;
4073 }
4074 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4075
4076 msleep(250);
4077
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004078 /* DV only to SPI adapters */
4079 if (ioc->bus_type != SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 continue;
4081
4082 /* Make sure everything looks ok */
4083 if (ioc->sh == NULL)
4084 continue;
4085
4086 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4087 if (hd == NULL)
4088 continue;
4089
4090 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4091 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004092 if (ioc->raid_data.pIocPg3) {
4093 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4094 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
4096 while (numPDisk) {
4097 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4098 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4099
4100 pPDisk++;
4101 numPDisk--;
4102 }
4103 }
4104 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4105 }
4106
4107 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4108
4109 for (id = 0; id < maxid; id++) {
4110 spin_lock_irqsave(&dvtaskQ_lock, flags);
4111 if (dvtaskQ_release) {
4112 dvtaskQ_active = 0;
4113 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4114 return;
4115 }
4116 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4117 dvStatus = hd->ioc->spi_data.dvStatus[id];
4118
4119 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4120 did++;
4121 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4122 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4123
4124 msleep(250);
4125
4126 /* If hidden phys disk, block IO's to all
4127 * raid volumes
4128 * else, process normally
4129 */
4130 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4131 if (isPhysDisk) {
4132 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004133 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4135 }
4136 }
4137 }
4138
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004139 if(mpt_alt_ioc_wait(hd->ioc)!=0) {
4140 ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
4141 hd->ioc->name));
4142 continue;
4143 }
4144
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 if (mptscsih_doDv(hd, 0, id) == 1) {
4146 /* Untagged device was busy, try again
4147 */
4148 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4149 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4150 } else {
4151 /* DV is complete. Clear flags.
4152 */
4153 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4154 }
4155
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004156 spin_lock(&hd->ioc->initializing_hba_lock);
4157 hd->ioc->initializing_hba_lock_flag=0;
4158 spin_unlock(&hd->ioc->initializing_hba_lock);
4159
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 if (isPhysDisk) {
4161 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004162 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4164 }
4165 }
4166 }
4167
4168 if (hd->ioc->spi_data.noQas)
4169 mptscsih_qas_check(hd, id);
4170 }
4171 }
4172 }
4173 }
4174
4175 spin_lock_irqsave(&dvtaskQ_lock, flags);
4176 dvtaskQ_active = 0;
4177 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4178
4179 return;
4180}
4181
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182/* Write SDP1 if no QAS has been enabled
4183 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004184static void
4185mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004187 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 int ii;
4189
4190 if (hd->Targets == NULL)
4191 return;
4192
4193 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4194 if (ii == id)
4195 continue;
4196
4197 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4198 continue;
4199
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004200 vtarget = hd->Targets[ii];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004202 if ((vtarget != NULL) && (!vtarget->raidVolume)) {
4203 if ((vtarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4204 vtarget->negoFlags |= hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4206 mptscsih_writeSDP1(hd, 0, ii, 0);
4207 }
4208 } else {
4209 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4210 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4211 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4212 }
4213 }
4214 }
4215 return;
4216}
4217
4218
4219
4220#define MPT_GET_NVRAM_VALS 0x01
4221#define MPT_UPDATE_MAX 0x02
4222#define MPT_SET_MAX 0x04
4223#define MPT_SET_MIN 0x08
4224#define MPT_FALLBACK 0x10
4225#define MPT_SAVE 0x20
4226
4227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4228/**
4229 * mptscsih_doDv - Perform domain validation to a target.
4230 * @hd: Pointer to MPT_SCSI_HOST structure.
4231 * @portnum: IOC port number.
4232 * @target: Physical ID of this target
4233 *
4234 * Uses the ISR, but with special processing.
4235 * MUST be single-threaded.
4236 * Test will exit if target is at async & narrow.
4237 *
4238 * Return: None.
4239 */
4240static int
4241mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4242{
4243 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004244 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 SCSIDevicePage1_t *pcfg1Data;
4246 SCSIDevicePage0_t *pcfg0Data;
4247 u8 *pbuf1;
4248 u8 *pbuf2;
4249 u8 *pDvBuf;
4250 dma_addr_t dvbuf_dma = -1;
4251 dma_addr_t buf1_dma = -1;
4252 dma_addr_t buf2_dma = -1;
4253 dma_addr_t cfg1_dma_addr = -1;
4254 dma_addr_t cfg0_dma_addr = -1;
4255 ConfigPageHeader_t header1;
4256 ConfigPageHeader_t header0;
4257 DVPARAMETERS dv;
4258 INTERNAL_CMD iocmd;
4259 CONFIGPARMS cfg;
4260 int dv_alloc = 0;
4261 int rc, sz = 0;
4262 int bufsize = 0;
4263 int dataBufSize = 0;
4264 int echoBufSize = 0;
4265 int notDone;
4266 int patt;
4267 int repeat;
4268 int retcode = 0;
4269 int nfactor = MPT_ULTRA320;
4270 char firstPass = 1;
4271 char doFallback = 0;
4272 char readPage0;
4273 char bus, lun;
4274 char inq0 = 0;
4275
4276 if (ioc->spi_data.sdp1length == 0)
4277 return 0;
4278
4279 if (ioc->spi_data.sdp0length == 0)
4280 return 0;
4281
4282 /* If multiple buses are used, require that the initiator
4283 * id be the same on all buses.
4284 */
4285 if (id == ioc->pfacts[0].PortSCSIID)
4286 return 0;
4287
4288 lun = 0;
4289 bus = (u8) bus_number;
4290 ddvtprintk((MYIOC_s_NOTE_FMT
4291 "DV started: bus=%d, id=%d dv @ %p\n",
4292 ioc->name, bus, id, &dv));
4293
4294 /* Prep DV structure
4295 */
4296 memset (&dv, 0, sizeof(DVPARAMETERS));
4297 dv.id = id;
4298
4299 /* Populate tmax with the current maximum
4300 * transfer parameters for this target.
4301 * Exit if narrow and async.
4302 */
4303 dv.cmd = MPT_GET_NVRAM_VALS;
4304 mptscsih_dv_parms(hd, &dv, NULL);
4305
4306 /* Prep SCSI IO structure
4307 */
4308 iocmd.id = id;
4309 iocmd.bus = bus;
4310 iocmd.lun = lun;
4311 iocmd.flags = 0;
4312 iocmd.physDiskNum = -1;
4313 iocmd.rsvd = iocmd.rsvd2 = 0;
4314
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004315 vtarget = hd->Targets[id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
4317 /* Use tagged commands if possible.
4318 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004319 if (vtarget) {
4320 if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4322 else {
4323 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4324 return 0;
4325
4326 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4327 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4328 return 0;
4329 }
4330 }
4331
4332 /* Prep cfg structure
4333 */
4334 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004335 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
4337 /* Prep SDP0 header
4338 */
4339 header0.PageVersion = ioc->spi_data.sdp0version;
4340 header0.PageLength = ioc->spi_data.sdp0length;
4341 header0.PageNumber = 0;
4342 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4343
4344 /* Prep SDP1 header
4345 */
4346 header1.PageVersion = ioc->spi_data.sdp1version;
4347 header1.PageLength = ioc->spi_data.sdp1length;
4348 header1.PageNumber = 1;
4349 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4350
4351 if (header0.PageLength & 1)
4352 dv_alloc = (header0.PageLength * 4) + 4;
4353
4354 dv_alloc += (2048 + (header1.PageLength * 4));
4355
4356 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4357 if (pDvBuf == NULL)
4358 return 0;
4359
4360 sz = 0;
4361 pbuf1 = (u8 *)pDvBuf;
4362 buf1_dma = dvbuf_dma;
4363 sz +=1024;
4364
4365 pbuf2 = (u8 *) (pDvBuf + sz);
4366 buf2_dma = dvbuf_dma + sz;
4367 sz +=1024;
4368
4369 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4370 cfg0_dma_addr = dvbuf_dma + sz;
4371 sz += header0.PageLength * 4;
4372
4373 /* 8-byte alignment
4374 */
4375 if (header0.PageLength & 1)
4376 sz += 4;
4377
4378 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4379 cfg1_dma_addr = dvbuf_dma + sz;
4380
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004381 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 */
4383 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004384 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4386 /* Set the factor from nvram */
4387 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4388 if (nfactor < pspi_data->minSyncFactor )
4389 nfactor = pspi_data->minSyncFactor;
4390
4391 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4392 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4393
4394 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4395 ioc->name, bus, id, lun));
4396
4397 dv.cmd = MPT_SET_MAX;
4398 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004399 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400
4401 /* Save the final negotiated settings to
4402 * SCSI device page 1.
4403 */
4404 cfg.physAddr = cfg1_dma_addr;
4405 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4406 cfg.dir = 1;
4407 mpt_config(hd->ioc, &cfg);
4408 goto target_done;
4409 }
4410 }
4411 }
4412
4413 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004414 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 /* Search IOC page 3 for matching id
4416 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004417 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4418 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
4420 while (numPDisk) {
4421 if (pPDisk->PhysDiskID == id) {
4422 /* match */
4423 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4424 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4425
4426 /* Quiesce the IM
4427 */
4428 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4429 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4430 goto target_done;
4431 }
4432 break;
4433 }
4434 pPDisk++;
4435 numPDisk--;
4436 }
4437 }
4438
4439 /* RAID Volume ID's may double for a physical device. If RAID but
4440 * not a physical ID as well, skip DV.
4441 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004442 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 goto target_done;
4444
4445
4446 /* Basic Test.
4447 * Async & Narrow - Inquiry
4448 * Async & Narrow - Inquiry
4449 * Maximum transfer rate - Inquiry
4450 * Compare buffers:
4451 * If compare, test complete.
4452 * If miscompare and first pass, repeat
4453 * If miscompare and not first pass, fall back and repeat
4454 */
4455 hd->pLocal = NULL;
4456 readPage0 = 0;
4457 sz = SCSI_MAX_INQUIRY_BYTES;
4458 rc = MPT_SCANDV_GOOD;
4459 while (1) {
4460 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4461 retcode = 0;
4462 dv.cmd = MPT_SET_MIN;
4463 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4464
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004465 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 cfg.physAddr = cfg1_dma_addr;
4467 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4468 cfg.dir = 1;
4469 if (mpt_config(hd->ioc, &cfg) != 0)
4470 goto target_done;
4471
4472 /* Wide - narrow - wide workaround case
4473 */
4474 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4475 /* Send an untagged command to reset disk Qs corrupted
4476 * when a parity error occurs on a Request Sense.
4477 */
4478 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4479 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4480 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4481
4482 iocmd.cmd = REQUEST_SENSE;
4483 iocmd.data_dma = buf1_dma;
4484 iocmd.data = pbuf1;
4485 iocmd.size = 0x12;
4486 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4487 goto target_done;
4488 else {
4489 if (hd->pLocal == NULL)
4490 goto target_done;
4491 rc = hd->pLocal->completion;
4492 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4493 dv.max.width = 0;
4494 doFallback = 0;
4495 } else
4496 goto target_done;
4497 }
4498 } else
4499 goto target_done;
4500 }
4501
4502 iocmd.cmd = INQUIRY;
4503 iocmd.data_dma = buf1_dma;
4504 iocmd.data = pbuf1;
4505 iocmd.size = sz;
4506 memset(pbuf1, 0x00, sz);
4507 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4508 goto target_done;
4509 else {
4510 if (hd->pLocal == NULL)
4511 goto target_done;
4512 rc = hd->pLocal->completion;
4513 if (rc == MPT_SCANDV_GOOD) {
4514 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4515 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4516 retcode = 1;
4517 else
4518 retcode = 0;
4519
4520 goto target_done;
4521 }
4522 } else if (rc == MPT_SCANDV_SENSE) {
4523 ;
4524 } else {
4525 /* If first command doesn't complete
4526 * with a good status or with a check condition,
4527 * exit.
4528 */
4529 goto target_done;
4530 }
4531 }
4532
4533 /* Reset the size for disks
4534 */
4535 inq0 = (*pbuf1) & 0x1F;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004536 if ((inq0 == 0) && vtarget && !vtarget->raidVolume) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 sz = 0x40;
4538 iocmd.size = sz;
4539 }
4540
4541 /* Another GEM workaround. Check peripheral device type,
4542 * if PROCESSOR, quit DV.
4543 */
4544 if (inq0 == TYPE_PROCESSOR) {
4545 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004546 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 lun,
4548 pbuf1,
4549 sz);
4550 goto target_done;
4551 }
4552
4553 if (inq0 > 0x08)
4554 goto target_done;
4555
4556 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4557 goto target_done;
4558
4559 if (sz == 0x40) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004560 if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A)
4561 && (vtarget->minSyncFactor > 0x09)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 if ((pbuf1[56] & 0x04) == 0)
4563 ;
4564 else if ((pbuf1[56] & 0x01) == 1) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004565 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4567 } else {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004568 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4570 }
4571
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004572 dv.max.factor = vtarget->minSyncFactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573
4574 if ((pbuf1[56] & 0x02) == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004575 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004577 ddvprintk((MYIOC_s_NOTE_FMT
4578 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 ioc->name, id, pbuf1[56]));
4580 }
4581 }
4582 }
4583
4584 if (doFallback)
4585 dv.cmd = MPT_FALLBACK;
4586 else
4587 dv.cmd = MPT_SET_MAX;
4588
4589 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4590 if (mpt_config(hd->ioc, &cfg) != 0)
4591 goto target_done;
4592
4593 if ((!dv.now.width) && (!dv.now.offset))
4594 goto target_done;
4595
4596 iocmd.cmd = INQUIRY;
4597 iocmd.data_dma = buf2_dma;
4598 iocmd.data = pbuf2;
4599 iocmd.size = sz;
4600 memset(pbuf2, 0x00, sz);
4601 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4602 goto target_done;
4603 else if (hd->pLocal == NULL)
4604 goto target_done;
4605 else {
4606 /* Save the return code.
4607 * If this is the first pass,
4608 * read SCSI Device Page 0
4609 * and update the target max parameters.
4610 */
4611 rc = hd->pLocal->completion;
4612 doFallback = 0;
4613 if (rc == MPT_SCANDV_GOOD) {
4614 if (!readPage0) {
4615 u32 sdp0_info;
4616 u32 sdp0_nego;
4617
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004618 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 cfg.physAddr = cfg0_dma_addr;
4620 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4621 cfg.dir = 0;
4622
4623 if (mpt_config(hd->ioc, &cfg) != 0)
4624 goto target_done;
4625
4626 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4627 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4628
4629 /* Quantum and Fujitsu workarounds.
4630 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4631 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4632 * Resetart with a request for U160.
4633 */
4634 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4635 doFallback = 1;
4636 } else {
4637 dv.cmd = MPT_UPDATE_MAX;
4638 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4639 /* Update the SCSI device page 1 area
4640 */
4641 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4642 readPage0 = 1;
4643 }
4644 }
4645
4646 /* Quantum workaround. Restart this test will the fallback
4647 * flag set.
4648 */
4649 if (doFallback == 0) {
4650 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4651 if (!firstPass)
4652 doFallback = 1;
4653 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004654 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4656 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4657 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004658 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 lun,
4660 pbuf1,
4661 sz);
4662 break; /* test complete */
4663 }
4664 }
4665
4666
4667 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4668 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004669 else if ((rc == MPT_SCANDV_DID_RESET) ||
4670 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 (rc == MPT_SCANDV_FALLBACK))
4672 doFallback = 1; /* set fallback flag */
4673 else
4674 goto target_done;
4675
4676 firstPass = 0;
4677 }
4678 }
4679 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4680
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004681 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 goto target_done;
4683
4684 inq0 = (*pbuf1) & 0x1F;
4685
4686 /* Continue only for disks
4687 */
4688 if (inq0 != 0)
4689 goto target_done;
4690
4691 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4692 goto target_done;
4693
4694 /* Start the Enhanced Test.
4695 * 0) issue TUR to clear out check conditions
4696 * 1) read capacity of echo (regular) buffer
4697 * 2) reserve device
4698 * 3) do write-read-compare data pattern test
4699 * 4) release
4700 * 5) update nego parms to target struct
4701 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004702 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 cfg.physAddr = cfg1_dma_addr;
4704 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4705 cfg.dir = 1;
4706
4707 iocmd.cmd = TEST_UNIT_READY;
4708 iocmd.data_dma = -1;
4709 iocmd.data = NULL;
4710 iocmd.size = 0;
4711 notDone = 1;
4712 while (notDone) {
4713 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4714 goto target_done;
4715
4716 if (hd->pLocal == NULL)
4717 goto target_done;
4718
4719 rc = hd->pLocal->completion;
4720 if (rc == MPT_SCANDV_GOOD)
4721 notDone = 0;
4722 else if (rc == MPT_SCANDV_SENSE) {
4723 u8 skey = hd->pLocal->sense[2] & 0x0F;
4724 u8 asc = hd->pLocal->sense[12];
4725 u8 ascq = hd->pLocal->sense[13];
4726 ddvprintk((MYIOC_s_INFO_FMT
4727 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4728 ioc->name, skey, asc, ascq));
4729
4730 if (skey == UNIT_ATTENTION)
4731 notDone++; /* repeat */
4732 else if ((skey == NOT_READY) &&
4733 (asc == 0x04)&&(ascq == 0x01)) {
4734 /* wait then repeat */
4735 mdelay (2000);
4736 notDone++;
4737 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4738 /* no medium, try read test anyway */
4739 notDone = 0;
4740 } else {
4741 /* All other errors are fatal.
4742 */
4743 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4744 ioc->name));
4745 goto target_done;
4746 }
4747 } else
4748 goto target_done;
4749 }
4750
4751 iocmd.cmd = READ_BUFFER;
4752 iocmd.data_dma = buf1_dma;
4753 iocmd.data = pbuf1;
4754 iocmd.size = 4;
4755 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4756
4757 dataBufSize = 0;
4758 echoBufSize = 0;
4759 for (patt = 0; patt < 2; patt++) {
4760 if (patt == 0)
4761 iocmd.flags |= MPT_ICFLAG_ECHO;
4762 else
4763 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4764
4765 notDone = 1;
4766 while (notDone) {
4767 bufsize = 0;
4768
4769 /* If not ready after 8 trials,
4770 * give up on this device.
4771 */
4772 if (notDone > 8)
4773 goto target_done;
4774
4775 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4776 goto target_done;
4777 else if (hd->pLocal == NULL)
4778 goto target_done;
4779 else {
4780 rc = hd->pLocal->completion;
4781 ddvprintk(("ReadBuffer Comp Code %d", rc));
4782 ddvprintk((" buff: %0x %0x %0x %0x\n",
4783 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4784
4785 if (rc == MPT_SCANDV_GOOD) {
4786 notDone = 0;
4787 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4788 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004789 if (pbuf1[0] & 0x01)
4790 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 } else {
4792 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4793 }
4794 } else if (rc == MPT_SCANDV_SENSE) {
4795 u8 skey = hd->pLocal->sense[2] & 0x0F;
4796 u8 asc = hd->pLocal->sense[12];
4797 u8 ascq = hd->pLocal->sense[13];
4798 ddvprintk((MYIOC_s_INFO_FMT
4799 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4800 ioc->name, skey, asc, ascq));
4801 if (skey == ILLEGAL_REQUEST) {
4802 notDone = 0;
4803 } else if (skey == UNIT_ATTENTION) {
4804 notDone++; /* repeat */
4805 } else if ((skey == NOT_READY) &&
4806 (asc == 0x04)&&(ascq == 0x01)) {
4807 /* wait then repeat */
4808 mdelay (2000);
4809 notDone++;
4810 } else {
4811 /* All other errors are fatal.
4812 */
4813 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4814 ioc->name));
4815 goto target_done;
4816 }
4817 } else {
4818 /* All other errors are fatal
4819 */
4820 goto target_done;
4821 }
4822 }
4823 }
4824
4825 if (iocmd.flags & MPT_ICFLAG_ECHO)
4826 echoBufSize = bufsize;
4827 else
4828 dataBufSize = bufsize;
4829 }
4830 sz = 0;
4831 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4832
4833 /* Use echo buffers if possible,
4834 * Exit if both buffers are 0.
4835 */
4836 if (echoBufSize > 0) {
4837 iocmd.flags |= MPT_ICFLAG_ECHO;
4838 if (dataBufSize > 0)
4839 bufsize = min(echoBufSize, dataBufSize);
4840 else
4841 bufsize = echoBufSize;
4842 } else if (dataBufSize == 0)
4843 goto target_done;
4844
4845 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4846 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4847
4848 /* Data buffers for write-read-compare test max 1K.
4849 */
4850 sz = min(bufsize, 1024);
4851
4852 /* --- loop ----
4853 * On first pass, always issue a reserve.
4854 * On additional loops, only if a reset has occurred.
4855 * iocmd.flags indicates if echo or regular buffer
4856 */
4857 for (patt = 0; patt < 4; patt++) {
4858 ddvprintk(("Pattern %d\n", patt));
4859 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4860 iocmd.cmd = TEST_UNIT_READY;
4861 iocmd.data_dma = -1;
4862 iocmd.data = NULL;
4863 iocmd.size = 0;
4864 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4865 goto target_done;
4866
4867 iocmd.cmd = RELEASE;
4868 iocmd.data_dma = -1;
4869 iocmd.data = NULL;
4870 iocmd.size = 0;
4871 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4872 goto target_done;
4873 else if (hd->pLocal == NULL)
4874 goto target_done;
4875 else {
4876 rc = hd->pLocal->completion;
4877 ddvprintk(("Release rc %d\n", rc));
4878 if (rc == MPT_SCANDV_GOOD)
4879 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4880 else
4881 goto target_done;
4882 }
4883 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4884 }
4885 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4886
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004887 if (iocmd.flags & MPT_ICFLAG_EBOS)
4888 goto skip_Reserve;
4889
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 repeat = 5;
4891 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4892 iocmd.cmd = RESERVE;
4893 iocmd.data_dma = -1;
4894 iocmd.data = NULL;
4895 iocmd.size = 0;
4896 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4897 goto target_done;
4898 else if (hd->pLocal == NULL)
4899 goto target_done;
4900 else {
4901 rc = hd->pLocal->completion;
4902 if (rc == MPT_SCANDV_GOOD) {
4903 iocmd.flags |= MPT_ICFLAG_RESERVED;
4904 } else if (rc == MPT_SCANDV_SENSE) {
4905 /* Wait if coming ready
4906 */
4907 u8 skey = hd->pLocal->sense[2] & 0x0F;
4908 u8 asc = hd->pLocal->sense[12];
4909 u8 ascq = hd->pLocal->sense[13];
4910 ddvprintk((MYIOC_s_INFO_FMT
4911 "DV: Reserve Failed: ", ioc->name));
4912 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4913 skey, asc, ascq));
4914
4915 if ((skey == NOT_READY) && (asc == 0x04)&&
4916 (ascq == 0x01)) {
4917 /* wait then repeat */
4918 mdelay (2000);
4919 notDone++;
4920 } else {
4921 ddvprintk((MYIOC_s_INFO_FMT
4922 "DV: Reserved Failed.", ioc->name));
4923 goto target_done;
4924 }
4925 } else {
4926 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4927 ioc->name));
4928 goto target_done;
4929 }
4930 }
4931 }
4932
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004933skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4935 iocmd.cmd = WRITE_BUFFER;
4936 iocmd.data_dma = buf1_dma;
4937 iocmd.data = pbuf1;
4938 iocmd.size = sz;
4939 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4940 goto target_done;
4941 else if (hd->pLocal == NULL)
4942 goto target_done;
4943 else {
4944 rc = hd->pLocal->completion;
4945 if (rc == MPT_SCANDV_GOOD)
4946 ; /* Issue read buffer */
4947 else if (rc == MPT_SCANDV_DID_RESET) {
4948 /* If using echo buffers, reset to data buffers.
4949 * Else do Fallback and restart
4950 * this test (re-issue reserve
4951 * because of bus reset).
4952 */
4953 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4954 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4955 } else {
4956 dv.cmd = MPT_FALLBACK;
4957 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4958
4959 if (mpt_config(hd->ioc, &cfg) != 0)
4960 goto target_done;
4961
4962 if ((!dv.now.width) && (!dv.now.offset))
4963 goto target_done;
4964 }
4965
4966 iocmd.flags |= MPT_ICFLAG_DID_RESET;
4967 patt = -1;
4968 continue;
4969 } else if (rc == MPT_SCANDV_SENSE) {
4970 /* Restart data test if UA, else quit.
4971 */
4972 u8 skey = hd->pLocal->sense[2] & 0x0F;
4973 ddvprintk((MYIOC_s_INFO_FMT
4974 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
4975 hd->pLocal->sense[12], hd->pLocal->sense[13]));
4976 if (skey == UNIT_ATTENTION) {
4977 patt = -1;
4978 continue;
4979 } else if (skey == ILLEGAL_REQUEST) {
4980 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4981 if (dataBufSize >= bufsize) {
4982 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4983 patt = -1;
4984 continue;
4985 }
4986 }
4987 goto target_done;
4988 }
4989 else
4990 goto target_done;
4991 } else {
4992 /* fatal error */
4993 goto target_done;
4994 }
4995 }
4996
4997 iocmd.cmd = READ_BUFFER;
4998 iocmd.data_dma = buf2_dma;
4999 iocmd.data = pbuf2;
5000 iocmd.size = sz;
5001 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5002 goto target_done;
5003 else if (hd->pLocal == NULL)
5004 goto target_done;
5005 else {
5006 rc = hd->pLocal->completion;
5007 if (rc == MPT_SCANDV_GOOD) {
5008 /* If buffers compare,
5009 * go to next pattern,
5010 * else, do a fallback and restart
5011 * data transfer test.
5012 */
5013 if (memcmp (pbuf1, pbuf2, sz) == 0) {
5014 ; /* goto next pattern */
5015 } else {
5016 /* Miscompare with Echo buffer, go to data buffer,
5017 * if that buffer exists.
5018 * Miscompare with Data buffer, check first 4 bytes,
5019 * some devices return capacity. Exit in this case.
5020 */
5021 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5022 if (dataBufSize >= bufsize)
5023 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5024 else
5025 goto target_done;
5026 } else {
5027 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
5028 /* Argh. Device returning wrong data.
5029 * Quit DV for this device.
5030 */
5031 goto target_done;
5032 }
5033
5034 /* Had an actual miscompare. Slow down.*/
5035 dv.cmd = MPT_FALLBACK;
5036 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5037
5038 if (mpt_config(hd->ioc, &cfg) != 0)
5039 goto target_done;
5040
5041 if ((!dv.now.width) && (!dv.now.offset))
5042 goto target_done;
5043 }
5044
5045 patt = -1;
5046 continue;
5047 }
5048 } else if (rc == MPT_SCANDV_DID_RESET) {
5049 /* Do Fallback and restart
5050 * this test (re-issue reserve
5051 * because of bus reset).
5052 */
5053 dv.cmd = MPT_FALLBACK;
5054 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5055
5056 if (mpt_config(hd->ioc, &cfg) != 0)
5057 goto target_done;
5058
5059 if ((!dv.now.width) && (!dv.now.offset))
5060 goto target_done;
5061
5062 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5063 patt = -1;
5064 continue;
5065 } else if (rc == MPT_SCANDV_SENSE) {
5066 /* Restart data test if UA, else quit.
5067 */
5068 u8 skey = hd->pLocal->sense[2] & 0x0F;
5069 ddvprintk((MYIOC_s_INFO_FMT
5070 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5071 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5072 if (skey == UNIT_ATTENTION) {
5073 patt = -1;
5074 continue;
5075 }
5076 else
5077 goto target_done;
5078 } else {
5079 /* fatal error */
5080 goto target_done;
5081 }
5082 }
5083
5084 } /* --- end of patt loop ---- */
5085
5086target_done:
5087 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5088 iocmd.cmd = RELEASE;
5089 iocmd.data_dma = -1;
5090 iocmd.data = NULL;
5091 iocmd.size = 0;
5092 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5093 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5094 ioc->name, id);
5095 else if (hd->pLocal) {
5096 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5097 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5098 } else {
5099 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5100 ioc->name, id);
5101 }
5102 }
5103
5104
5105 /* Set if cfg1_dma_addr contents is valid
5106 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005107 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 /* If disk, not U320, disable QAS
5109 */
5110 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5111 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005112 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5114 }
5115
5116 dv.cmd = MPT_SAVE;
5117 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5118
5119 /* Double writes to SDP1 can cause problems,
5120 * skip save of the final negotiated settings to
5121 * SCSI device page 1.
5122 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005123 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 cfg.physAddr = cfg1_dma_addr;
5125 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5126 cfg.dir = 1;
5127 mpt_config(hd->ioc, &cfg);
5128 */
5129 }
5130
5131 /* If this is a RAID Passthrough, enable internal IOs
5132 */
5133 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5134 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5135 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5136 }
5137
5138 /* Done with the DV scan of the current target
5139 */
5140 if (pDvBuf)
5141 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5142
5143 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5144 ioc->name, id));
5145
5146 return retcode;
5147}
5148
5149/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5150/* mptscsih_dv_parms - perform a variety of operations on the
5151 * parameters used for negotiation.
5152 * @hd: Pointer to a SCSI host.
5153 * @dv: Pointer to a structure that contains the maximum and current
5154 * negotiated parameters.
5155 */
5156static void
5157mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5158{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005159 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 SCSIDevicePage0_t *pPage0;
5161 SCSIDevicePage1_t *pPage1;
5162 int val = 0, data, configuration;
5163 u8 width = 0;
5164 u8 offset = 0;
5165 u8 factor = 0;
5166 u8 negoFlags = 0;
5167 u8 cmd = dv->cmd;
5168 u8 id = dv->id;
5169
5170 switch (cmd) {
5171 case MPT_GET_NVRAM_VALS:
5172 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5173 hd->ioc->name));
5174 /* Get the NVRAM values and save in tmax
5175 * If not an LVD bus, the adapter minSyncFactor has been
5176 * already throttled back.
5177 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005178 negoFlags = hd->ioc->spi_data.noQas;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005179 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume) {
5180 width = vtarget->maxWidth;
5181 offset = vtarget->maxOffset;
5182 factor = vtarget->minSyncFactor;
5183 negoFlags |= vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 } else {
5185 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5186 data = hd->ioc->spi_data.nvram[id];
5187 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5188 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5189 factor = MPT_ASYNC;
5190 else {
5191 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5192 if ((factor == 0) || (factor == MPT_ASYNC)){
5193 factor = MPT_ASYNC;
5194 offset = 0;
5195 }
5196 }
5197 } else {
5198 width = MPT_NARROW;
5199 offset = 0;
5200 factor = MPT_ASYNC;
5201 }
5202
5203 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 if (!width)
5205 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5206
5207 if (!offset)
5208 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5209 }
5210
5211 /* limit by adapter capabilities */
5212 width = min(width, hd->ioc->spi_data.maxBusWidth);
5213 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5214 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5215
5216 /* Check Consistency */
5217 if (offset && (factor < MPT_ULTRA2) && !width)
5218 factor = MPT_ULTRA2;
5219
5220 dv->max.width = width;
5221 dv->max.offset = offset;
5222 dv->max.factor = factor;
5223 dv->max.flags = negoFlags;
5224 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5225 id, width, factor, offset, negoFlags));
5226 break;
5227
5228 case MPT_UPDATE_MAX:
5229 ddvprintk((MYIOC_s_NOTE_FMT
5230 "Updating with SDP0 Data: ", hd->ioc->name));
5231 /* Update tmax values with those from Device Page 0.*/
5232 pPage0 = (SCSIDevicePage0_t *) pPage;
5233 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005234 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5236 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5237 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5238 }
5239
5240 dv->now.width = dv->max.width;
5241 dv->now.offset = dv->max.offset;
5242 dv->now.factor = dv->max.factor;
5243 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5244 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5245 break;
5246
5247 case MPT_SET_MAX:
5248 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5249 hd->ioc->name));
5250 /* Set current to the max values. Update the config page.*/
5251 dv->now.width = dv->max.width;
5252 dv->now.offset = dv->max.offset;
5253 dv->now.factor = dv->max.factor;
5254 dv->now.flags = dv->max.flags;
5255
5256 pPage1 = (SCSIDevicePage1_t *)pPage;
5257 if (pPage1) {
5258 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5259 dv->now.offset, &val, &configuration, dv->now.flags);
5260 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5261 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005262 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005264 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 }
5266
Christoph Hellwig637fa992005-08-18 16:25:44 +02005267 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5269 break;
5270
5271 case MPT_SET_MIN:
5272 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5273 hd->ioc->name));
5274 /* Set page to asynchronous and narrow
5275 * Do not update now, breaks fallback routine. */
5276 width = MPT_NARROW;
5277 offset = 0;
5278 factor = MPT_ASYNC;
5279 negoFlags = dv->max.flags;
5280
5281 pPage1 = (SCSIDevicePage1_t *)pPage;
5282 if (pPage1) {
5283 mptscsih_setDevicePage1Flags (width, factor,
5284 offset, &val, &configuration, negoFlags);
5285 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5286 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005287 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005289 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 }
5291 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5292 id, width, factor, offset, val, configuration, negoFlags));
5293 break;
5294
5295 case MPT_FALLBACK:
5296 ddvprintk((MYIOC_s_NOTE_FMT
5297 "Fallback: Start: offset %d, factor %x, width %d \n",
5298 hd->ioc->name, dv->now.offset,
5299 dv->now.factor, dv->now.width));
5300 width = dv->now.width;
5301 offset = dv->now.offset;
5302 factor = dv->now.factor;
5303 if ((offset) && (dv->max.width)) {
5304 if (factor < MPT_ULTRA160)
5305 factor = MPT_ULTRA160;
5306 else if (factor < MPT_ULTRA2) {
5307 factor = MPT_ULTRA2;
5308 width = MPT_WIDE;
5309 } else if ((factor == MPT_ULTRA2) && width) {
5310 factor = MPT_ULTRA2;
5311 width = MPT_NARROW;
5312 } else if (factor < MPT_ULTRA) {
5313 factor = MPT_ULTRA;
5314 width = MPT_WIDE;
5315 } else if ((factor == MPT_ULTRA) && width) {
5316 width = MPT_NARROW;
5317 } else if (factor < MPT_FAST) {
5318 factor = MPT_FAST;
5319 width = MPT_WIDE;
5320 } else if ((factor == MPT_FAST) && width) {
5321 factor = MPT_FAST;
5322 width = MPT_NARROW;
5323 } else if (factor < MPT_SCSI) {
5324 factor = MPT_SCSI;
5325 width = MPT_WIDE;
5326 } else if ((factor == MPT_SCSI) && width) {
5327 factor = MPT_SCSI;
5328 width = MPT_NARROW;
5329 } else {
5330 factor = MPT_ASYNC;
5331 offset = 0;
5332 }
5333
5334 } else if (offset) {
5335 width = MPT_NARROW;
5336 if (factor < MPT_ULTRA)
5337 factor = MPT_ULTRA;
5338 else if (factor < MPT_FAST)
5339 factor = MPT_FAST;
5340 else if (factor < MPT_SCSI)
5341 factor = MPT_SCSI;
5342 else {
5343 factor = MPT_ASYNC;
5344 offset = 0;
5345 }
5346
5347 } else {
5348 width = MPT_NARROW;
5349 factor = MPT_ASYNC;
5350 }
5351 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5352 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5353
5354 dv->now.width = width;
5355 dv->now.offset = offset;
5356 dv->now.factor = factor;
5357 dv->now.flags = dv->max.flags;
5358
5359 pPage1 = (SCSIDevicePage1_t *)pPage;
5360 if (pPage1) {
5361 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5362 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005363 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 id, width, offset, factor, dv->now.flags, val, configuration));
5365
Christoph Hellwig637fa992005-08-18 16:25:44 +02005366 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005368 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 }
5370
5371 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5372 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5373 break;
5374
5375 case MPT_SAVE:
5376 ddvprintk((MYIOC_s_NOTE_FMT
5377 "Saving to Target structure: ", hd->ioc->name));
5378 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5379 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5380
5381 /* Save these values to target structures
5382 * or overwrite nvram (phys disks only).
5383 */
5384
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005385 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume ) {
5386 vtarget->maxWidth = dv->now.width;
5387 vtarget->maxOffset = dv->now.offset;
5388 vtarget->minSyncFactor = dv->now.factor;
5389 vtarget->negoFlags = dv->now.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 } else {
5391 /* Preserv all flags, use
5392 * read-modify-write algorithm
5393 */
5394 if (hd->ioc->spi_data.nvram) {
5395 data = hd->ioc->spi_data.nvram[id];
5396
5397 if (dv->now.width)
5398 data &= ~MPT_NVRAM_WIDE_DISABLE;
5399 else
5400 data |= MPT_NVRAM_WIDE_DISABLE;
5401
5402 if (!dv->now.offset)
5403 factor = MPT_ASYNC;
5404
5405 data &= ~MPT_NVRAM_SYNC_MASK;
5406 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5407
5408 hd->ioc->spi_data.nvram[id] = data;
5409 }
5410 }
5411 break;
5412 }
5413}
5414
5415/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5416/* mptscsih_fillbuf - fill a buffer with a special data pattern
5417 * cleanup. For bus scan only.
5418 *
5419 * @buffer: Pointer to data buffer to be filled.
5420 * @size: Number of bytes to fill
5421 * @index: Pattern index
5422 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5423 */
5424static void
5425mptscsih_fillbuf(char *buffer, int size, int index, int width)
5426{
5427 char *ptr = buffer;
5428 int ii;
5429 char byte;
5430 short val;
5431
5432 switch (index) {
5433 case 0:
5434
5435 if (width) {
5436 /* Pattern: 0000 FFFF 0000 FFFF
5437 */
5438 for (ii=0; ii < size; ii++, ptr++) {
5439 if (ii & 0x02)
5440 *ptr = 0xFF;
5441 else
5442 *ptr = 0x00;
5443 }
5444 } else {
5445 /* Pattern: 00 FF 00 FF
5446 */
5447 for (ii=0; ii < size; ii++, ptr++) {
5448 if (ii & 0x01)
5449 *ptr = 0xFF;
5450 else
5451 *ptr = 0x00;
5452 }
5453 }
5454 break;
5455
5456 case 1:
5457 if (width) {
5458 /* Pattern: 5555 AAAA 5555 AAAA 5555
5459 */
5460 for (ii=0; ii < size; ii++, ptr++) {
5461 if (ii & 0x02)
5462 *ptr = 0xAA;
5463 else
5464 *ptr = 0x55;
5465 }
5466 } else {
5467 /* Pattern: 55 AA 55 AA 55
5468 */
5469 for (ii=0; ii < size; ii++, ptr++) {
5470 if (ii & 0x01)
5471 *ptr = 0xAA;
5472 else
5473 *ptr = 0x55;
5474 }
5475 }
5476 break;
5477
5478 case 2:
5479 /* Pattern: 00 01 02 03 04 05
5480 * ... FE FF 00 01..
5481 */
5482 for (ii=0; ii < size; ii++, ptr++)
5483 *ptr = (char) ii;
5484 break;
5485
5486 case 3:
5487 if (width) {
5488 /* Wide Pattern: FFFE 0001 FFFD 0002
5489 * ... 4000 DFFF 8000 EFFF
5490 */
5491 byte = 0;
5492 for (ii=0; ii < size/2; ii++) {
5493 /* Create the base pattern
5494 */
5495 val = (1 << byte);
5496 /* every 64 (0x40) bytes flip the pattern
5497 * since we fill 2 bytes / iteration,
5498 * test for ii = 0x20
5499 */
5500 if (ii & 0x20)
5501 val = ~(val);
5502
5503 if (ii & 0x01) {
5504 *ptr = (char)( (val & 0xFF00) >> 8);
5505 ptr++;
5506 *ptr = (char)(val & 0xFF);
5507 byte++;
5508 byte &= 0x0F;
5509 } else {
5510 val = ~val;
5511 *ptr = (char)( (val & 0xFF00) >> 8);
5512 ptr++;
5513 *ptr = (char)(val & 0xFF);
5514 }
5515
5516 ptr++;
5517 }
5518 } else {
5519 /* Narrow Pattern: FE 01 FD 02 FB 04
5520 * .. 7F 80 01 FE 02 FD ... 80 7F
5521 */
5522 byte = 0;
5523 for (ii=0; ii < size; ii++, ptr++) {
5524 /* Base pattern - first 32 bytes
5525 */
5526 if (ii & 0x01) {
5527 *ptr = (1 << byte);
5528 byte++;
5529 byte &= 0x07;
5530 } else {
5531 *ptr = (char) (~(1 << byte));
5532 }
5533
5534 /* Flip the pattern every 32 bytes
5535 */
5536 if (ii & 0x20)
5537 *ptr = ~(*ptr);
5538 }
5539 }
5540 break;
5541 }
5542}
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005543
5544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5545/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
5546 * Else set the NEED_DV flag after Read Capacity Issued (disks)
5547 * or Mode Sense (cdroms).
5548 *
5549 * Tapes, initTarget will set this flag on completion of Inquiry command.
5550 * Called only if DV_NOT_DONE flag is set
5551 */
5552static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005553mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005554{
5555 MPT_ADAPTER *ioc = hd->ioc;
5556 u8 cmd;
5557 SpiCfgData *pSpi;
5558
5559 ddvtprintk((MYIOC_s_NOTE_FMT
5560 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005561 hd->ioc->name, sc->device->id, sc->device->lun , hd->negoNvram, sc->cmnd[0]));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005562
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005563 if ((sc->device->lun != 0) || (hd->negoNvram != 0))
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005564 return;
5565
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005566 cmd = sc->cmnd[0];
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005567
5568 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
5569 pSpi = &ioc->spi_data;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005570 if ((ioc->raid_data.isRaid & (1 << sc->device->id)) && ioc->raid_data.pIocPg3) {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005571 /* Set NEED_DV for all hidden disks
5572 */
5573 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5574 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5575
5576 while (numPDisk) {
5577 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
5578 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
5579 pPDisk++;
5580 numPDisk--;
5581 }
5582 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005583 pSpi->dvStatus[sc->device->id] |= MPT_SCSICFG_NEED_DV;
5584 ddvtprintk(("NEED_DV set for visible disk id %d\n", sc->device->id));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005585 }
5586}
5587
5588/* mptscsih_raid_set_dv_flags()
5589 *
5590 * New or replaced disk. Set DV flag and schedule DV.
5591 */
5592static void
5593mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
5594{
5595 MPT_ADAPTER *ioc = hd->ioc;
5596 SpiCfgData *pSpi = &ioc->spi_data;
5597 Ioc3PhysDisk_t *pPDisk;
5598 int numPDisk;
5599
5600 if (hd->negoNvram != 0)
5601 return;
5602
5603 ddvtprintk(("DV requested for phys disk id %d\n", id));
5604 if (ioc->raid_data.pIocPg3) {
5605 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5606 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5607 while (numPDisk) {
5608 if (id == pPDisk->PhysDiskNum) {
5609 pSpi->dvStatus[pPDisk->PhysDiskID] =
5610 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
5611 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
5612 ddvtprintk(("NEED_DV set for phys disk id %d\n",
5613 pPDisk->PhysDiskID));
5614 break;
5615 }
5616 pPDisk++;
5617 numPDisk--;
5618 }
5619
5620 if (numPDisk == 0) {
5621 /* The physical disk that needs DV was not found
5622 * in the stored IOC Page 3. The driver must reload
5623 * this page. DV routine will set the NEED_DV flag for
5624 * all phys disks that have DV_NOT_DONE set.
5625 */
5626 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
5627 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
5628 }
5629 }
5630}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5632
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005633EXPORT_SYMBOL(mptscsih_remove);
5634EXPORT_SYMBOL(mptscsih_shutdown);
5635#ifdef CONFIG_PM
5636EXPORT_SYMBOL(mptscsih_suspend);
5637EXPORT_SYMBOL(mptscsih_resume);
5638#endif
5639EXPORT_SYMBOL(mptscsih_proc_info);
5640EXPORT_SYMBOL(mptscsih_info);
5641EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005642EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005643EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005644EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005645EXPORT_SYMBOL(mptscsih_slave_destroy);
5646EXPORT_SYMBOL(mptscsih_slave_configure);
5647EXPORT_SYMBOL(mptscsih_abort);
5648EXPORT_SYMBOL(mptscsih_dev_reset);
5649EXPORT_SYMBOL(mptscsih_bus_reset);
5650EXPORT_SYMBOL(mptscsih_host_reset);
5651EXPORT_SYMBOL(mptscsih_bios_param);
5652EXPORT_SYMBOL(mptscsih_io_done);
5653EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5654EXPORT_SYMBOL(mptscsih_scandv_complete);
5655EXPORT_SYMBOL(mptscsih_event_process);
5656EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005657EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005658EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06005659EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005661/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/