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