blob: aa9cde807632c0c23981862eaae4f5d4fb7cbdd9 [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
730 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
731 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600732 if (scsi_status == MPI_SCSI_STATUS_BUSY)
733 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
734 else
735 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (scsi_state == 0) {
737 ;
738 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
739 /*
740 * If running against circa 200003dd 909 MPT f/w,
741 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
742 * (QUEUE_FULL) returned from device! --> get 0x0000?128
743 * and with SenseBytes set to 0.
744 */
745 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
746 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
747
748 }
749 else if (scsi_state &
750 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
751 ) {
752 /*
753 * What to do?
754 */
755 sc->result = DID_SOFT_ERROR << 16;
756 }
757 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
758 /* Not real sure here either... */
759 sc->result = DID_RESET << 16;
760 }
761 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
762 /* Device Inq. data indicates that it supports
763 * QTags, but rejects QTag messages.
764 * This command completed OK.
765 *
766 * Not real sure here either so do nothing... */
767 }
768
769 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
770 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
771
772 /* Add handling of:
773 * Reservation Conflict, Busy,
774 * Command Terminated, CHECK
775 */
776 break;
777
778 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
779 sc->result = DID_SOFT_ERROR << 16;
780 break;
781
782 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
783 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
784 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
785 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
786 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
787 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
788 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
789 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
790 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
791 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
792 default:
793 /*
794 * What to do?
795 */
796 sc->result = DID_SOFT_ERROR << 16;
797 break;
798
799 } /* switch(status) */
800
801 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
802 } /* end of address reply case */
803
804 /* Unmap the DMA buffers, if any. */
805 if (sc->use_sg) {
806 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
807 sc->use_sg, sc->sc_data_direction);
808 } else if (sc->request_bufflen) {
809 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
810 sc->request_bufflen, sc->sc_data_direction);
811 }
812
813 hd->ScsiLookup[req_idx] = NULL;
814
815 sc->scsi_done(sc); /* Issue the command callback */
816
817 /* Free Chain buffers */
818 mptscsih_freeChainBuffers(ioc, req_idx);
819 return 1;
820}
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822/*
823 * mptscsih_flush_running_cmds - For each command found, search
824 * Scsi_Host instance taskQ and reply to OS.
825 * Called only if recovering from a FW reload.
826 * @hd: Pointer to a SCSI HOST structure
827 *
828 * Returns: None.
829 *
830 * Must be called while new I/Os are being queued.
831 */
832static void
833mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
834{
835 MPT_ADAPTER *ioc = hd->ioc;
836 struct scsi_cmnd *SCpnt;
837 MPT_FRAME_HDR *mf;
838 int ii;
839 int max = ioc->req_depth;
840
841 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
842 for (ii= 0; ii < max; ii++) {
843 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
844
845 /* Command found.
846 */
847
848 /* Null ScsiLookup index
849 */
850 hd->ScsiLookup[ii] = NULL;
851
852 mf = MPT_INDEX_2_MFPTR(ioc, ii);
853 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
854 mf, SCpnt));
855
856 /* Set status, free OS resources (SG DMA buffers)
857 * Do OS callback
858 * Free driver resources (chain, msg buffers)
859 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400860 if (SCpnt->use_sg) {
861 pci_unmap_sg(ioc->pcidev,
862 (struct scatterlist *) SCpnt->request_buffer,
863 SCpnt->use_sg,
864 SCpnt->sc_data_direction);
865 } else if (SCpnt->request_bufflen) {
866 pci_unmap_single(ioc->pcidev,
867 SCpnt->SCp.dma_handle,
868 SCpnt->request_bufflen,
869 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
871 SCpnt->result = DID_RESET << 16;
872 SCpnt->host_scribble = NULL;
873
874 /* Free Chain buffers */
875 mptscsih_freeChainBuffers(ioc, ii);
876
877 /* Free Message frames */
878 mpt_free_msg_frame(ioc, mf);
879
880 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
881 }
882 }
883
884 return;
885}
886
887/*
888 * mptscsih_search_running_cmds - Delete any commands associated
889 * with the specified target and lun. Function called only
890 * when a lun is disable by mid-layer.
891 * Do NOT access the referenced scsi_cmnd structure or
892 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600893 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700894 * @hd: Pointer to a SCSI HOST structure
895 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 *
897 * Returns: None.
898 *
899 * Called from slave_destroy.
900 */
901static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700902mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 SCSIIORequest_t *mf = NULL;
905 int ii;
906 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600907 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700910 vdevice->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600913 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
916
917 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
918 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
919
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700920 if ((mf->TargetID != ((u8)vdevice->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 continue;
922
923 /* Cleanup
924 */
925 hd->ScsiLookup[ii] = NULL;
926 mptscsih_freeChainBuffers(hd->ioc, ii);
927 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600928 if (sc->use_sg) {
929 pci_unmap_sg(hd->ioc->pcidev,
930 (struct scatterlist *) sc->request_buffer,
931 sc->use_sg,
932 sc->sc_data_direction);
933 } else if (sc->request_bufflen) {
934 pci_unmap_single(hd->ioc->pcidev,
935 sc->SCp.dma_handle,
936 sc->request_bufflen,
937 sc->sc_data_direction);
938 }
939 sc->host_scribble = NULL;
940 sc->result = DID_NO_CONNECT << 16;
941 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 }
943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 return;
945}
946
947/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
950/*
951 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
952 * from a SCSI target device.
953 * @sc: Pointer to scsi_cmnd structure
954 * @pScsiReply: Pointer to SCSIIOReply_t
955 * @pScsiReq: Pointer to original SCSI request
956 *
957 * This routine periodically reports QUEUE_FULL status returned from a
958 * SCSI target device. It reports this to the console via kernel
959 * printk() API call, not more than once every 10 seconds.
960 */
961static void
962mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
963{
964 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400967 if (sc->device == NULL)
968 return;
969 if (sc->device->host == NULL)
970 return;
971 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
972 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400974 if (time - hd->last_queue_full > 10 * HZ) {
975 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
976 hd->ioc->name, 0, sc->device->id, sc->device->lun));
977 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
982/*
983 * mptscsih_remove - Removed scsi devices
984 * @pdev: Pointer to pci_dev structure
985 *
986 *
987 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400988void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989mptscsih_remove(struct pci_dev *pdev)
990{
991 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
992 struct Scsi_Host *host = ioc->sh;
993 MPT_SCSI_HOST *hd;
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700994#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 int count;
996 unsigned long flags;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700997#endif
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400998 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001000 if(!host) {
1001 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 scsi_remove_host(host);
1006
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001007 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1008 return;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1011 /* Check DV thread active */
1012 count = 10 * HZ;
1013 spin_lock_irqsave(&dvtaskQ_lock, flags);
1014 if (dvtaskQ_active) {
1015 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
Nishanth Aravamudan65210182005-11-07 01:01:19 -08001016 while(dvtaskQ_active && --count)
1017 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 } else {
1019 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
1020 }
1021 if (!count)
1022 printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
1023#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
1024 else
1025 printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
1026#endif
1027#endif
1028
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001029 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001031 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001033 if (hd->ScsiLookup != NULL) {
1034 sz1 = hd->ioc->req_depth * sizeof(void *);
1035 kfree(hd->ScsiLookup);
1036 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
1038
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001039 /*
1040 * Free pointer array.
1041 */
1042 kfree(hd->Targets);
1043 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001045 dprintk((MYIOC_s_INFO_FMT
1046 "Free'd ScsiLookup (%d) memory\n",
1047 hd->ioc->name, sz1));
1048
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001049 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001050
1051 /* NULL the Scsi_Host pointer
1052 */
1053 hd->ioc->sh = NULL;
1054
1055 scsi_host_put(host);
1056
1057 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1062/*
1063 * mptscsih_shutdown - reboot notifier
1064 *
1065 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001066void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001067mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001069 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 struct Scsi_Host *host = ioc->sh;
1071 MPT_SCSI_HOST *hd;
1072
1073 if(!host)
1074 return;
1075
1076 hd = (MPT_SCSI_HOST *)host->hostdata;
1077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078}
1079
1080#ifdef CONFIG_PM
1081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1082/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001083 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 *
1085 *
1086 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001087int
Pavel Machek8d189f72005-04-16 15:25:28 -07001088mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001090 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001091 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
1094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1095/*
1096 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1097 *
1098 *
1099 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001100int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101mptscsih_resume(struct pci_dev *pdev)
1102{
1103 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1104 struct Scsi_Host *host = ioc->sh;
1105 MPT_SCSI_HOST *hd;
1106
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001107 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if(!host)
1110 return 0;
1111
1112 hd = (MPT_SCSI_HOST *)host->hostdata;
1113 if(!hd)
1114 return 0;
1115
1116#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1117 {
1118 unsigned long lflags;
1119 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1120 if (!dvtaskQ_active) {
1121 dvtaskQ_active = 1;
1122 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001123 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001125 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 } else {
1127 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1128 }
1129 }
1130#endif
1131 return 0;
1132}
1133
1134#endif
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1137/**
1138 * mptscsih_info - Return information about MPT adapter
1139 * @SChost: Pointer to Scsi_Host structure
1140 *
1141 * (linux scsi_host_template.info routine)
1142 *
1143 * Returns pointer to buffer where information was written.
1144 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001145const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146mptscsih_info(struct Scsi_Host *SChost)
1147{
1148 MPT_SCSI_HOST *h;
1149 int size = 0;
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001154 if (h->info_kbuf == NULL)
1155 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1156 return h->info_kbuf;
1157 h->info_kbuf[0] = '\0';
1158
1159 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1160 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001163 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164}
1165
1166struct info_str {
1167 char *buffer;
1168 int length;
1169 int offset;
1170 int pos;
1171};
1172
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001173static void
1174mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
1176 if (info->pos + len > info->length)
1177 len = info->length - info->pos;
1178
1179 if (info->pos + len < info->offset) {
1180 info->pos += len;
1181 return;
1182 }
1183
1184 if (info->pos < info->offset) {
1185 data += (info->offset - info->pos);
1186 len -= (info->offset - info->pos);
1187 }
1188
1189 if (len > 0) {
1190 memcpy(info->buffer + info->pos, data, len);
1191 info->pos += len;
1192 }
1193}
1194
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001195static int
1196mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197{
1198 va_list args;
1199 char buf[81];
1200 int len;
1201
1202 va_start(args, fmt);
1203 len = vsprintf(buf, fmt, args);
1204 va_end(args);
1205
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001206 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 return len;
1208}
1209
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001210static int
1211mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
1213 struct info_str info;
1214
1215 info.buffer = pbuf;
1216 info.length = len;
1217 info.offset = offset;
1218 info.pos = 0;
1219
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001220 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1221 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1222 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1223 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1226}
1227
1228/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1229/**
1230 * mptscsih_proc_info - Return information about MPT adapter
1231 *
1232 * (linux scsi_host_template.info routine)
1233 *
1234 * buffer: if write, user data; if read, buffer for user
1235 * length: if write, return length;
1236 * offset: if write, 0; if read, the current offset into the buffer from
1237 * the previous read.
1238 * hostno: scsi host number
1239 * func: if write = 1; if read = 0
1240 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001241int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1243 int length, int func)
1244{
1245 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1246 MPT_ADAPTER *ioc = hd->ioc;
1247 int size = 0;
1248
1249 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001250 /*
1251 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 */
1253 } else {
1254 if (start)
1255 *start = buffer;
1256
1257 size = mptscsih_host_info(ioc, buffer, offset, length);
1258 }
1259
1260 return size;
1261}
1262
1263/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1264#define ADD_INDEX_LOG(req_ent) do { } while(0)
1265
1266/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1267/**
1268 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1269 * @SCpnt: Pointer to scsi_cmnd structure
1270 * @done: Pointer SCSI mid-layer IO completion function
1271 *
1272 * (linux scsi_host_template.queuecommand routine)
1273 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1274 * from a linux scsi_cmnd request and send it to the IOC.
1275 *
1276 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1277 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001278int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1280{
1281 MPT_SCSI_HOST *hd;
1282 MPT_FRAME_HDR *mf;
1283 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001284 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 int lun;
1286 u32 datalen;
1287 u32 scsictl;
1288 u32 scsidir;
1289 u32 cmd_len;
1290 int my_idx;
1291 int ii;
1292
1293 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 lun = SCpnt->device->lun;
1295 SCpnt->scsi_done = done;
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1298 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1299
1300 if (hd->resetPending) {
1301 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1302 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1303 return SCSI_MLQUEUE_HOST_BUSY;
1304 }
1305
1306 /*
1307 * Put together a MPT SCSI request...
1308 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001309 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1311 hd->ioc->name));
1312 return SCSI_MLQUEUE_HOST_BUSY;
1313 }
1314
1315 pScsiReq = (SCSIIORequest_t *) mf;
1316
1317 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1318
1319 ADD_INDEX_LOG(my_idx);
1320
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001321 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 * Seems we may receive a buffer (datalen>0) even when there
1323 * will be no data transfer! GRRRRR...
1324 */
1325 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1326 datalen = SCpnt->request_bufflen;
1327 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1328 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1329 datalen = SCpnt->request_bufflen;
1330 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1331 } else {
1332 datalen = 0;
1333 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1334 }
1335
1336 /* Default to untagged. Once a target structure has been allocated,
1337 * use the Inquiry data to determine if device supports tagged.
1338 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001339 if (vdev
1340 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 && (SCpnt->device->tagged_supported)) {
1342 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1343 } else {
1344 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1345 }
1346
1347 /* Use the above information to set up the message frame
1348 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001349 pScsiReq->TargetID = (u8) vdev->target_id;
1350 pScsiReq->Bus = vdev->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 pScsiReq->ChainOffset = 0;
1352 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1353 pScsiReq->CDBLength = SCpnt->cmd_len;
1354 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1355 pScsiReq->Reserved = 0;
1356 pScsiReq->MsgFlags = mpt_msg_flags();
1357 pScsiReq->LUN[0] = 0;
1358 pScsiReq->LUN[1] = lun;
1359 pScsiReq->LUN[2] = 0;
1360 pScsiReq->LUN[3] = 0;
1361 pScsiReq->LUN[4] = 0;
1362 pScsiReq->LUN[5] = 0;
1363 pScsiReq->LUN[6] = 0;
1364 pScsiReq->LUN[7] = 0;
1365 pScsiReq->Control = cpu_to_le32(scsictl);
1366
1367 /*
1368 * Write SCSI CDB into the message
1369 */
1370 cmd_len = SCpnt->cmd_len;
1371 for (ii=0; ii < cmd_len; ii++)
1372 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1373
1374 for (ii=cmd_len; ii < 16; ii++)
1375 pScsiReq->CDB[ii] = 0;
1376
1377 /* DataLength */
1378 pScsiReq->DataLength = cpu_to_le32(datalen);
1379
1380 /* SenseBuffer low address */
1381 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1382 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1383
1384 /* Now add the SG list
1385 * Always have a SGE even if null length.
1386 */
1387 if (datalen == 0) {
1388 /* Add a NULL SGE */
1389 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1390 (dma_addr_t) -1);
1391 } else {
1392 /* Add a 32 or 64 bit SGE */
1393 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1394 goto fail;
1395 }
1396
1397 hd->ScsiLookup[my_idx] = SCpnt;
1398 SCpnt->host_scribble = NULL;
1399
1400#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001401 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001402 int dvStatus = hd->ioc->spi_data.dvStatus[vdev->target_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 int issueCmd = 1;
1404
1405 if (dvStatus || hd->ioc->spi_data.forceDv) {
1406
1407 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1408 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1409 unsigned long lflags;
1410 /* Schedule DV if necessary */
1411 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1412 if (!dvtaskQ_active) {
1413 dvtaskQ_active = 1;
1414 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001415 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001417 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 } else {
1419 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1420 }
1421 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1422 }
1423
1424 /* Trying to do DV to this target, extend timeout.
1425 * Wait to issue until flag is clear
1426 */
1427 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1428 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1429 issueCmd = 0;
1430 }
1431
1432 /* Set the DV flags.
1433 */
1434 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001435 mptscsih_set_dvflags(hd, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437 if (!issueCmd)
1438 goto fail;
1439 }
1440 }
1441#endif
1442
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001443 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1445 hd->ioc->name, SCpnt, mf, my_idx));
1446 DBG_DUMP_REQUEST_FRAME(mf)
1447 return 0;
1448
1449 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001450 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1452 mpt_free_msg_frame(hd->ioc, mf);
1453 return SCSI_MLQUEUE_HOST_BUSY;
1454}
1455
1456/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1457/*
1458 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1459 * with a SCSI IO request
1460 * @hd: Pointer to the MPT_SCSI_HOST instance
1461 * @req_idx: Index of the SCSI IO request frame.
1462 *
1463 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1464 * No return.
1465 */
1466static void
1467mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1468{
1469 MPT_FRAME_HDR *chain;
1470 unsigned long flags;
1471 int chain_idx;
1472 int next;
1473
1474 /* Get the first chain index and reset
1475 * tracker state.
1476 */
1477 chain_idx = ioc->ReqToChain[req_idx];
1478 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1479
1480 while (chain_idx != MPT_HOST_NO_CHAIN) {
1481
1482 /* Save the next chain buffer index */
1483 next = ioc->ChainToChain[chain_idx];
1484
1485 /* Free this chain buffer and reset
1486 * tracker
1487 */
1488 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1489
1490 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1491 + (chain_idx * ioc->req_sz));
1492
1493 spin_lock_irqsave(&ioc->FreeQlock, flags);
1494 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1495 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1496
1497 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1498 ioc->name, chain_idx));
1499
1500 /* handle next */
1501 chain_idx = next;
1502 }
1503 return;
1504}
1505
1506/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1507/*
1508 * Reset Handling
1509 */
1510
1511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1512/*
1513 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1514 * Fall through to mpt_HardResetHandler if: not operational, too many
1515 * failed TM requests or handshake failure.
1516 *
1517 * @ioc: Pointer to MPT_ADAPTER structure
1518 * @type: Task Management type
1519 * @target: Logical Target ID for reset (if appropriate)
1520 * @lun: Logical Unit for reset (if appropriate)
1521 * @ctx2abort: Context for the task to be aborted (if appropriate)
1522 *
1523 * Remark: Currently invoked from a non-interrupt thread (_bh).
1524 *
1525 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1526 * will be active.
1527 *
1528 * Returns 0 for SUCCESS or -1 if FAILED.
1529 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001530int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1532{
1533 MPT_ADAPTER *ioc;
1534 int rc = -1;
1535 int doTask = 1;
1536 u32 ioc_raw_state;
1537 unsigned long flags;
1538
1539 /* If FW is being reloaded currently, return success to
1540 * the calling function.
1541 */
1542 if (hd == NULL)
1543 return 0;
1544
1545 ioc = hd->ioc;
1546 if (ioc == NULL) {
1547 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1548 return FAILED;
1549 }
1550 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1551
1552 // SJR - CHECKME - Can we avoid this here?
1553 // (mpt_HardResetHandler has this check...)
1554 spin_lock_irqsave(&ioc->diagLock, flags);
1555 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1556 spin_unlock_irqrestore(&ioc->diagLock, flags);
1557 return FAILED;
1558 }
1559 spin_unlock_irqrestore(&ioc->diagLock, flags);
1560
1561 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1562 * If we time out and not bus reset, then we return a FAILED status to the caller.
1563 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1564 * successful. Otherwise, reload the FW.
1565 */
1566 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1567 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001568 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 "Timed out waiting for last TM (%d) to complete! \n",
1570 hd->ioc->name, hd->tmPending));
1571 return FAILED;
1572 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001573 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 "Timed out waiting for last TM (%d) to complete! \n",
1575 hd->ioc->name, hd->tmPending));
1576 return FAILED;
1577 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001578 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 "Timed out waiting for last TM (%d) to complete! \n",
1580 hd->ioc->name, hd->tmPending));
1581 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1582 return FAILED;
1583
1584 doTask = 0;
1585 }
1586 } else {
1587 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1588 hd->tmPending |= (1 << type);
1589 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1590 }
1591
1592 /* Is operational?
1593 */
1594 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1595
1596#ifdef MPT_DEBUG_RESET
1597 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1598 printk(MYIOC_s_WARN_FMT
1599 "TM Handler: IOC Not operational(0x%x)!\n",
1600 hd->ioc->name, ioc_raw_state);
1601 }
1602#endif
1603
1604 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1605 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1606
1607 /* Isse the Task Mgmt request.
1608 */
1609 if (hd->hard_resets < -1)
1610 hd->hard_resets++;
1611 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1612 if (rc) {
1613 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1614 } else {
1615 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1616 }
1617 }
1618
1619 /* Only fall through to the HRH if this is a bus reset
1620 */
1621 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1622 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1623 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1624 hd->ioc->name));
1625 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1626 }
1627
1628 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1629
1630 return rc;
1631}
1632
1633
1634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1635/*
1636 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1637 * @hd: Pointer to MPT_SCSI_HOST structure
1638 * @type: Task Management type
1639 * @target: Logical Target ID for reset (if appropriate)
1640 * @lun: Logical Unit for reset (if appropriate)
1641 * @ctx2abort: Context for the task to be aborted (if appropriate)
1642 *
1643 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1644 * or a non-interrupt thread. In the former, must not call schedule().
1645 *
1646 * Not all fields are meaningfull for all task types.
1647 *
1648 * Returns 0 for SUCCESS, -999 for "no msg frames",
1649 * else other non-zero value returned.
1650 */
1651static int
1652mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1653{
1654 MPT_FRAME_HDR *mf;
1655 SCSITaskMgmt_t *pScsiTm;
1656 int ii;
1657 int retval;
1658
1659 /* Return Fail to calling function if no message frames available.
1660 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001661 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1663 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001664 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 }
1666 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1667 hd->ioc->name, mf));
1668
1669 /* Format the Request
1670 */
1671 pScsiTm = (SCSITaskMgmt_t *) mf;
1672 pScsiTm->TargetID = target;
1673 pScsiTm->Bus = channel;
1674 pScsiTm->ChainOffset = 0;
1675 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1676
1677 pScsiTm->Reserved = 0;
1678 pScsiTm->TaskType = type;
1679 pScsiTm->Reserved1 = 0;
1680 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1681 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1682
1683 for (ii= 0; ii < 8; ii++) {
1684 pScsiTm->LUN[ii] = 0;
1685 }
1686 pScsiTm->LUN[1] = lun;
1687
1688 for (ii=0; ii < 7; ii++)
1689 pScsiTm->Reserved2[ii] = 0;
1690
1691 pScsiTm->TaskMsgContext = ctx2abort;
1692
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001693 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1694 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1697
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001698 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1700 CAN_SLEEP)) != 0) {
1701 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1702 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1703 hd->ioc, mf));
1704 mpt_free_msg_frame(hd->ioc, mf);
1705 return retval;
1706 }
1707
1708 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1709 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1710 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1711 hd->ioc, mf));
1712 mpt_free_msg_frame(hd->ioc, mf);
1713 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1714 hd->ioc->name));
1715 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1716 }
1717
1718 return retval;
1719}
1720
1721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1722/**
1723 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1724 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1725 *
1726 * (linux scsi_host_template.eh_abort_handler routine)
1727 *
1728 * Returns SUCCESS or FAILED.
1729 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001730int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731mptscsih_abort(struct scsi_cmnd * SCpnt)
1732{
1733 MPT_SCSI_HOST *hd;
1734 MPT_ADAPTER *ioc;
1735 MPT_FRAME_HDR *mf;
1736 u32 ctx2abort;
1737 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001738 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001739 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
1741 /* If we can't locate our host adapter structure, return FAILED status.
1742 */
1743 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1744 SCpnt->result = DID_RESET << 16;
1745 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001746 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 "Can't locate host! (sc=%p)\n",
1748 SCpnt));
1749 return FAILED;
1750 }
1751
1752 ioc = hd->ioc;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001753 if (hd->resetPending) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 return FAILED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 if (hd->timeouts < -1)
1758 hd->timeouts++;
1759
1760 /* Find this command
1761 */
1762 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001763 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 * Do OS callback.
1765 */
1766 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001767 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 "Command not in the active list! (sc=%p)\n",
1769 hd->ioc->name, SCpnt));
1770 return SUCCESS;
1771 }
1772
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001773 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1774 hd->ioc->name, SCpnt);
1775 scsi_print_command(SCpnt);
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1778 * (the IO to be ABORT'd)
1779 *
1780 * NOTE: Since we do not byteswap MsgContext, we do not
1781 * swap it here either. It is an opaque cookie to
1782 * the controller, so it does not matter. -DaveM
1783 */
1784 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1785 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1786
1787 hd->abortSCpnt = SCpnt;
1788
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001789 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001790 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001791 vdev->bus_id, vdev->target_id, vdev->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001792 ctx2abort, 2 /* 2 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001794 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1795 hd->ioc->name,
1796 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001798 if (retval == 0)
1799 return SUCCESS;
1800
1801 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 hd->tmPending = 0;
1803 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001805 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806}
1807
1808/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1809/**
1810 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1811 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1812 *
1813 * (linux scsi_host_template.eh_dev_reset_handler routine)
1814 *
1815 * Returns SUCCESS or FAILED.
1816 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001817int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1819{
1820 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001821 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001822 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 /* If we can't locate our host adapter structure, return FAILED status.
1825 */
1826 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001827 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 "Can't locate host! (sc=%p)\n",
1829 SCpnt));
1830 return FAILED;
1831 }
1832
1833 if (hd->resetPending)
1834 return FAILED;
1835
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001836 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001838 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001840 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001841 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001842 vdev->bus_id, vdev->target_id,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001843 0, 0, 5 /* 5 second timeout */);
1844
1845 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1846 hd->ioc->name,
1847 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1848
1849 if (retval == 0)
1850 return SUCCESS;
1851
1852 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 hd->tmPending = 0;
1854 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001856 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857}
1858
1859/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1860/**
1861 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1862 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1863 *
1864 * (linux scsi_host_template.eh_bus_reset_handler routine)
1865 *
1866 * Returns SUCCESS or FAILED.
1867 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001868int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1870{
1871 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001872 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001873 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 /* If we can't locate our host adapter structure, return FAILED status.
1876 */
1877 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001878 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 "Can't locate host! (sc=%p)\n",
1880 SCpnt ) );
1881 return FAILED;
1882 }
1883
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001884 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001886 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 if (hd->timeouts < -1)
1889 hd->timeouts++;
1890
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001891 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001892 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001893 vdev->bus_id, 0, 0, 0, 5 /* 5 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001895 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1896 hd->ioc->name,
1897 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1898
1899 if (retval == 0)
1900 return SUCCESS;
1901
1902 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 hd->tmPending = 0;
1904 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001906 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907}
1908
1909/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1910/**
1911 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1912 * new_eh variant
1913 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1914 *
1915 * (linux scsi_host_template.eh_host_reset_handler routine)
1916 *
1917 * Returns SUCCESS or FAILED.
1918 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001919int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1921{
1922 MPT_SCSI_HOST * hd;
1923 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925 /* If we can't locate the host to reset, then we failed. */
1926 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001927 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 "Can't locate host! (sc=%p)\n",
1929 SCpnt ) );
1930 return FAILED;
1931 }
1932
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001933 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 hd->ioc->name, SCpnt);
1935
1936 /* If our attempts to reset the host failed, then return a failed
1937 * status. The host will be taken off line by the SCSI mid-layer.
1938 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1940 status = FAILED;
1941 } else {
1942 /* Make sure TM pending is cleared and TM state is set to
1943 * NONE.
1944 */
1945 hd->tmPending = 0;
1946 hd->tmState = TM_STATE_NONE;
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001949 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 "Status = %s\n",
1951 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1952
1953 return status;
1954}
1955
1956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1957/**
1958 * mptscsih_tm_pending_wait - wait for pending task management request to
1959 * complete.
1960 * @hd: Pointer to MPT host structure.
1961 *
1962 * Returns {SUCCESS,FAILED}.
1963 */
1964static int
1965mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1966{
1967 unsigned long flags;
1968 int loop_count = 4 * 10; /* Wait 10 seconds */
1969 int status = FAILED;
1970
1971 do {
1972 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1973 if (hd->tmState == TM_STATE_NONE) {
1974 hd->tmState = TM_STATE_IN_PROGRESS;
1975 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001977 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 break;
1979 }
1980 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1981 msleep(250);
1982 } while (--loop_count);
1983
1984 return status;
1985}
1986
1987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1988/**
1989 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1990 * @hd: Pointer to MPT host structure.
1991 *
1992 * Returns {SUCCESS,FAILED}.
1993 */
1994static int
1995mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1996{
1997 unsigned long flags;
1998 int loop_count = 4 * timeout;
1999 int status = FAILED;
2000
2001 do {
2002 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2003 if(hd->tmPending == 0) {
2004 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002005 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 break;
2007 }
2008 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2009 msleep_interruptible(250);
2010 } while (--loop_count);
2011
2012 return status;
2013}
2014
2015/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2016/**
2017 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2018 * @ioc: Pointer to MPT_ADAPTER structure
2019 * @mf: Pointer to SCSI task mgmt request frame
2020 * @mr: Pointer to SCSI task mgmt reply frame
2021 *
2022 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2023 * of any SCSI task management request.
2024 * This routine is registered with the MPT (base) driver at driver
2025 * load/init time via the mpt_register() API call.
2026 *
2027 * Returns 1 indicating alloc'd request frame ptr should be freed.
2028 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002029int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2031{
2032 SCSITaskMgmtReply_t *pScsiTmReply;
2033 SCSITaskMgmt_t *pScsiTmReq;
2034 MPT_SCSI_HOST *hd;
2035 unsigned long flags;
2036 u16 iocstatus;
2037 u8 tmType;
2038
2039 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2040 ioc->name, mf, mr));
2041 if (ioc->sh) {
2042 /* Depending on the thread, a timer is activated for
2043 * the TM request. Delete this timer on completion of TM.
2044 * Decrement count of outstanding TM requests.
2045 */
2046 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2047 } else {
2048 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2049 ioc->name));
2050 return 1;
2051 }
2052
2053 if (mr == NULL) {
2054 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2055 ioc->name, mf));
2056 return 1;
2057 } else {
2058 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2059 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2060
2061 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2062 tmType = pScsiTmReq->TaskType;
2063
2064 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2065 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2066 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2067
2068 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2069 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2070 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2071 /* Error? (anything non-zero?) */
2072 if (iocstatus) {
2073
2074 /* clear flags and continue.
2075 */
2076 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2077 hd->abortSCpnt = NULL;
2078
2079 /* If an internal command is present
2080 * or the TM failed - reload the FW.
2081 * FC FW may respond FAILED to an ABORT
2082 */
2083 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2084 if ((hd->cmdPtr) ||
2085 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2086 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2087 printk((KERN_WARNING
2088 " Firmware Reload FAILED!!\n"));
2089 }
2090 }
2091 }
2092 } else {
2093 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2094
2095 hd->abortSCpnt = NULL;
2096
2097 }
2098 }
2099
2100 spin_lock_irqsave(&ioc->FreeQlock, flags);
2101 hd->tmPending = 0;
2102 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2103 hd->tmState = TM_STATE_NONE;
2104
2105 return 1;
2106}
2107
2108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2109/*
2110 * This is anyones guess quite frankly.
2111 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002112int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2114 sector_t capacity, int geom[])
2115{
2116 int heads;
2117 int sectors;
2118 sector_t cylinders;
2119 ulong dummy;
2120
2121 heads = 64;
2122 sectors = 32;
2123
2124 dummy = heads * sectors;
2125 cylinders = capacity;
2126 sector_div(cylinders,dummy);
2127
2128 /*
2129 * Handle extended translation size for logical drives
2130 * > 1Gb
2131 */
2132 if ((ulong)capacity >= 0x200000) {
2133 heads = 255;
2134 sectors = 63;
2135 dummy = heads * sectors;
2136 cylinders = capacity;
2137 sector_div(cylinders,dummy);
2138 }
2139
2140 /* return result */
2141 geom[0] = heads;
2142 geom[1] = sectors;
2143 geom[2] = cylinders;
2144
2145 dprintk((KERN_NOTICE
2146 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2147 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2148
2149 return 0;
2150}
2151
2152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2153/*
2154 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002155 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002158int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002159mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002161 VirtTarget *vtarget;
2162
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002163 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002164 if (!vtarget)
2165 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002166 starget->hostdata = vtarget;
2167 return 0;
2168}
2169
2170/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2171/*
2172 * OS entry point to allow host driver to alloc memory
2173 * for each scsi device. Called once per device the bus scan.
2174 * Return non-zero if allocation fails.
2175 */
2176int
2177mptscsih_slave_alloc(struct scsi_device *sdev)
2178{
2179 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002181 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002183 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002185 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 if (!vdev) {
2187 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2188 hd->ioc->name, sizeof(VirtDevice));
2189 return -ENOMEM;
2190 }
2191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 vdev->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002193 vdev->target_id = sdev->id;
2194 vdev->bus_id = sdev->channel;
2195 vdev->lun = sdev->lun;
2196 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002198 starget = scsi_target(sdev);
2199 vtarget = starget->hostdata;
2200 vdev->vtarget = vtarget;
2201
2202 if (vtarget->num_luns == 0) {
2203 hd->Targets[sdev->id] = vtarget;
2204 vtarget->ioc_id = hd->ioc->id;
2205 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2206 vtarget->target_id = sdev->id;
2207 vtarget->bus_id = sdev->channel;
2208 if (hd->ioc->bus_type == SPI) {
2209 if (hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2210 vtarget->raidVolume = 1;
2211 ddvtprintk((KERN_INFO
2212 "RAID Volume @ id %d\n", sdev->id));
2213 }
2214 } else {
2215 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2216 }
2217 }
2218 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return 0;
2220}
2221
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222/*
2223 * OS entry point to allow for host driver to free allocated memory
2224 * Called if no device present or device being unloaded
2225 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002226void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002227mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002229 if (starget->hostdata)
2230 kfree(starget->hostdata);
2231 starget->hostdata = NULL;
2232}
2233
2234/*
2235 * OS entry point to allow for host driver to free allocated memory
2236 * Called if no device present or device being unloaded
2237 */
2238void
2239mptscsih_slave_destroy(struct scsi_device *sdev)
2240{
2241 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002243 VirtTarget *vtarget;
2244 VirtDevice *vdevice;
2245 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002247 starget = scsi_target(sdev);
2248 vtarget = starget->hostdata;
2249 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002251 mptscsih_search_running_cmds(hd, vdevice);
2252 vtarget->luns[0] &= ~(1 << vdevice->lun);
2253 vtarget->num_luns--;
2254 if (vtarget->num_luns == 0) {
2255 mptscsih_negotiate_to_asyn_narrow(hd, vtarget);
2256 if (hd->ioc->bus_type == SPI) {
2257 if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
2258 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2259 } else {
2260 hd->ioc->spi_data.dvStatus[vtarget->target_id] =
2261 MPT_SCSICFG_NEGOTIATE;
2262 if (!hd->negoNvram) {
2263 hd->ioc->spi_data.dvStatus[vtarget->target_id] |=
2264 MPT_SCSICFG_DV_NOT_DONE;
2265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
2267 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002268 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002270 mptscsih_synchronize_cache(hd, vdevice);
2271 kfree(vdevice);
2272 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273}
2274
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2276/*
2277 * mptscsih_change_queue_depth - This function will set a devices queue depth
2278 * @sdev: per scsi_device pointer
2279 * @qdepth: requested queue depth
2280 *
2281 * Adding support for new 'change_queue_depth' api.
2282*/
2283int
2284mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002286 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2287 VirtTarget *vtarget;
2288 struct scsi_target *starget;
2289 int max_depth;
2290 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002292 starget = scsi_target(sdev);
2293 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002294
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002295 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002296 if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2297 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 max_depth = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002299 else if (((vtarget->inq_data[0] & 0x1f) == 0x00) &&
2300 (vtarget->minSyncFactor <= MPT_ULTRA160 ))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2302 else
2303 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2304 } else {
2305 /* error case - No Inq. Data */
2306 max_depth = 1;
2307 }
2308 } else
2309 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2310
2311 if (qdepth > max_depth)
2312 qdepth = max_depth;
2313 if (qdepth == 1)
2314 tagged = 0;
2315 else
2316 tagged = MSG_SIMPLE_TAG;
2317
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002318 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2319 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320}
2321
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322/*
2323 * OS entry point to adjust the queue_depths on a per-device basis.
2324 * Called once per device the bus scan. Use it to force the queue_depth
2325 * member to 1 if a device does not support Q tags.
2326 * Return non-zero if fails.
2327 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002328int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002329mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002331 struct Scsi_Host *sh = sdev->host;
2332 VirtTarget *vtarget;
2333 VirtDevice *vdevice;
2334 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002336 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002338 starget = scsi_target(sdev);
2339 vtarget = starget->hostdata;
2340 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
2342 dsprintk((MYIOC_s_INFO_FMT
2343 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002344 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2345 if (hd->ioc->bus_type == SPI)
2346 dsprintk((MYIOC_s_INFO_FMT
2347 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2348 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2349 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002351 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002353 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 goto slave_configure_exit;
2355 }
2356
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002357 vdevice->configured_lun=1;
2358 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2359 indexed_lun = (vdevice->lun % 32);
2360 vtarget->luns[lun_index] |= (1 << indexed_lun);
2361 mptscsih_initTarget(hd, vtarget, sdev->lun, sdev->inquiry,
2362 sdev->inquiry_len );
2363 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
2365 dsprintk((MYIOC_s_INFO_FMT
2366 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002367 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002369 if (hd->ioc->bus_type == SPI)
2370 dsprintk((MYIOC_s_INFO_FMT
2371 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2372 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2373 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375slave_configure_exit:
2376
2377 dsprintk((MYIOC_s_INFO_FMT
2378 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2380 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
2382 return 0;
2383}
2384
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2386/*
2387 * Private routines...
2388 */
2389
2390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2391/* Utility function to copy sense data from the scsi_cmnd buffer
2392 * to the FC and SCSI target structures.
2393 *
2394 */
2395static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002396mptscsih_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 -07002397{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002398 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 SCSIIORequest_t *pReq;
2400 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 /* Get target structure
2403 */
2404 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 if (sense_count) {
2408 u8 *sense_data;
2409 int req_index;
2410
2411 /* Copy the sense received into the scsi command block. */
2412 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2413 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2414 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2415
2416 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2417 */
2418 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002419 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 int idx;
2421 MPT_ADAPTER *ioc = hd->ioc;
2422
2423 idx = ioc->eventContext % ioc->eventLogSize;
2424 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2425 ioc->events[idx].eventContext = ioc->eventContext;
2426
2427 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2428 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002429 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2432
2433 ioc->eventContext++;
2434 }
2435 }
2436 } else {
2437 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2438 hd->ioc->name));
2439 }
2440}
2441
2442static u32
2443SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2444{
2445 MPT_SCSI_HOST *hd;
2446 int i;
2447
2448 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2449
2450 for (i = 0; i < hd->ioc->req_depth; i++) {
2451 if (hd->ScsiLookup[i] == sc) {
2452 return i;
2453 }
2454 }
2455
2456 return -1;
2457}
2458
2459/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002460int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2462{
2463 MPT_SCSI_HOST *hd;
2464 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002465 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
2467 dtmprintk((KERN_WARNING MYNAM
2468 ": IOC %s_reset routed to SCSI host driver!\n",
2469 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2470 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2471
2472 /* If a FW reload request arrives after base installed but
2473 * before all scsi hosts have been attached, then an alt_ioc
2474 * may have a NULL sh pointer.
2475 */
2476 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2477 return 0;
2478 else
2479 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2480
2481 if (reset_phase == MPT_IOC_SETUP_RESET) {
2482 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2483
2484 /* Clean Up:
2485 * 1. Set Hard Reset Pending Flag
2486 * All new commands go to doneQ
2487 */
2488 hd->resetPending = 1;
2489
2490 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2491 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2492
2493 /* 2. Flush running commands
2494 * Clean ScsiLookup (and associated memory)
2495 * AND clean mytaskQ
2496 */
2497
2498 /* 2b. Reply to OS all known outstanding I/O commands.
2499 */
2500 mptscsih_flush_running_cmds(hd);
2501
2502 /* 2c. If there was an internal command that
2503 * has not completed, configuration or io request,
2504 * free these resources.
2505 */
2506 if (hd->cmdPtr) {
2507 del_timer(&hd->timer);
2508 mpt_free_msg_frame(ioc, hd->cmdPtr);
2509 }
2510
2511 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2512
2513 } else {
2514 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2515
2516 /* Once a FW reload begins, all new OS commands are
2517 * redirected to the doneQ w/ a reset status.
2518 * Init all control structures.
2519 */
2520
2521 /* ScsiLookup initialization
2522 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002523 for (ii=0; ii < hd->ioc->req_depth; ii++)
2524 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
2526 /* 2. Chain Buffer initialization
2527 */
2528
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002529 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002531 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2533 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2534 }
2535
2536 /* 5. Enable new commands to be posted
2537 */
2538 spin_lock_irqsave(&ioc->FreeQlock, flags);
2539 hd->tmPending = 0;
2540 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2541 hd->resetPending = 0;
2542 hd->tmState = TM_STATE_NONE;
2543
2544 /* 6. If there was an internal command,
2545 * wake this process up.
2546 */
2547 if (hd->cmdPtr) {
2548 /*
2549 * Wake up the original calling thread
2550 */
2551 hd->pLocal = &hd->localReply;
2552 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002553 hd->scandv_wait_done = 1;
2554 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 hd->cmdPtr = NULL;
2556 }
2557
Michael Reed05e8ec12006-01-13 14:31:54 -06002558 /* 7. SPI: Set flag to force DV and re-read IOC Page 3
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002560 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2562 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2563 }
2564
Michael Reed05e8ec12006-01-13 14:31:54 -06002565 /* 7. FC: Rescan for blocked rports which might have returned.
2566 */
2567 else if (ioc->bus_type == FC) {
2568 int work_count;
2569 unsigned long flags;
2570
2571 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2572 work_count = ++ioc->fc_rescan_work_count;
2573 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2574 if (work_count == 1)
2575 schedule_work(&ioc->fc_rescan_work);
2576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2578
2579 }
2580
2581 return 1; /* currently means nothing really */
2582}
2583
2584/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002585int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2587{
2588 MPT_SCSI_HOST *hd;
2589 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
Michael Reed05e8ec12006-01-13 14:31:54 -06002590 int work_count;
2591 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
2593 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2594 ioc->name, event));
2595
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002596 if (ioc->sh == NULL ||
2597 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2598 return 1;
2599
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 switch (event) {
2601 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2602 /* FIXME! */
2603 break;
2604 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2605 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002606 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002607 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 break;
2609 case MPI_EVENT_LOGOUT: /* 09 */
2610 /* FIXME! */
2611 break;
2612
Michael Reed05e8ec12006-01-13 14:31:54 -06002613 case MPI_EVENT_RESCAN: /* 06 */
2614 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2615 work_count = ++ioc->fc_rescan_work_count;
2616 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2617 if (work_count == 1)
2618 schedule_work(&ioc->fc_rescan_work);
2619 break;
2620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 /*
2622 * CHECKME! Don't think we need to do
2623 * anything for these, but...
2624 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2626 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2627 /*
2628 * CHECKME! Falling thru...
2629 */
2630 break;
2631
2632 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002633 {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07002634#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002635 pMpiEventDataRaid_t pRaidEventData =
2636 (pMpiEventDataRaid_t) pEvReply->Data;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002637 /* Domain Validation Needed */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002638 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002639 pRaidEventData->ReasonCode ==
2640 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2641 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002643 break;
2644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 case MPI_EVENT_NONE: /* 00 */
2647 case MPI_EVENT_LOG_DATA: /* 01 */
2648 case MPI_EVENT_STATE_CHANGE: /* 02 */
2649 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2650 default:
2651 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2652 break;
2653 }
2654
2655 return 1; /* currently means nothing really */
2656}
2657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2659/*
2660 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2661 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002662 * @vtarget: per target private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 * @lun: SCSI LUN id
2664 * @data: Pointer to data
2665 * @dlen: Number of INQUIRY bytes
2666 *
2667 * NOTE: It's only SAFE to call this routine if data points to
2668 * sane & valid STANDARD INQUIRY data!
2669 *
2670 * Allocate and initialize memory for this target.
2671 * Save inquiry data.
2672 *
2673 */
2674static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002675mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002677 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 char data_56;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002679 int inq_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
2681 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002682 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684 /*
2685 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2686 * (i.e. The targer is capable of supporting the specified peripheral device type
2687 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002688 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 * capable of supporting a physical device on this logical unit). This is to work
2690 * around a bug in th emid-layer in some distributions in which the mid-layer will
2691 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2692 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002693 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002695
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 /* Is LUN supported? If so, upper 2 bits will be 0
2697 * in first byte of inquiry data.
2698 */
2699 if (data[0] & 0xe0)
2700 return;
2701
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002702 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002705 if (data)
2706 vtarget->type = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002708 if (hd->ioc->bus_type != SPI)
2709 return;
2710
2711 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2712 /* Treat all Processors as SAF-TE if
2713 * command line option is set */
2714 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2715 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
2716 }else if ((data[0] == TYPE_PROCESSOR) &&
2717 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2718 if ( dlen > 49 ) {
2719 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2720 if ( data[44] == 'S' &&
2721 data[45] == 'A' &&
2722 data[46] == 'F' &&
2723 data[47] == '-' &&
2724 data[48] == 'T' &&
2725 data[49] == 'E' ) {
2726 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2727 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 }
2729 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002730 }
2731 if (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2732 inq_len = dlen < 8 ? dlen : 8;
2733 memcpy (vtarget->inq_data, data, inq_len);
2734 /* If have not done DV, set the DV flag.
2735 */
2736 pSpi = &hd->ioc->spi_data;
2737 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2738 if (pSpi->dvStatus[vtarget->target_id] & MPT_SCSICFG_DV_NOT_DONE)
2739 pSpi->dvStatus[vtarget->target_id] |= MPT_SCSICFG_NEED_DV;
2740 }
2741 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002743 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2744 if (dlen > 56) {
2745 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2746 /* Update the target capabilities
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002748 data_56 = data[56];
2749 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002751 }
2752 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
2753 } else {
2754 /* Initial Inquiry may not request enough data bytes to
2755 * obtain byte 57. DV will; if target doesn't return
2756 * at least 57 bytes, data[56] will be zero. */
2757 if (dlen > 56) {
2758 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2759 /* Update the target capabilities
2760 */
2761 data_56 = data[56];
2762 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
2763 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 }
2765 }
2766 }
2767}
2768
2769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2770/*
2771 * Update the target negotiation parameters based on the
2772 * the Inquiry data, adapter capabilities, and NVRAM settings.
2773 *
2774 */
2775static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002776mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, char byte56)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002778 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 int id = (int) target->target_id;
2780 int nvram;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002781 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 int ii;
2783 u8 width = MPT_NARROW;
2784 u8 factor = MPT_ASYNC;
2785 u8 offset = 0;
2786 u8 version, nfactor;
2787 u8 noQas = 1;
2788
2789 target->negoFlags = pspi_data->noQas;
2790
2791 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2792 * support. If available, default QAS to off and allow enabling.
2793 * If not available, default QAS to on, turn off for non-disks.
2794 */
2795
2796 /* Set flags based on Inquiry data
2797 */
2798 version = target->inq_data[2] & 0x07;
2799 if (version < 2) {
2800 width = 0;
2801 factor = MPT_ULTRA2;
2802 offset = pspi_data->maxSyncOffset;
2803 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2804 } else {
2805 if (target->inq_data[7] & 0x20) {
2806 width = 1;
2807 }
2808
2809 if (target->inq_data[7] & 0x10) {
2810 factor = pspi_data->minSyncFactor;
2811 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2812 /* bits 2 & 3 show Clocking support */
2813 if ((byte56 & 0x0C) == 0)
2814 factor = MPT_ULTRA2;
2815 else {
2816 if ((byte56 & 0x03) == 0)
2817 factor = MPT_ULTRA160;
2818 else {
2819 factor = MPT_ULTRA320;
2820 if (byte56 & 0x02)
2821 {
2822 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2823 noQas = 0;
2824 }
2825 if (target->inq_data[0] == TYPE_TAPE) {
2826 if (byte56 & 0x01)
2827 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2828 }
2829 }
2830 }
2831 } else {
2832 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2833 noQas = 0;
2834 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 offset = pspi_data->maxSyncOffset;
2837
2838 /* If RAID, never disable QAS
2839 * else if non RAID, do not disable
2840 * QAS if bit 1 is set
2841 * bit 1 QAS support, non-raid only
2842 * bit 0 IU support
2843 */
2844 if (target->raidVolume == 1) {
2845 noQas = 0;
2846 }
2847 } else {
2848 factor = MPT_ASYNC;
2849 offset = 0;
2850 }
2851 }
2852
2853 if ( (target->inq_data[7] & 0x02) == 0) {
2854 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2855 }
2856
2857 /* Update tflags based on NVRAM settings. (SCSI only)
2858 */
2859 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2860 nvram = pspi_data->nvram[id];
2861 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2862
2863 if (width)
2864 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2865
2866 if (offset > 0) {
2867 /* Ensure factor is set to the
2868 * maximum of: adapter, nvram, inquiry
2869 */
2870 if (nfactor) {
2871 if (nfactor < pspi_data->minSyncFactor )
2872 nfactor = pspi_data->minSyncFactor;
2873
2874 factor = max(factor, nfactor);
2875 if (factor == MPT_ASYNC)
2876 offset = 0;
2877 } else {
2878 offset = 0;
2879 factor = MPT_ASYNC;
2880 }
2881 } else {
2882 factor = MPT_ASYNC;
2883 }
2884 }
2885
2886 /* Make sure data is consistent
2887 */
2888 if ((!width) && (factor < MPT_ULTRA2)) {
2889 factor = MPT_ULTRA2;
2890 }
2891
2892 /* Save the data to the target structure.
2893 */
2894 target->minSyncFactor = factor;
2895 target->maxOffset = offset;
2896 target->maxWidth = width;
2897
2898 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2899
2900 /* Disable unused features.
2901 */
2902 if (!width)
2903 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2904
2905 if (!offset)
2906 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2907
2908 if ( factor > MPT_ULTRA320 )
2909 noQas = 0;
2910
2911 /* GEM, processor WORKAROUND
2912 */
2913 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2914 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2915 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2916 } else {
2917 if (noQas && (pspi_data->noQas == 0)) {
2918 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2919 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2920
2921 /* Disable QAS in a mixed configuration case
2922 */
2923
2924 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2925 for (ii = 0; ii < id; ii++) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002926 if ( (vtarget = hd->Targets[ii]) ) {
2927 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2928 mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 }
2931 }
2932 }
2933
2934 /* Write SDP1 on this I/O to this target */
2935 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2936 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2937 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2938 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2939 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2940 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2941 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2942 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2943 }
2944}
2945
2946/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947/*
2948 * If no Target, bus reset on 1st I/O. Set the flag to
2949 * prevent any future negotiations to this device.
2950 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002951static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002952mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002954 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002956 if ((vdev = sc->device->hostdata) != NULL)
2957 hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 return;
2959}
2960
2961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2962/*
2963 * SCSI Config Page functionality ...
2964 */
2965/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2966/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
2967 * based on width, factor and offset parameters.
2968 * @width: bus width
2969 * @factor: sync factor
2970 * @offset: sync offset
2971 * @requestedPtr: pointer to requested values (updated)
2972 * @configurationPtr: pointer to configuration values (updated)
2973 * @flags: flags to block WDTR or SDTR negotiation
2974 *
2975 * Return: None.
2976 *
2977 * Remark: Called by writeSDP1 and _dv_params
2978 */
2979static void
2980mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
2981{
2982 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
2983 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
2984
2985 *configurationPtr = 0;
2986 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
2987 *requestedPtr |= (offset << 16) | (factor << 8);
2988
2989 if (width && offset && !nowide && !nosync) {
2990 if (factor < MPT_ULTRA160) {
2991 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
2992 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
2993 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
2994 if (flags & MPT_TAPE_NEGO_IDP)
2995 *requestedPtr |= 0x08000000;
2996 } else if (factor < MPT_ULTRA2) {
2997 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
2998 }
2999 }
3000
3001 if (nowide)
3002 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3003
3004 if (nosync)
3005 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3006
3007 return;
3008}
3009
3010/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3011/* mptscsih_writeSDP1 - write SCSI Device Page 1
3012 * @hd: Pointer to a SCSI Host Strucutre
3013 * @portnum: IOC port number
3014 * @target_id: writeSDP1 for single ID
3015 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3016 *
3017 * Return: -EFAULT if read of config page header fails
3018 * or 0 if success.
3019 *
3020 * Remark: If a target has been found, the settings from the
3021 * target structure are used, else the device is set
3022 * to async/narrow.
3023 *
3024 * Remark: Called during init and after a FW reload.
3025 * Remark: We do not wait for a return, write pages sequentially.
3026 */
3027static int
3028mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3029{
3030 MPT_ADAPTER *ioc = hd->ioc;
3031 Config_t *pReq;
3032 SCSIDevicePage1_t *pData;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003033 VirtTarget *vtarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 MPT_FRAME_HDR *mf;
3035 dma_addr_t dataDma;
3036 u16 req_idx;
3037 u32 frameOffset;
3038 u32 requested, configuration, flagsLength;
3039 int ii, nvram;
3040 int id = 0, maxid = 0;
3041 u8 width;
3042 u8 factor;
3043 u8 offset;
3044 u8 bus = 0;
3045 u8 negoFlags;
3046 u8 maxwidth, maxoffset, maxfactor;
3047
3048 if (ioc->spi_data.sdp1length == 0)
3049 return 0;
3050
3051 if (flags & MPT_SCSICFG_ALL_IDS) {
3052 id = 0;
3053 maxid = ioc->sh->max_id - 1;
3054 } else if (ioc->sh) {
3055 id = target_id;
3056 maxid = min_t(int, id, ioc->sh->max_id - 1);
3057 }
3058
3059 for (; id <= maxid; id++) {
3060
3061 if (id == ioc->pfacts[portnum].PortSCSIID)
3062 continue;
3063
3064 /* Use NVRAM to get adapter and target maximums
3065 * Data over-riden by target structure information, if present
3066 */
3067 maxwidth = ioc->spi_data.maxBusWidth;
3068 maxoffset = ioc->spi_data.maxSyncOffset;
3069 maxfactor = ioc->spi_data.minSyncFactor;
3070 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3071 nvram = ioc->spi_data.nvram[id];
3072
3073 if (maxwidth)
3074 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3075
3076 if (maxoffset > 0) {
3077 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3078 if (maxfactor == 0) {
3079 /* Key for async */
3080 maxfactor = MPT_ASYNC;
3081 maxoffset = 0;
3082 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3083 maxfactor = ioc->spi_data.minSyncFactor;
3084 }
3085 } else
3086 maxfactor = MPT_ASYNC;
3087 }
3088
3089 /* Set the negotiation flags.
3090 */
3091 negoFlags = ioc->spi_data.noQas;
3092 if (!maxwidth)
3093 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3094
3095 if (!maxoffset)
3096 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3097
3098 if (flags & MPT_SCSICFG_USE_NVRAM) {
3099 width = maxwidth;
3100 factor = maxfactor;
3101 offset = maxoffset;
3102 } else {
3103 width = 0;
3104 factor = MPT_ASYNC;
3105 offset = 0;
3106 //negoFlags = 0;
3107 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3108 }
3109
3110 /* If id is not a raid volume, get the updated
3111 * transmission settings from the target structure.
3112 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003113 if (hd->Targets && (vtarget = hd->Targets[id]) && !vtarget->raidVolume) {
3114 width = vtarget->maxWidth;
3115 factor = vtarget->minSyncFactor;
3116 offset = vtarget->maxOffset;
3117 negoFlags = vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003119
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3121 /* Force to async and narrow if DV has not been executed
3122 * for this ID
3123 */
3124 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3125 width = 0;
3126 factor = MPT_ASYNC;
3127 offset = 0;
3128 }
3129#endif
3130
3131 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003132 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 mptscsih_setDevicePage1Flags(width, factor, offset,
3135 &requested, &configuration, negoFlags);
3136 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3137 target_id, width, factor, offset, negoFlags, requested, configuration));
3138
3139 /* Get a MF for this command.
3140 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003141 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003142 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3143 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 return -EAGAIN;
3145 }
3146
3147 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3148 hd->ioc->name, mf, id, requested, configuration));
3149
3150
3151 /* Set the request and the data pointers.
3152 * Request takes: 36 bytes (32 bit SGE)
3153 * SCSI Device Page 1 requires 16 bytes
3154 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3155 * and MF size >= 64 bytes.
3156 * Place data at end of MF.
3157 */
3158 pReq = (Config_t *)mf;
3159
3160 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3161 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3162
3163 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3164 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3165
3166 /* Complete the request frame (same for all requests).
3167 */
3168 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3169 pReq->Reserved = 0;
3170 pReq->ChainOffset = 0;
3171 pReq->Function = MPI_FUNCTION_CONFIG;
3172 pReq->ExtPageLength = 0;
3173 pReq->ExtPageType = 0;
3174 pReq->MsgFlags = 0;
3175 for (ii=0; ii < 8; ii++) {
3176 pReq->Reserved2[ii] = 0;
3177 }
3178 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3179 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3180 pReq->Header.PageNumber = 1;
3181 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3182 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3183
3184 /* Add a SGE to the config request.
3185 */
3186 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3187
3188 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3189
3190 /* Set up the common data portion
3191 */
3192 pData->Header.PageVersion = pReq->Header.PageVersion;
3193 pData->Header.PageLength = pReq->Header.PageLength;
3194 pData->Header.PageNumber = pReq->Header.PageNumber;
3195 pData->Header.PageType = pReq->Header.PageType;
3196 pData->RequestedParameters = cpu_to_le32(requested);
3197 pData->Reserved = 0;
3198 pData->Configuration = cpu_to_le32(configuration);
3199
3200 dprintk((MYIOC_s_INFO_FMT
3201 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3202 ioc->name, id, (id | (bus<<8)),
3203 requested, configuration));
3204
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003205 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
3207
3208 return 0;
3209}
3210
3211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3212/* mptscsih_writeIOCPage4 - write IOC Page 4
3213 * @hd: Pointer to a SCSI Host Structure
3214 * @target_id: write IOC Page4 for this ID & Bus
3215 *
3216 * Return: -EAGAIN if unable to obtain a Message Frame
3217 * or 0 if success.
3218 *
3219 * Remark: We do not wait for a return, write pages sequentially.
3220 */
3221static int
3222mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3223{
3224 MPT_ADAPTER *ioc = hd->ioc;
3225 Config_t *pReq;
3226 IOCPage4_t *IOCPage4Ptr;
3227 MPT_FRAME_HDR *mf;
3228 dma_addr_t dataDma;
3229 u16 req_idx;
3230 u32 frameOffset;
3231 u32 flagsLength;
3232 int ii;
3233
3234 /* Get a MF for this command.
3235 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003236 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003237 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 ioc->name));
3239 return -EAGAIN;
3240 }
3241
3242 /* Set the request and the data pointers.
3243 * Place data at end of MF.
3244 */
3245 pReq = (Config_t *)mf;
3246
3247 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3248 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3249
3250 /* Complete the request frame (same for all requests).
3251 */
3252 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3253 pReq->Reserved = 0;
3254 pReq->ChainOffset = 0;
3255 pReq->Function = MPI_FUNCTION_CONFIG;
3256 pReq->ExtPageLength = 0;
3257 pReq->ExtPageType = 0;
3258 pReq->MsgFlags = 0;
3259 for (ii=0; ii < 8; ii++) {
3260 pReq->Reserved2[ii] = 0;
3261 }
3262
3263 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3264 dataDma = ioc->spi_data.IocPg4_dma;
3265 ii = IOCPage4Ptr->ActiveSEP++;
3266 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3267 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3268 pReq->Header = IOCPage4Ptr->Header;
3269 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3270
3271 /* Add a SGE to the config request.
3272 */
3273 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3274 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3275
3276 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3277
3278 dinitprintk((MYIOC_s_INFO_FMT
3279 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3280 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3281
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003282 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
3284 return 0;
3285}
3286
3287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3288/*
3289 * Bus Scan and Domain Validation functionality ...
3290 */
3291
3292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3293/*
3294 * mptscsih_scandv_complete - Scan and DV callback routine registered
3295 * to Fustion MPT (base) driver.
3296 *
3297 * @ioc: Pointer to MPT_ADAPTER structure
3298 * @mf: Pointer to original MPT request frame
3299 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3300 *
3301 * This routine is called from mpt.c::mpt_interrupt() at the completion
3302 * of any SCSI IO request.
3303 * This routine is registered with the Fusion MPT (base) driver at driver
3304 * load/init time via the mpt_register() API call.
3305 *
3306 * Returns 1 indicating alloc'd request frame ptr should be freed.
3307 *
3308 * Remark: Sets a completion code and (possibly) saves sense data
3309 * in the IOC member localReply structure.
3310 * Used ONLY for DV and other internal commands.
3311 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003312int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3314{
3315 MPT_SCSI_HOST *hd;
3316 SCSIIORequest_t *pReq;
3317 int completionCode;
3318 u16 req_idx;
3319
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003320 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3321
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 if ((mf == NULL) ||
3323 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3324 printk(MYIOC_s_ERR_FMT
3325 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3326 ioc->name, mf?"BAD":"NULL", (void *) mf);
3327 goto wakeup;
3328 }
3329
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 del_timer(&hd->timer);
3331 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3332 hd->ScsiLookup[req_idx] = NULL;
3333 pReq = (SCSIIORequest_t *) mf;
3334
3335 if (mf != hd->cmdPtr) {
3336 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3337 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3338 }
3339 hd->cmdPtr = NULL;
3340
3341 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3342 hd->ioc->name, mf, mr, req_idx));
3343
3344 hd->pLocal = &hd->localReply;
3345 hd->pLocal->scsiStatus = 0;
3346
3347 /* If target struct exists, clear sense valid flag.
3348 */
3349 if (mr == NULL) {
3350 completionCode = MPT_SCANDV_GOOD;
3351 } else {
3352 SCSIIOReply_t *pReply;
3353 u16 status;
3354 u8 scsi_status;
3355
3356 pReply = (SCSIIOReply_t *) mr;
3357
3358 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3359 scsi_status = pReply->SCSIStatus;
3360
3361 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3362 status, pReply->SCSIState, scsi_status,
3363 le32_to_cpu(pReply->IOCLogInfo)));
3364
3365 switch(status) {
3366
3367 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3368 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3369 break;
3370
3371 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3372 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3373 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3374 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3375 completionCode = MPT_SCANDV_DID_RESET;
3376 break;
3377
3378 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3379 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3380 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3381 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3382 ConfigReply_t *pr = (ConfigReply_t *)mr;
3383 completionCode = MPT_SCANDV_GOOD;
3384 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3385 hd->pLocal->header.PageLength = pr->Header.PageLength;
3386 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3387 hd->pLocal->header.PageType = pr->Header.PageType;
3388
3389 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3390 /* If the RAID Volume request is successful,
3391 * return GOOD, else indicate that
3392 * some type of error occurred.
3393 */
3394 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003395 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 completionCode = MPT_SCANDV_GOOD;
3397 else
3398 completionCode = MPT_SCANDV_SOME_ERROR;
3399
3400 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3401 u8 *sense_data;
3402 int sz;
3403
3404 /* save sense data in global structure
3405 */
3406 completionCode = MPT_SCANDV_SENSE;
3407 hd->pLocal->scsiStatus = scsi_status;
3408 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3409 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3410
3411 sz = min_t(int, pReq->SenseBufferLength,
3412 SCSI_STD_SENSE_BYTES);
3413 memcpy(hd->pLocal->sense, sense_data, sz);
3414
3415 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3416 sense_data));
3417 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3418 if (pReq->CDB[0] == INQUIRY)
3419 completionCode = MPT_SCANDV_ISSUE_SENSE;
3420 else
3421 completionCode = MPT_SCANDV_DID_RESET;
3422 }
3423 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3424 completionCode = MPT_SCANDV_DID_RESET;
3425 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3426 completionCode = MPT_SCANDV_DID_RESET;
3427 else {
3428 completionCode = MPT_SCANDV_GOOD;
3429 hd->pLocal->scsiStatus = scsi_status;
3430 }
3431 break;
3432
3433 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3434 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3435 completionCode = MPT_SCANDV_DID_RESET;
3436 else
3437 completionCode = MPT_SCANDV_SOME_ERROR;
3438 break;
3439
3440 default:
3441 completionCode = MPT_SCANDV_SOME_ERROR;
3442 break;
3443
3444 } /* switch(status) */
3445
3446 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3447 completionCode));
3448 } /* end of address reply case */
3449
3450 hd->pLocal->completion = completionCode;
3451
3452 /* MF and RF are freed in mpt_interrupt
3453 */
3454wakeup:
3455 /* Free Chain buffers (will never chain) in scan or dv */
3456 //mptscsih_freeChainBuffers(ioc, req_idx);
3457
3458 /*
3459 * Wake up the original calling thread
3460 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003461 hd->scandv_wait_done = 1;
3462 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
3464 return 1;
3465}
3466
3467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3468/* mptscsih_timer_expired - Call back for timer process.
3469 * Used only for dv functionality.
3470 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3471 *
3472 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003473void
3474mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475{
3476 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3477
3478 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3479
3480 if (hd->cmdPtr) {
3481 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3482
3483 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3484 /* Desire to issue a task management request here.
3485 * TM requests MUST be single threaded.
3486 * If old eh code and no TM current, issue request.
3487 * If new eh code, do nothing. Wait for OS cmd timeout
3488 * for bus reset.
3489 */
3490 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3491 } else {
3492 /* Perform a FW reload */
3493 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3494 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3495 }
3496 }
3497 } else {
3498 /* This should NEVER happen */
3499 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3500 }
3501
3502 /* No more processing.
3503 * TM call will generate an interrupt for SCSI TM Management.
3504 * The FW will reply to all outstanding commands, callback will finish cleanup.
3505 * Hard reset clean-up will free all resources.
3506 */
3507 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3508
3509 return;
3510}
3511
3512#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3513/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3514/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3515 * @hd: Pointer to scsi host structure
3516 * @action: What do be done.
3517 * @id: Logical target id.
3518 * @bus: Target locations bus.
3519 *
3520 * Returns: < 0 on a fatal error
3521 * 0 on success
3522 *
3523 * Remark: Wait to return until reply processed by the ISR.
3524 */
3525static int
3526mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3527{
3528 MpiRaidActionRequest_t *pReq;
3529 MPT_FRAME_HDR *mf;
3530 int in_isr;
3531
3532 in_isr = in_interrupt();
3533 if (in_isr) {
3534 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3535 hd->ioc->name));
3536 return -EPERM;
3537 }
3538
3539 /* Get and Populate a free Frame
3540 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003541 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3543 hd->ioc->name));
3544 return -EAGAIN;
3545 }
3546 pReq = (MpiRaidActionRequest_t *)mf;
3547 pReq->Action = action;
3548 pReq->Reserved1 = 0;
3549 pReq->ChainOffset = 0;
3550 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3551 pReq->VolumeID = io->id;
3552 pReq->VolumeBus = io->bus;
3553 pReq->PhysDiskNum = io->physDiskNum;
3554 pReq->MsgFlags = 0;
3555 pReq->Reserved2 = 0;
3556 pReq->ActionDataWord = 0; /* Reserved for this action */
3557 //pReq->ActionDataSGE = 0;
3558
3559 mpt_add_sge((char *)&pReq->ActionDataSGE,
3560 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3561
3562 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3563 hd->ioc->name, action, io->id));
3564
3565 hd->pLocal = NULL;
3566 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003567 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
3569 /* Save cmd pointer, for resource free if timeout or
3570 * FW reload occurs
3571 */
3572 hd->cmdPtr = mf;
3573
3574 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003575 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3576 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
3578 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3579 return -1;
3580
3581 return 0;
3582}
3583#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3584
3585/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3586/**
3587 * mptscsih_do_cmd - Do internal command.
3588 * @hd: MPT_SCSI_HOST pointer
3589 * @io: INTERNAL_CMD pointer.
3590 *
3591 * Issue the specified internally generated command and do command
3592 * specific cleanup. For bus scan / DV only.
3593 * NOTES: If command is Inquiry and status is good,
3594 * initialize a target structure, save the data
3595 *
3596 * Remark: Single threaded access only.
3597 *
3598 * Return:
3599 * < 0 if an illegal command or no resources
3600 *
3601 * 0 if good
3602 *
3603 * > 0 if command complete but some type of completion error.
3604 */
3605static int
3606mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3607{
3608 MPT_FRAME_HDR *mf;
3609 SCSIIORequest_t *pScsiReq;
3610 SCSIIORequest_t ReqCopy;
3611 int my_idx, ii, dir;
3612 int rc, cmdTimeout;
3613 int in_isr;
3614 char cmdLen;
3615 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3616 char cmd = io->cmd;
3617
3618 in_isr = in_interrupt();
3619 if (in_isr) {
3620 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3621 hd->ioc->name));
3622 return -EPERM;
3623 }
3624
3625
3626 /* Set command specific information
3627 */
3628 switch (cmd) {
3629 case INQUIRY:
3630 cmdLen = 6;
3631 dir = MPI_SCSIIO_CONTROL_READ;
3632 CDB[0] = cmd;
3633 CDB[4] = io->size;
3634 cmdTimeout = 10;
3635 break;
3636
3637 case TEST_UNIT_READY:
3638 cmdLen = 6;
3639 dir = MPI_SCSIIO_CONTROL_READ;
3640 cmdTimeout = 10;
3641 break;
3642
3643 case START_STOP:
3644 cmdLen = 6;
3645 dir = MPI_SCSIIO_CONTROL_READ;
3646 CDB[0] = cmd;
3647 CDB[4] = 1; /*Spin up the disk */
3648 cmdTimeout = 15;
3649 break;
3650
3651 case REQUEST_SENSE:
3652 cmdLen = 6;
3653 CDB[0] = cmd;
3654 CDB[4] = io->size;
3655 dir = MPI_SCSIIO_CONTROL_READ;
3656 cmdTimeout = 10;
3657 break;
3658
3659 case READ_BUFFER:
3660 cmdLen = 10;
3661 dir = MPI_SCSIIO_CONTROL_READ;
3662 CDB[0] = cmd;
3663 if (io->flags & MPT_ICFLAG_ECHO) {
3664 CDB[1] = 0x0A;
3665 } else {
3666 CDB[1] = 0x02;
3667 }
3668
3669 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3670 CDB[1] |= 0x01;
3671 }
3672 CDB[6] = (io->size >> 16) & 0xFF;
3673 CDB[7] = (io->size >> 8) & 0xFF;
3674 CDB[8] = io->size & 0xFF;
3675 cmdTimeout = 10;
3676 break;
3677
3678 case WRITE_BUFFER:
3679 cmdLen = 10;
3680 dir = MPI_SCSIIO_CONTROL_WRITE;
3681 CDB[0] = cmd;
3682 if (io->flags & MPT_ICFLAG_ECHO) {
3683 CDB[1] = 0x0A;
3684 } else {
3685 CDB[1] = 0x02;
3686 }
3687 CDB[6] = (io->size >> 16) & 0xFF;
3688 CDB[7] = (io->size >> 8) & 0xFF;
3689 CDB[8] = io->size & 0xFF;
3690 cmdTimeout = 10;
3691 break;
3692
3693 case RESERVE:
3694 cmdLen = 6;
3695 dir = MPI_SCSIIO_CONTROL_READ;
3696 CDB[0] = cmd;
3697 cmdTimeout = 10;
3698 break;
3699
3700 case RELEASE:
3701 cmdLen = 6;
3702 dir = MPI_SCSIIO_CONTROL_READ;
3703 CDB[0] = cmd;
3704 cmdTimeout = 10;
3705 break;
3706
3707 case SYNCHRONIZE_CACHE:
3708 cmdLen = 10;
3709 dir = MPI_SCSIIO_CONTROL_READ;
3710 CDB[0] = cmd;
3711// CDB[1] = 0x02; /* set immediate bit */
3712 cmdTimeout = 10;
3713 break;
3714
3715 default:
3716 /* Error Case */
3717 return -EFAULT;
3718 }
3719
3720 /* Get and Populate a free Frame
3721 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003722 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3724 hd->ioc->name));
3725 return -EBUSY;
3726 }
3727
3728 pScsiReq = (SCSIIORequest_t *) mf;
3729
3730 /* Get the request index */
3731 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3732 ADD_INDEX_LOG(my_idx); /* for debug */
3733
3734 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3735 pScsiReq->TargetID = io->physDiskNum;
3736 pScsiReq->Bus = 0;
3737 pScsiReq->ChainOffset = 0;
3738 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3739 } else {
3740 pScsiReq->TargetID = io->id;
3741 pScsiReq->Bus = io->bus;
3742 pScsiReq->ChainOffset = 0;
3743 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3744 }
3745
3746 pScsiReq->CDBLength = cmdLen;
3747 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3748
3749 pScsiReq->Reserved = 0;
3750
3751 pScsiReq->MsgFlags = mpt_msg_flags();
3752 /* MsgContext set in mpt_get_msg_fram call */
3753
3754 for (ii=0; ii < 8; ii++)
3755 pScsiReq->LUN[ii] = 0;
3756 pScsiReq->LUN[1] = io->lun;
3757
3758 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3759 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3760 else
3761 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3762
3763 if (cmd == REQUEST_SENSE) {
3764 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3765 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3766 hd->ioc->name, cmd));
3767 }
3768
3769 for (ii=0; ii < 16; ii++)
3770 pScsiReq->CDB[ii] = CDB[ii];
3771
3772 pScsiReq->DataLength = cpu_to_le32(io->size);
3773 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3774 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3775
3776 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3777 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3778
3779 if (dir == MPI_SCSIIO_CONTROL_READ) {
3780 mpt_add_sge((char *) &pScsiReq->SGL,
3781 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3782 io->data_dma);
3783 } else {
3784 mpt_add_sge((char *) &pScsiReq->SGL,
3785 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3786 io->data_dma);
3787 }
3788
3789 /* The ISR will free the request frame, but we need
3790 * the information to initialize the target. Duplicate.
3791 */
3792 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3793
3794 /* Issue this command after:
3795 * finish init
3796 * add timer
3797 * Wait until the reply has been received
3798 * ScsiScanDvCtx callback function will
3799 * set hd->pLocal;
3800 * set scandv_wait_done and call wake_up
3801 */
3802 hd->pLocal = NULL;
3803 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003804 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
3806 /* Save cmd pointer, for resource free if timeout or
3807 * FW reload occurs
3808 */
3809 hd->cmdPtr = mf;
3810
3811 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003812 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3813 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
3815 if (hd->pLocal) {
3816 rc = hd->pLocal->completion;
3817 hd->pLocal->skip = 0;
3818
3819 /* Always set fatal error codes in some cases.
3820 */
3821 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3822 rc = -ENXIO;
3823 else if (rc == MPT_SCANDV_SOME_ERROR)
3824 rc = -rc;
3825 } else {
3826 rc = -EFAULT;
3827 /* This should never happen. */
3828 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3829 hd->ioc->name));
3830 }
3831
3832 return rc;
3833}
3834
3835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3836/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003837 * mptscsih_negotiate_to_asyn_narrow - Restore devices to default state
3838 * @hd: Pointer to a SCSI HOST structure
3839 * @vtarget: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 *
3841 * Uses the ISR, but with special processing.
3842 * MUST be single-threaded.
3843 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003845static void
3846mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847{
3848 MPT_ADAPTER *ioc= hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003849 SCSIDevicePage1_t *pcfg1Data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 CONFIGPARMS cfg;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003851 dma_addr_t cfg1_dma_addr;
3852 ConfigPageHeader_t header;
3853 int id;
3854 int requested, configuration, data,i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 u8 flags, factor;
3856
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003857 if (ioc->bus_type != SPI)
3858 return;
3859
3860 if (!ioc->spi_data.sdp1length)
3861 return;
3862
3863 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3864 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3865
3866 if (pcfg1Data == NULL)
3867 return;
3868
3869 header.PageVersion = ioc->spi_data.sdp1version;
3870 header.PageLength = ioc->spi_data.sdp1length;
3871 header.PageNumber = 1;
3872 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3873 cfg.cfghdr.hdr = &header;
3874 cfg.physAddr = cfg1_dma_addr;
3875 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3876 cfg.dir = 1;
3877 cfg.timeout = 0;
3878
3879 if (vtarget->raidVolume && ioc->raid_data.pIocPg3) {
3880 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3881 id = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID;
3882 flags = hd->ioc->spi_data.noQas;
3883 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3884 data = hd->ioc->spi_data.nvram[id];
3885 if (data & MPT_NVRAM_WIDE_DISABLE)
3886 flags |= MPT_TARGET_NO_NEGO_WIDE;
3887 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
3888 if ((factor == 0) || (factor == MPT_ASYNC))
3889 flags |= MPT_TARGET_NO_NEGO_SYNC;
3890 }
3891 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3892 &configuration, flags);
3893 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3894 "offset=0 negoFlags=%x request=%x config=%x\n",
3895 id, flags, requested, configuration));
3896 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3897 pcfg1Data->Reserved = 0;
3898 pcfg1Data->Configuration = cpu_to_le32(configuration);
3899 cfg.pageAddr = (vtarget->bus_id<<8) | id;
3900 mpt_config(hd->ioc, &cfg);
3901 }
3902 } else {
3903 flags = vtarget->negoFlags;
3904 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3905 &configuration, flags);
3906 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3907 "offset=0 negoFlags=%x request=%x config=%x\n",
3908 vtarget->target_id, flags, requested, configuration));
3909 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3910 pcfg1Data->Reserved = 0;
3911 pcfg1Data->Configuration = cpu_to_le32(configuration);
3912 cfg.pageAddr = (vtarget->bus_id<<8) | vtarget->target_id;
3913 mpt_config(hd->ioc, &cfg);
3914 }
3915
3916 if (pcfg1Data)
3917 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr);
3918}
3919
3920/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3921/**
3922 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3923 * @hd: Pointer to a SCSI HOST structure
3924 * @vtarget: per device private data
3925 * @lun: lun
3926 *
3927 * Uses the ISR, but with special processing.
3928 * MUST be single-threaded.
3929 *
3930 */
3931static void
3932mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3933{
3934 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
3936 /* Following parameters will not change
3937 * in this routine.
3938 */
3939 iocmd.cmd = SYNCHRONIZE_CACHE;
3940 iocmd.flags = 0;
3941 iocmd.physDiskNum = -1;
3942 iocmd.data = NULL;
3943 iocmd.data_dma = -1;
3944 iocmd.size = 0;
3945 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003946 iocmd.bus = vdevice->bus_id;
3947 iocmd.id = vdevice->target_id;
3948 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003950 if ((vdevice->vtarget->type & TYPE_DISK) &&
3951 (vdevice->configured_lun))
3952 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953}
3954
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07003955/* Search IOC page 3 to determine if this is hidden physical disk
3956 */
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07003957static int
3958mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
3959{
3960 int i;
3961
3962 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
3963 return 0;
3964
3965 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3966 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
3967 return 1;
3968 }
3969
3970 return 0;
3971}
3972
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3974/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3975/**
3976 * mptscsih_domainValidation - Top level handler for domain validation.
3977 * @hd: Pointer to MPT_SCSI_HOST structure.
3978 *
3979 * Uses the ISR, but with special processing.
3980 * Called from schedule, should not be in interrupt mode.
3981 * While thread alive, do dv for all devices needing dv
3982 *
3983 * Return: None.
3984 */
3985static void
3986mptscsih_domainValidation(void *arg)
3987{
3988 MPT_SCSI_HOST *hd;
3989 MPT_ADAPTER *ioc;
3990 unsigned long flags;
3991 int id, maxid, dvStatus, did;
3992 int ii, isPhysDisk;
3993
3994 spin_lock_irqsave(&dvtaskQ_lock, flags);
3995 dvtaskQ_active = 1;
3996 if (dvtaskQ_release) {
3997 dvtaskQ_active = 0;
3998 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
3999 return;
4000 }
4001 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4002
4003 /* For this ioc, loop through all devices and do dv to each device.
4004 * When complete with this ioc, search through the ioc list, and
4005 * for each scsi ioc found, do dv for all devices. Exit when no
4006 * device needs dv.
4007 */
4008 did = 1;
4009 while (did) {
4010 did = 0;
4011 list_for_each_entry(ioc, &ioc_list, list) {
4012 spin_lock_irqsave(&dvtaskQ_lock, flags);
4013 if (dvtaskQ_release) {
4014 dvtaskQ_active = 0;
4015 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4016 return;
4017 }
4018 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4019
4020 msleep(250);
4021
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004022 /* DV only to SPI adapters */
4023 if (ioc->bus_type != SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 continue;
4025
4026 /* Make sure everything looks ok */
4027 if (ioc->sh == NULL)
4028 continue;
4029
4030 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4031 if (hd == NULL)
4032 continue;
4033
4034 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4035 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004036 if (ioc->raid_data.pIocPg3) {
4037 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4038 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039
4040 while (numPDisk) {
4041 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4042 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4043
4044 pPDisk++;
4045 numPDisk--;
4046 }
4047 }
4048 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4049 }
4050
4051 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4052
4053 for (id = 0; id < maxid; id++) {
4054 spin_lock_irqsave(&dvtaskQ_lock, flags);
4055 if (dvtaskQ_release) {
4056 dvtaskQ_active = 0;
4057 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4058 return;
4059 }
4060 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4061 dvStatus = hd->ioc->spi_data.dvStatus[id];
4062
4063 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4064 did++;
4065 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4066 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4067
4068 msleep(250);
4069
4070 /* If hidden phys disk, block IO's to all
4071 * raid volumes
4072 * else, process normally
4073 */
4074 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4075 if (isPhysDisk) {
4076 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004077 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4079 }
4080 }
4081 }
4082
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004083 if(mpt_alt_ioc_wait(hd->ioc)!=0) {
4084 ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
4085 hd->ioc->name));
4086 continue;
4087 }
4088
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 if (mptscsih_doDv(hd, 0, id) == 1) {
4090 /* Untagged device was busy, try again
4091 */
4092 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4093 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4094 } else {
4095 /* DV is complete. Clear flags.
4096 */
4097 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4098 }
4099
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004100 spin_lock(&hd->ioc->initializing_hba_lock);
4101 hd->ioc->initializing_hba_lock_flag=0;
4102 spin_unlock(&hd->ioc->initializing_hba_lock);
4103
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 if (isPhysDisk) {
4105 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004106 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4108 }
4109 }
4110 }
4111
4112 if (hd->ioc->spi_data.noQas)
4113 mptscsih_qas_check(hd, id);
4114 }
4115 }
4116 }
4117 }
4118
4119 spin_lock_irqsave(&dvtaskQ_lock, flags);
4120 dvtaskQ_active = 0;
4121 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4122
4123 return;
4124}
4125
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126/* Write SDP1 if no QAS has been enabled
4127 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004128static void
4129mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004131 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 int ii;
4133
4134 if (hd->Targets == NULL)
4135 return;
4136
4137 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4138 if (ii == id)
4139 continue;
4140
4141 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4142 continue;
4143
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004144 vtarget = hd->Targets[ii];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004146 if ((vtarget != NULL) && (!vtarget->raidVolume)) {
4147 if ((vtarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4148 vtarget->negoFlags |= hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4150 mptscsih_writeSDP1(hd, 0, ii, 0);
4151 }
4152 } else {
4153 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4154 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4155 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4156 }
4157 }
4158 }
4159 return;
4160}
4161
4162
4163
4164#define MPT_GET_NVRAM_VALS 0x01
4165#define MPT_UPDATE_MAX 0x02
4166#define MPT_SET_MAX 0x04
4167#define MPT_SET_MIN 0x08
4168#define MPT_FALLBACK 0x10
4169#define MPT_SAVE 0x20
4170
4171/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4172/**
4173 * mptscsih_doDv - Perform domain validation to a target.
4174 * @hd: Pointer to MPT_SCSI_HOST structure.
4175 * @portnum: IOC port number.
4176 * @target: Physical ID of this target
4177 *
4178 * Uses the ISR, but with special processing.
4179 * MUST be single-threaded.
4180 * Test will exit if target is at async & narrow.
4181 *
4182 * Return: None.
4183 */
4184static int
4185mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4186{
4187 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004188 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 SCSIDevicePage1_t *pcfg1Data;
4190 SCSIDevicePage0_t *pcfg0Data;
4191 u8 *pbuf1;
4192 u8 *pbuf2;
4193 u8 *pDvBuf;
4194 dma_addr_t dvbuf_dma = -1;
4195 dma_addr_t buf1_dma = -1;
4196 dma_addr_t buf2_dma = -1;
4197 dma_addr_t cfg1_dma_addr = -1;
4198 dma_addr_t cfg0_dma_addr = -1;
4199 ConfigPageHeader_t header1;
4200 ConfigPageHeader_t header0;
4201 DVPARAMETERS dv;
4202 INTERNAL_CMD iocmd;
4203 CONFIGPARMS cfg;
4204 int dv_alloc = 0;
4205 int rc, sz = 0;
4206 int bufsize = 0;
4207 int dataBufSize = 0;
4208 int echoBufSize = 0;
4209 int notDone;
4210 int patt;
4211 int repeat;
4212 int retcode = 0;
4213 int nfactor = MPT_ULTRA320;
4214 char firstPass = 1;
4215 char doFallback = 0;
4216 char readPage0;
4217 char bus, lun;
4218 char inq0 = 0;
4219
4220 if (ioc->spi_data.sdp1length == 0)
4221 return 0;
4222
4223 if (ioc->spi_data.sdp0length == 0)
4224 return 0;
4225
4226 /* If multiple buses are used, require that the initiator
4227 * id be the same on all buses.
4228 */
4229 if (id == ioc->pfacts[0].PortSCSIID)
4230 return 0;
4231
4232 lun = 0;
4233 bus = (u8) bus_number;
4234 ddvtprintk((MYIOC_s_NOTE_FMT
4235 "DV started: bus=%d, id=%d dv @ %p\n",
4236 ioc->name, bus, id, &dv));
4237
4238 /* Prep DV structure
4239 */
4240 memset (&dv, 0, sizeof(DVPARAMETERS));
4241 dv.id = id;
4242
4243 /* Populate tmax with the current maximum
4244 * transfer parameters for this target.
4245 * Exit if narrow and async.
4246 */
4247 dv.cmd = MPT_GET_NVRAM_VALS;
4248 mptscsih_dv_parms(hd, &dv, NULL);
4249
4250 /* Prep SCSI IO structure
4251 */
4252 iocmd.id = id;
4253 iocmd.bus = bus;
4254 iocmd.lun = lun;
4255 iocmd.flags = 0;
4256 iocmd.physDiskNum = -1;
4257 iocmd.rsvd = iocmd.rsvd2 = 0;
4258
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004259 vtarget = hd->Targets[id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
4261 /* Use tagged commands if possible.
4262 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004263 if (vtarget) {
4264 if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4266 else {
4267 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4268 return 0;
4269
4270 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4271 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4272 return 0;
4273 }
4274 }
4275
4276 /* Prep cfg structure
4277 */
4278 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004279 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
4281 /* Prep SDP0 header
4282 */
4283 header0.PageVersion = ioc->spi_data.sdp0version;
4284 header0.PageLength = ioc->spi_data.sdp0length;
4285 header0.PageNumber = 0;
4286 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4287
4288 /* Prep SDP1 header
4289 */
4290 header1.PageVersion = ioc->spi_data.sdp1version;
4291 header1.PageLength = ioc->spi_data.sdp1length;
4292 header1.PageNumber = 1;
4293 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4294
4295 if (header0.PageLength & 1)
4296 dv_alloc = (header0.PageLength * 4) + 4;
4297
4298 dv_alloc += (2048 + (header1.PageLength * 4));
4299
4300 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4301 if (pDvBuf == NULL)
4302 return 0;
4303
4304 sz = 0;
4305 pbuf1 = (u8 *)pDvBuf;
4306 buf1_dma = dvbuf_dma;
4307 sz +=1024;
4308
4309 pbuf2 = (u8 *) (pDvBuf + sz);
4310 buf2_dma = dvbuf_dma + sz;
4311 sz +=1024;
4312
4313 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4314 cfg0_dma_addr = dvbuf_dma + sz;
4315 sz += header0.PageLength * 4;
4316
4317 /* 8-byte alignment
4318 */
4319 if (header0.PageLength & 1)
4320 sz += 4;
4321
4322 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4323 cfg1_dma_addr = dvbuf_dma + sz;
4324
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004325 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 */
4327 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004328 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4330 /* Set the factor from nvram */
4331 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4332 if (nfactor < pspi_data->minSyncFactor )
4333 nfactor = pspi_data->minSyncFactor;
4334
4335 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4336 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4337
4338 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4339 ioc->name, bus, id, lun));
4340
4341 dv.cmd = MPT_SET_MAX;
4342 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004343 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
4345 /* Save the final negotiated settings to
4346 * SCSI device page 1.
4347 */
4348 cfg.physAddr = cfg1_dma_addr;
4349 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4350 cfg.dir = 1;
4351 mpt_config(hd->ioc, &cfg);
4352 goto target_done;
4353 }
4354 }
4355 }
4356
4357 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004358 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 /* Search IOC page 3 for matching id
4360 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004361 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4362 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363
4364 while (numPDisk) {
4365 if (pPDisk->PhysDiskID == id) {
4366 /* match */
4367 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4368 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4369
4370 /* Quiesce the IM
4371 */
4372 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4373 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4374 goto target_done;
4375 }
4376 break;
4377 }
4378 pPDisk++;
4379 numPDisk--;
4380 }
4381 }
4382
4383 /* RAID Volume ID's may double for a physical device. If RAID but
4384 * not a physical ID as well, skip DV.
4385 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004386 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 goto target_done;
4388
4389
4390 /* Basic Test.
4391 * Async & Narrow - Inquiry
4392 * Async & Narrow - Inquiry
4393 * Maximum transfer rate - Inquiry
4394 * Compare buffers:
4395 * If compare, test complete.
4396 * If miscompare and first pass, repeat
4397 * If miscompare and not first pass, fall back and repeat
4398 */
4399 hd->pLocal = NULL;
4400 readPage0 = 0;
4401 sz = SCSI_MAX_INQUIRY_BYTES;
4402 rc = MPT_SCANDV_GOOD;
4403 while (1) {
4404 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4405 retcode = 0;
4406 dv.cmd = MPT_SET_MIN;
4407 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4408
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004409 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 cfg.physAddr = cfg1_dma_addr;
4411 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4412 cfg.dir = 1;
4413 if (mpt_config(hd->ioc, &cfg) != 0)
4414 goto target_done;
4415
4416 /* Wide - narrow - wide workaround case
4417 */
4418 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4419 /* Send an untagged command to reset disk Qs corrupted
4420 * when a parity error occurs on a Request Sense.
4421 */
4422 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4423 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4424 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4425
4426 iocmd.cmd = REQUEST_SENSE;
4427 iocmd.data_dma = buf1_dma;
4428 iocmd.data = pbuf1;
4429 iocmd.size = 0x12;
4430 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4431 goto target_done;
4432 else {
4433 if (hd->pLocal == NULL)
4434 goto target_done;
4435 rc = hd->pLocal->completion;
4436 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4437 dv.max.width = 0;
4438 doFallback = 0;
4439 } else
4440 goto target_done;
4441 }
4442 } else
4443 goto target_done;
4444 }
4445
4446 iocmd.cmd = INQUIRY;
4447 iocmd.data_dma = buf1_dma;
4448 iocmd.data = pbuf1;
4449 iocmd.size = sz;
4450 memset(pbuf1, 0x00, sz);
4451 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4452 goto target_done;
4453 else {
4454 if (hd->pLocal == NULL)
4455 goto target_done;
4456 rc = hd->pLocal->completion;
4457 if (rc == MPT_SCANDV_GOOD) {
4458 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4459 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4460 retcode = 1;
4461 else
4462 retcode = 0;
4463
4464 goto target_done;
4465 }
4466 } else if (rc == MPT_SCANDV_SENSE) {
4467 ;
4468 } else {
4469 /* If first command doesn't complete
4470 * with a good status or with a check condition,
4471 * exit.
4472 */
4473 goto target_done;
4474 }
4475 }
4476
4477 /* Reset the size for disks
4478 */
4479 inq0 = (*pbuf1) & 0x1F;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004480 if ((inq0 == 0) && vtarget && !vtarget->raidVolume) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 sz = 0x40;
4482 iocmd.size = sz;
4483 }
4484
4485 /* Another GEM workaround. Check peripheral device type,
4486 * if PROCESSOR, quit DV.
4487 */
4488 if (inq0 == TYPE_PROCESSOR) {
4489 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004490 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 lun,
4492 pbuf1,
4493 sz);
4494 goto target_done;
4495 }
4496
4497 if (inq0 > 0x08)
4498 goto target_done;
4499
4500 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4501 goto target_done;
4502
4503 if (sz == 0x40) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004504 if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A)
4505 && (vtarget->minSyncFactor > 0x09)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 if ((pbuf1[56] & 0x04) == 0)
4507 ;
4508 else if ((pbuf1[56] & 0x01) == 1) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004509 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4511 } else {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004512 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4514 }
4515
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004516 dv.max.factor = vtarget->minSyncFactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517
4518 if ((pbuf1[56] & 0x02) == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004519 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004521 ddvprintk((MYIOC_s_NOTE_FMT
4522 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 ioc->name, id, pbuf1[56]));
4524 }
4525 }
4526 }
4527
4528 if (doFallback)
4529 dv.cmd = MPT_FALLBACK;
4530 else
4531 dv.cmd = MPT_SET_MAX;
4532
4533 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4534 if (mpt_config(hd->ioc, &cfg) != 0)
4535 goto target_done;
4536
4537 if ((!dv.now.width) && (!dv.now.offset))
4538 goto target_done;
4539
4540 iocmd.cmd = INQUIRY;
4541 iocmd.data_dma = buf2_dma;
4542 iocmd.data = pbuf2;
4543 iocmd.size = sz;
4544 memset(pbuf2, 0x00, sz);
4545 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4546 goto target_done;
4547 else if (hd->pLocal == NULL)
4548 goto target_done;
4549 else {
4550 /* Save the return code.
4551 * If this is the first pass,
4552 * read SCSI Device Page 0
4553 * and update the target max parameters.
4554 */
4555 rc = hd->pLocal->completion;
4556 doFallback = 0;
4557 if (rc == MPT_SCANDV_GOOD) {
4558 if (!readPage0) {
4559 u32 sdp0_info;
4560 u32 sdp0_nego;
4561
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004562 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 cfg.physAddr = cfg0_dma_addr;
4564 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4565 cfg.dir = 0;
4566
4567 if (mpt_config(hd->ioc, &cfg) != 0)
4568 goto target_done;
4569
4570 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4571 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4572
4573 /* Quantum and Fujitsu workarounds.
4574 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4575 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4576 * Resetart with a request for U160.
4577 */
4578 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4579 doFallback = 1;
4580 } else {
4581 dv.cmd = MPT_UPDATE_MAX;
4582 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4583 /* Update the SCSI device page 1 area
4584 */
4585 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4586 readPage0 = 1;
4587 }
4588 }
4589
4590 /* Quantum workaround. Restart this test will the fallback
4591 * flag set.
4592 */
4593 if (doFallback == 0) {
4594 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4595 if (!firstPass)
4596 doFallback = 1;
4597 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004598 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4600 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4601 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004602 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 lun,
4604 pbuf1,
4605 sz);
4606 break; /* test complete */
4607 }
4608 }
4609
4610
4611 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4612 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004613 else if ((rc == MPT_SCANDV_DID_RESET) ||
4614 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 (rc == MPT_SCANDV_FALLBACK))
4616 doFallback = 1; /* set fallback flag */
4617 else
4618 goto target_done;
4619
4620 firstPass = 0;
4621 }
4622 }
4623 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4624
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004625 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 goto target_done;
4627
4628 inq0 = (*pbuf1) & 0x1F;
4629
4630 /* Continue only for disks
4631 */
4632 if (inq0 != 0)
4633 goto target_done;
4634
4635 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4636 goto target_done;
4637
4638 /* Start the Enhanced Test.
4639 * 0) issue TUR to clear out check conditions
4640 * 1) read capacity of echo (regular) buffer
4641 * 2) reserve device
4642 * 3) do write-read-compare data pattern test
4643 * 4) release
4644 * 5) update nego parms to target struct
4645 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004646 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 cfg.physAddr = cfg1_dma_addr;
4648 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4649 cfg.dir = 1;
4650
4651 iocmd.cmd = TEST_UNIT_READY;
4652 iocmd.data_dma = -1;
4653 iocmd.data = NULL;
4654 iocmd.size = 0;
4655 notDone = 1;
4656 while (notDone) {
4657 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4658 goto target_done;
4659
4660 if (hd->pLocal == NULL)
4661 goto target_done;
4662
4663 rc = hd->pLocal->completion;
4664 if (rc == MPT_SCANDV_GOOD)
4665 notDone = 0;
4666 else if (rc == MPT_SCANDV_SENSE) {
4667 u8 skey = hd->pLocal->sense[2] & 0x0F;
4668 u8 asc = hd->pLocal->sense[12];
4669 u8 ascq = hd->pLocal->sense[13];
4670 ddvprintk((MYIOC_s_INFO_FMT
4671 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4672 ioc->name, skey, asc, ascq));
4673
4674 if (skey == UNIT_ATTENTION)
4675 notDone++; /* repeat */
4676 else if ((skey == NOT_READY) &&
4677 (asc == 0x04)&&(ascq == 0x01)) {
4678 /* wait then repeat */
4679 mdelay (2000);
4680 notDone++;
4681 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4682 /* no medium, try read test anyway */
4683 notDone = 0;
4684 } else {
4685 /* All other errors are fatal.
4686 */
4687 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4688 ioc->name));
4689 goto target_done;
4690 }
4691 } else
4692 goto target_done;
4693 }
4694
4695 iocmd.cmd = READ_BUFFER;
4696 iocmd.data_dma = buf1_dma;
4697 iocmd.data = pbuf1;
4698 iocmd.size = 4;
4699 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4700
4701 dataBufSize = 0;
4702 echoBufSize = 0;
4703 for (patt = 0; patt < 2; patt++) {
4704 if (patt == 0)
4705 iocmd.flags |= MPT_ICFLAG_ECHO;
4706 else
4707 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4708
4709 notDone = 1;
4710 while (notDone) {
4711 bufsize = 0;
4712
4713 /* If not ready after 8 trials,
4714 * give up on this device.
4715 */
4716 if (notDone > 8)
4717 goto target_done;
4718
4719 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4720 goto target_done;
4721 else if (hd->pLocal == NULL)
4722 goto target_done;
4723 else {
4724 rc = hd->pLocal->completion;
4725 ddvprintk(("ReadBuffer Comp Code %d", rc));
4726 ddvprintk((" buff: %0x %0x %0x %0x\n",
4727 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4728
4729 if (rc == MPT_SCANDV_GOOD) {
4730 notDone = 0;
4731 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4732 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004733 if (pbuf1[0] & 0x01)
4734 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 } else {
4736 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4737 }
4738 } else if (rc == MPT_SCANDV_SENSE) {
4739 u8 skey = hd->pLocal->sense[2] & 0x0F;
4740 u8 asc = hd->pLocal->sense[12];
4741 u8 ascq = hd->pLocal->sense[13];
4742 ddvprintk((MYIOC_s_INFO_FMT
4743 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4744 ioc->name, skey, asc, ascq));
4745 if (skey == ILLEGAL_REQUEST) {
4746 notDone = 0;
4747 } else if (skey == UNIT_ATTENTION) {
4748 notDone++; /* repeat */
4749 } else if ((skey == NOT_READY) &&
4750 (asc == 0x04)&&(ascq == 0x01)) {
4751 /* wait then repeat */
4752 mdelay (2000);
4753 notDone++;
4754 } else {
4755 /* All other errors are fatal.
4756 */
4757 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4758 ioc->name));
4759 goto target_done;
4760 }
4761 } else {
4762 /* All other errors are fatal
4763 */
4764 goto target_done;
4765 }
4766 }
4767 }
4768
4769 if (iocmd.flags & MPT_ICFLAG_ECHO)
4770 echoBufSize = bufsize;
4771 else
4772 dataBufSize = bufsize;
4773 }
4774 sz = 0;
4775 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4776
4777 /* Use echo buffers if possible,
4778 * Exit if both buffers are 0.
4779 */
4780 if (echoBufSize > 0) {
4781 iocmd.flags |= MPT_ICFLAG_ECHO;
4782 if (dataBufSize > 0)
4783 bufsize = min(echoBufSize, dataBufSize);
4784 else
4785 bufsize = echoBufSize;
4786 } else if (dataBufSize == 0)
4787 goto target_done;
4788
4789 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4790 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4791
4792 /* Data buffers for write-read-compare test max 1K.
4793 */
4794 sz = min(bufsize, 1024);
4795
4796 /* --- loop ----
4797 * On first pass, always issue a reserve.
4798 * On additional loops, only if a reset has occurred.
4799 * iocmd.flags indicates if echo or regular buffer
4800 */
4801 for (patt = 0; patt < 4; patt++) {
4802 ddvprintk(("Pattern %d\n", patt));
4803 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4804 iocmd.cmd = TEST_UNIT_READY;
4805 iocmd.data_dma = -1;
4806 iocmd.data = NULL;
4807 iocmd.size = 0;
4808 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4809 goto target_done;
4810
4811 iocmd.cmd = RELEASE;
4812 iocmd.data_dma = -1;
4813 iocmd.data = NULL;
4814 iocmd.size = 0;
4815 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4816 goto target_done;
4817 else if (hd->pLocal == NULL)
4818 goto target_done;
4819 else {
4820 rc = hd->pLocal->completion;
4821 ddvprintk(("Release rc %d\n", rc));
4822 if (rc == MPT_SCANDV_GOOD)
4823 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4824 else
4825 goto target_done;
4826 }
4827 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4828 }
4829 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4830
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004831 if (iocmd.flags & MPT_ICFLAG_EBOS)
4832 goto skip_Reserve;
4833
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 repeat = 5;
4835 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4836 iocmd.cmd = RESERVE;
4837 iocmd.data_dma = -1;
4838 iocmd.data = NULL;
4839 iocmd.size = 0;
4840 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4841 goto target_done;
4842 else if (hd->pLocal == NULL)
4843 goto target_done;
4844 else {
4845 rc = hd->pLocal->completion;
4846 if (rc == MPT_SCANDV_GOOD) {
4847 iocmd.flags |= MPT_ICFLAG_RESERVED;
4848 } else if (rc == MPT_SCANDV_SENSE) {
4849 /* Wait if coming ready
4850 */
4851 u8 skey = hd->pLocal->sense[2] & 0x0F;
4852 u8 asc = hd->pLocal->sense[12];
4853 u8 ascq = hd->pLocal->sense[13];
4854 ddvprintk((MYIOC_s_INFO_FMT
4855 "DV: Reserve Failed: ", ioc->name));
4856 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4857 skey, asc, ascq));
4858
4859 if ((skey == NOT_READY) && (asc == 0x04)&&
4860 (ascq == 0x01)) {
4861 /* wait then repeat */
4862 mdelay (2000);
4863 notDone++;
4864 } else {
4865 ddvprintk((MYIOC_s_INFO_FMT
4866 "DV: Reserved Failed.", ioc->name));
4867 goto target_done;
4868 }
4869 } else {
4870 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4871 ioc->name));
4872 goto target_done;
4873 }
4874 }
4875 }
4876
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004877skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4879 iocmd.cmd = WRITE_BUFFER;
4880 iocmd.data_dma = buf1_dma;
4881 iocmd.data = pbuf1;
4882 iocmd.size = sz;
4883 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4884 goto target_done;
4885 else if (hd->pLocal == NULL)
4886 goto target_done;
4887 else {
4888 rc = hd->pLocal->completion;
4889 if (rc == MPT_SCANDV_GOOD)
4890 ; /* Issue read buffer */
4891 else if (rc == MPT_SCANDV_DID_RESET) {
4892 /* If using echo buffers, reset to data buffers.
4893 * Else do Fallback and restart
4894 * this test (re-issue reserve
4895 * because of bus reset).
4896 */
4897 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4898 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4899 } else {
4900 dv.cmd = MPT_FALLBACK;
4901 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4902
4903 if (mpt_config(hd->ioc, &cfg) != 0)
4904 goto target_done;
4905
4906 if ((!dv.now.width) && (!dv.now.offset))
4907 goto target_done;
4908 }
4909
4910 iocmd.flags |= MPT_ICFLAG_DID_RESET;
4911 patt = -1;
4912 continue;
4913 } else if (rc == MPT_SCANDV_SENSE) {
4914 /* Restart data test if UA, else quit.
4915 */
4916 u8 skey = hd->pLocal->sense[2] & 0x0F;
4917 ddvprintk((MYIOC_s_INFO_FMT
4918 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
4919 hd->pLocal->sense[12], hd->pLocal->sense[13]));
4920 if (skey == UNIT_ATTENTION) {
4921 patt = -1;
4922 continue;
4923 } else if (skey == ILLEGAL_REQUEST) {
4924 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4925 if (dataBufSize >= bufsize) {
4926 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4927 patt = -1;
4928 continue;
4929 }
4930 }
4931 goto target_done;
4932 }
4933 else
4934 goto target_done;
4935 } else {
4936 /* fatal error */
4937 goto target_done;
4938 }
4939 }
4940
4941 iocmd.cmd = READ_BUFFER;
4942 iocmd.data_dma = buf2_dma;
4943 iocmd.data = pbuf2;
4944 iocmd.size = sz;
4945 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4946 goto target_done;
4947 else if (hd->pLocal == NULL)
4948 goto target_done;
4949 else {
4950 rc = hd->pLocal->completion;
4951 if (rc == MPT_SCANDV_GOOD) {
4952 /* If buffers compare,
4953 * go to next pattern,
4954 * else, do a fallback and restart
4955 * data transfer test.
4956 */
4957 if (memcmp (pbuf1, pbuf2, sz) == 0) {
4958 ; /* goto next pattern */
4959 } else {
4960 /* Miscompare with Echo buffer, go to data buffer,
4961 * if that buffer exists.
4962 * Miscompare with Data buffer, check first 4 bytes,
4963 * some devices return capacity. Exit in this case.
4964 */
4965 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4966 if (dataBufSize >= bufsize)
4967 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4968 else
4969 goto target_done;
4970 } else {
4971 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
4972 /* Argh. Device returning wrong data.
4973 * Quit DV for this device.
4974 */
4975 goto target_done;
4976 }
4977
4978 /* Had an actual miscompare. Slow down.*/
4979 dv.cmd = MPT_FALLBACK;
4980 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4981
4982 if (mpt_config(hd->ioc, &cfg) != 0)
4983 goto target_done;
4984
4985 if ((!dv.now.width) && (!dv.now.offset))
4986 goto target_done;
4987 }
4988
4989 patt = -1;
4990 continue;
4991 }
4992 } else if (rc == MPT_SCANDV_DID_RESET) {
4993 /* Do Fallback and restart
4994 * this test (re-issue reserve
4995 * because of bus reset).
4996 */
4997 dv.cmd = MPT_FALLBACK;
4998 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4999
5000 if (mpt_config(hd->ioc, &cfg) != 0)
5001 goto target_done;
5002
5003 if ((!dv.now.width) && (!dv.now.offset))
5004 goto target_done;
5005
5006 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5007 patt = -1;
5008 continue;
5009 } else if (rc == MPT_SCANDV_SENSE) {
5010 /* Restart data test if UA, else quit.
5011 */
5012 u8 skey = hd->pLocal->sense[2] & 0x0F;
5013 ddvprintk((MYIOC_s_INFO_FMT
5014 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5015 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5016 if (skey == UNIT_ATTENTION) {
5017 patt = -1;
5018 continue;
5019 }
5020 else
5021 goto target_done;
5022 } else {
5023 /* fatal error */
5024 goto target_done;
5025 }
5026 }
5027
5028 } /* --- end of patt loop ---- */
5029
5030target_done:
5031 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5032 iocmd.cmd = RELEASE;
5033 iocmd.data_dma = -1;
5034 iocmd.data = NULL;
5035 iocmd.size = 0;
5036 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5037 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5038 ioc->name, id);
5039 else if (hd->pLocal) {
5040 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5041 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5042 } else {
5043 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5044 ioc->name, id);
5045 }
5046 }
5047
5048
5049 /* Set if cfg1_dma_addr contents is valid
5050 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005051 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 /* If disk, not U320, disable QAS
5053 */
5054 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5055 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005056 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5058 }
5059
5060 dv.cmd = MPT_SAVE;
5061 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5062
5063 /* Double writes to SDP1 can cause problems,
5064 * skip save of the final negotiated settings to
5065 * SCSI device page 1.
5066 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005067 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 cfg.physAddr = cfg1_dma_addr;
5069 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5070 cfg.dir = 1;
5071 mpt_config(hd->ioc, &cfg);
5072 */
5073 }
5074
5075 /* If this is a RAID Passthrough, enable internal IOs
5076 */
5077 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5078 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5079 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5080 }
5081
5082 /* Done with the DV scan of the current target
5083 */
5084 if (pDvBuf)
5085 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5086
5087 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5088 ioc->name, id));
5089
5090 return retcode;
5091}
5092
5093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5094/* mptscsih_dv_parms - perform a variety of operations on the
5095 * parameters used for negotiation.
5096 * @hd: Pointer to a SCSI host.
5097 * @dv: Pointer to a structure that contains the maximum and current
5098 * negotiated parameters.
5099 */
5100static void
5101mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5102{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005103 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 SCSIDevicePage0_t *pPage0;
5105 SCSIDevicePage1_t *pPage1;
5106 int val = 0, data, configuration;
5107 u8 width = 0;
5108 u8 offset = 0;
5109 u8 factor = 0;
5110 u8 negoFlags = 0;
5111 u8 cmd = dv->cmd;
5112 u8 id = dv->id;
5113
5114 switch (cmd) {
5115 case MPT_GET_NVRAM_VALS:
5116 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5117 hd->ioc->name));
5118 /* Get the NVRAM values and save in tmax
5119 * If not an LVD bus, the adapter minSyncFactor has been
5120 * already throttled back.
5121 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005122 negoFlags = hd->ioc->spi_data.noQas;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005123 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume) {
5124 width = vtarget->maxWidth;
5125 offset = vtarget->maxOffset;
5126 factor = vtarget->minSyncFactor;
5127 negoFlags |= vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 } else {
5129 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5130 data = hd->ioc->spi_data.nvram[id];
5131 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5132 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5133 factor = MPT_ASYNC;
5134 else {
5135 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5136 if ((factor == 0) || (factor == MPT_ASYNC)){
5137 factor = MPT_ASYNC;
5138 offset = 0;
5139 }
5140 }
5141 } else {
5142 width = MPT_NARROW;
5143 offset = 0;
5144 factor = MPT_ASYNC;
5145 }
5146
5147 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 if (!width)
5149 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5150
5151 if (!offset)
5152 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5153 }
5154
5155 /* limit by adapter capabilities */
5156 width = min(width, hd->ioc->spi_data.maxBusWidth);
5157 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5158 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5159
5160 /* Check Consistency */
5161 if (offset && (factor < MPT_ULTRA2) && !width)
5162 factor = MPT_ULTRA2;
5163
5164 dv->max.width = width;
5165 dv->max.offset = offset;
5166 dv->max.factor = factor;
5167 dv->max.flags = negoFlags;
5168 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5169 id, width, factor, offset, negoFlags));
5170 break;
5171
5172 case MPT_UPDATE_MAX:
5173 ddvprintk((MYIOC_s_NOTE_FMT
5174 "Updating with SDP0 Data: ", hd->ioc->name));
5175 /* Update tmax values with those from Device Page 0.*/
5176 pPage0 = (SCSIDevicePage0_t *) pPage;
5177 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005178 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5180 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5181 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5182 }
5183
5184 dv->now.width = dv->max.width;
5185 dv->now.offset = dv->max.offset;
5186 dv->now.factor = dv->max.factor;
5187 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5188 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5189 break;
5190
5191 case MPT_SET_MAX:
5192 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5193 hd->ioc->name));
5194 /* Set current to the max values. Update the config page.*/
5195 dv->now.width = dv->max.width;
5196 dv->now.offset = dv->max.offset;
5197 dv->now.factor = dv->max.factor;
5198 dv->now.flags = dv->max.flags;
5199
5200 pPage1 = (SCSIDevicePage1_t *)pPage;
5201 if (pPage1) {
5202 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5203 dv->now.offset, &val, &configuration, dv->now.flags);
5204 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5205 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005206 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005208 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 }
5210
Christoph Hellwig637fa992005-08-18 16:25:44 +02005211 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5213 break;
5214
5215 case MPT_SET_MIN:
5216 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5217 hd->ioc->name));
5218 /* Set page to asynchronous and narrow
5219 * Do not update now, breaks fallback routine. */
5220 width = MPT_NARROW;
5221 offset = 0;
5222 factor = MPT_ASYNC;
5223 negoFlags = dv->max.flags;
5224
5225 pPage1 = (SCSIDevicePage1_t *)pPage;
5226 if (pPage1) {
5227 mptscsih_setDevicePage1Flags (width, factor,
5228 offset, &val, &configuration, negoFlags);
5229 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5230 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005231 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005233 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 }
5235 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5236 id, width, factor, offset, val, configuration, negoFlags));
5237 break;
5238
5239 case MPT_FALLBACK:
5240 ddvprintk((MYIOC_s_NOTE_FMT
5241 "Fallback: Start: offset %d, factor %x, width %d \n",
5242 hd->ioc->name, dv->now.offset,
5243 dv->now.factor, dv->now.width));
5244 width = dv->now.width;
5245 offset = dv->now.offset;
5246 factor = dv->now.factor;
5247 if ((offset) && (dv->max.width)) {
5248 if (factor < MPT_ULTRA160)
5249 factor = MPT_ULTRA160;
5250 else if (factor < MPT_ULTRA2) {
5251 factor = MPT_ULTRA2;
5252 width = MPT_WIDE;
5253 } else if ((factor == MPT_ULTRA2) && width) {
5254 factor = MPT_ULTRA2;
5255 width = MPT_NARROW;
5256 } else if (factor < MPT_ULTRA) {
5257 factor = MPT_ULTRA;
5258 width = MPT_WIDE;
5259 } else if ((factor == MPT_ULTRA) && width) {
5260 width = MPT_NARROW;
5261 } else if (factor < MPT_FAST) {
5262 factor = MPT_FAST;
5263 width = MPT_WIDE;
5264 } else if ((factor == MPT_FAST) && width) {
5265 factor = MPT_FAST;
5266 width = MPT_NARROW;
5267 } else if (factor < MPT_SCSI) {
5268 factor = MPT_SCSI;
5269 width = MPT_WIDE;
5270 } else if ((factor == MPT_SCSI) && width) {
5271 factor = MPT_SCSI;
5272 width = MPT_NARROW;
5273 } else {
5274 factor = MPT_ASYNC;
5275 offset = 0;
5276 }
5277
5278 } else if (offset) {
5279 width = MPT_NARROW;
5280 if (factor < MPT_ULTRA)
5281 factor = MPT_ULTRA;
5282 else if (factor < MPT_FAST)
5283 factor = MPT_FAST;
5284 else if (factor < MPT_SCSI)
5285 factor = MPT_SCSI;
5286 else {
5287 factor = MPT_ASYNC;
5288 offset = 0;
5289 }
5290
5291 } else {
5292 width = MPT_NARROW;
5293 factor = MPT_ASYNC;
5294 }
5295 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5296 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5297
5298 dv->now.width = width;
5299 dv->now.offset = offset;
5300 dv->now.factor = factor;
5301 dv->now.flags = dv->max.flags;
5302
5303 pPage1 = (SCSIDevicePage1_t *)pPage;
5304 if (pPage1) {
5305 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5306 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005307 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 id, width, offset, factor, dv->now.flags, val, configuration));
5309
Christoph Hellwig637fa992005-08-18 16:25:44 +02005310 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005312 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 }
5314
5315 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5316 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5317 break;
5318
5319 case MPT_SAVE:
5320 ddvprintk((MYIOC_s_NOTE_FMT
5321 "Saving to Target structure: ", hd->ioc->name));
5322 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5323 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5324
5325 /* Save these values to target structures
5326 * or overwrite nvram (phys disks only).
5327 */
5328
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005329 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume ) {
5330 vtarget->maxWidth = dv->now.width;
5331 vtarget->maxOffset = dv->now.offset;
5332 vtarget->minSyncFactor = dv->now.factor;
5333 vtarget->negoFlags = dv->now.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 } else {
5335 /* Preserv all flags, use
5336 * read-modify-write algorithm
5337 */
5338 if (hd->ioc->spi_data.nvram) {
5339 data = hd->ioc->spi_data.nvram[id];
5340
5341 if (dv->now.width)
5342 data &= ~MPT_NVRAM_WIDE_DISABLE;
5343 else
5344 data |= MPT_NVRAM_WIDE_DISABLE;
5345
5346 if (!dv->now.offset)
5347 factor = MPT_ASYNC;
5348
5349 data &= ~MPT_NVRAM_SYNC_MASK;
5350 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5351
5352 hd->ioc->spi_data.nvram[id] = data;
5353 }
5354 }
5355 break;
5356 }
5357}
5358
5359/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5360/* mptscsih_fillbuf - fill a buffer with a special data pattern
5361 * cleanup. For bus scan only.
5362 *
5363 * @buffer: Pointer to data buffer to be filled.
5364 * @size: Number of bytes to fill
5365 * @index: Pattern index
5366 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5367 */
5368static void
5369mptscsih_fillbuf(char *buffer, int size, int index, int width)
5370{
5371 char *ptr = buffer;
5372 int ii;
5373 char byte;
5374 short val;
5375
5376 switch (index) {
5377 case 0:
5378
5379 if (width) {
5380 /* Pattern: 0000 FFFF 0000 FFFF
5381 */
5382 for (ii=0; ii < size; ii++, ptr++) {
5383 if (ii & 0x02)
5384 *ptr = 0xFF;
5385 else
5386 *ptr = 0x00;
5387 }
5388 } else {
5389 /* Pattern: 00 FF 00 FF
5390 */
5391 for (ii=0; ii < size; ii++, ptr++) {
5392 if (ii & 0x01)
5393 *ptr = 0xFF;
5394 else
5395 *ptr = 0x00;
5396 }
5397 }
5398 break;
5399
5400 case 1:
5401 if (width) {
5402 /* Pattern: 5555 AAAA 5555 AAAA 5555
5403 */
5404 for (ii=0; ii < size; ii++, ptr++) {
5405 if (ii & 0x02)
5406 *ptr = 0xAA;
5407 else
5408 *ptr = 0x55;
5409 }
5410 } else {
5411 /* Pattern: 55 AA 55 AA 55
5412 */
5413 for (ii=0; ii < size; ii++, ptr++) {
5414 if (ii & 0x01)
5415 *ptr = 0xAA;
5416 else
5417 *ptr = 0x55;
5418 }
5419 }
5420 break;
5421
5422 case 2:
5423 /* Pattern: 00 01 02 03 04 05
5424 * ... FE FF 00 01..
5425 */
5426 for (ii=0; ii < size; ii++, ptr++)
5427 *ptr = (char) ii;
5428 break;
5429
5430 case 3:
5431 if (width) {
5432 /* Wide Pattern: FFFE 0001 FFFD 0002
5433 * ... 4000 DFFF 8000 EFFF
5434 */
5435 byte = 0;
5436 for (ii=0; ii < size/2; ii++) {
5437 /* Create the base pattern
5438 */
5439 val = (1 << byte);
5440 /* every 64 (0x40) bytes flip the pattern
5441 * since we fill 2 bytes / iteration,
5442 * test for ii = 0x20
5443 */
5444 if (ii & 0x20)
5445 val = ~(val);
5446
5447 if (ii & 0x01) {
5448 *ptr = (char)( (val & 0xFF00) >> 8);
5449 ptr++;
5450 *ptr = (char)(val & 0xFF);
5451 byte++;
5452 byte &= 0x0F;
5453 } else {
5454 val = ~val;
5455 *ptr = (char)( (val & 0xFF00) >> 8);
5456 ptr++;
5457 *ptr = (char)(val & 0xFF);
5458 }
5459
5460 ptr++;
5461 }
5462 } else {
5463 /* Narrow Pattern: FE 01 FD 02 FB 04
5464 * .. 7F 80 01 FE 02 FD ... 80 7F
5465 */
5466 byte = 0;
5467 for (ii=0; ii < size; ii++, ptr++) {
5468 /* Base pattern - first 32 bytes
5469 */
5470 if (ii & 0x01) {
5471 *ptr = (1 << byte);
5472 byte++;
5473 byte &= 0x07;
5474 } else {
5475 *ptr = (char) (~(1 << byte));
5476 }
5477
5478 /* Flip the pattern every 32 bytes
5479 */
5480 if (ii & 0x20)
5481 *ptr = ~(*ptr);
5482 }
5483 }
5484 break;
5485 }
5486}
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005487
5488/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5489/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
5490 * Else set the NEED_DV flag after Read Capacity Issued (disks)
5491 * or Mode Sense (cdroms).
5492 *
5493 * Tapes, initTarget will set this flag on completion of Inquiry command.
5494 * Called only if DV_NOT_DONE flag is set
5495 */
5496static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005497mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005498{
5499 MPT_ADAPTER *ioc = hd->ioc;
5500 u8 cmd;
5501 SpiCfgData *pSpi;
5502
5503 ddvtprintk((MYIOC_s_NOTE_FMT
5504 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005505 hd->ioc->name, sc->device->id, sc->device->lun , hd->negoNvram, sc->cmnd[0]));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005506
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005507 if ((sc->device->lun != 0) || (hd->negoNvram != 0))
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005508 return;
5509
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005510 cmd = sc->cmnd[0];
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005511
5512 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
5513 pSpi = &ioc->spi_data;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005514 if ((ioc->raid_data.isRaid & (1 << sc->device->id)) && ioc->raid_data.pIocPg3) {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005515 /* Set NEED_DV for all hidden disks
5516 */
5517 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5518 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5519
5520 while (numPDisk) {
5521 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
5522 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
5523 pPDisk++;
5524 numPDisk--;
5525 }
5526 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005527 pSpi->dvStatus[sc->device->id] |= MPT_SCSICFG_NEED_DV;
5528 ddvtprintk(("NEED_DV set for visible disk id %d\n", sc->device->id));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005529 }
5530}
5531
5532/* mptscsih_raid_set_dv_flags()
5533 *
5534 * New or replaced disk. Set DV flag and schedule DV.
5535 */
5536static void
5537mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
5538{
5539 MPT_ADAPTER *ioc = hd->ioc;
5540 SpiCfgData *pSpi = &ioc->spi_data;
5541 Ioc3PhysDisk_t *pPDisk;
5542 int numPDisk;
5543
5544 if (hd->negoNvram != 0)
5545 return;
5546
5547 ddvtprintk(("DV requested for phys disk id %d\n", id));
5548 if (ioc->raid_data.pIocPg3) {
5549 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5550 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5551 while (numPDisk) {
5552 if (id == pPDisk->PhysDiskNum) {
5553 pSpi->dvStatus[pPDisk->PhysDiskID] =
5554 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
5555 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
5556 ddvtprintk(("NEED_DV set for phys disk id %d\n",
5557 pPDisk->PhysDiskID));
5558 break;
5559 }
5560 pPDisk++;
5561 numPDisk--;
5562 }
5563
5564 if (numPDisk == 0) {
5565 /* The physical disk that needs DV was not found
5566 * in the stored IOC Page 3. The driver must reload
5567 * this page. DV routine will set the NEED_DV flag for
5568 * all phys disks that have DV_NOT_DONE set.
5569 */
5570 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
5571 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
5572 }
5573 }
5574}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5576
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005577EXPORT_SYMBOL(mptscsih_remove);
5578EXPORT_SYMBOL(mptscsih_shutdown);
5579#ifdef CONFIG_PM
5580EXPORT_SYMBOL(mptscsih_suspend);
5581EXPORT_SYMBOL(mptscsih_resume);
5582#endif
5583EXPORT_SYMBOL(mptscsih_proc_info);
5584EXPORT_SYMBOL(mptscsih_info);
5585EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005586EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005587EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005588EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005589EXPORT_SYMBOL(mptscsih_slave_destroy);
5590EXPORT_SYMBOL(mptscsih_slave_configure);
5591EXPORT_SYMBOL(mptscsih_abort);
5592EXPORT_SYMBOL(mptscsih_dev_reset);
5593EXPORT_SYMBOL(mptscsih_bus_reset);
5594EXPORT_SYMBOL(mptscsih_host_reset);
5595EXPORT_SYMBOL(mptscsih_bios_param);
5596EXPORT_SYMBOL(mptscsih_io_done);
5597EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5598EXPORT_SYMBOL(mptscsih_scandv_complete);
5599EXPORT_SYMBOL(mptscsih_event_process);
5600EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005601EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005602EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06005603EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005605/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/