blob: c8492034cfe75acbc60bbdc1534fccb81d190d35 [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 *);
173void mptscsih_shutdown(struct device *);
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
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400991 mptscsih_shutdown(&pdev->dev);
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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029mptscsih_shutdown(struct device * dev)
1030{
1031 MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev));
1032 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{
1057 mptscsih_shutdown(&pdev->dev);
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;
1710 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1711
1712 /* If we can't locate our host adapter structure, return FAILED status.
1713 */
1714 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1715 SCpnt->result = DID_RESET << 16;
1716 SCpnt->scsi_done(SCpnt);
1717 dfailprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
1718 "Can't locate host! (sc=%p)\n",
1719 SCpnt));
1720 return FAILED;
1721 }
1722
1723 ioc = hd->ioc;
1724 if (hd->resetPending)
1725 return FAILED;
1726
1727 printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
1728 hd->ioc->name, SCpnt);
1729
1730 if (hd->timeouts < -1)
1731 hd->timeouts++;
1732
1733 /* Find this command
1734 */
1735 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
1736 /* Cmd not found in ScsiLookup.
1737 * Do OS callback.
1738 */
1739 SCpnt->result = DID_RESET << 16;
1740 dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
1741 "Command not in the active list! (sc=%p)\n",
1742 hd->ioc->name, SCpnt));
1743 return SUCCESS;
1744 }
1745
1746 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1747 * (the IO to be ABORT'd)
1748 *
1749 * NOTE: Since we do not byteswap MsgContext, we do not
1750 * swap it here either. It is an opaque cookie to
1751 * the controller, so it does not matter. -DaveM
1752 */
1753 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1754 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1755
1756 hd->abortSCpnt = SCpnt;
1757
1758 spin_unlock_irq(host_lock);
1759 if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1760 SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
1761 ctx2abort, 2 /* 2 second timeout */)
1762 < 0) {
1763
1764 /* The TM request failed and the subsequent FW-reload failed!
1765 * Fatal error case.
1766 */
1767 printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
1768 hd->ioc->name, SCpnt);
1769
1770 /* We must clear our pending flag before clearing our state.
1771 */
1772 hd->tmPending = 0;
1773 hd->tmState = TM_STATE_NONE;
1774
1775 spin_lock_irq(host_lock);
1776
1777 /* Unmap the DMA buffers, if any. */
1778 if (SCpnt->use_sg) {
1779 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer,
1780 SCpnt->use_sg, SCpnt->sc_data_direction);
1781 } else if (SCpnt->request_bufflen) {
1782 pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle,
1783 SCpnt->request_bufflen, SCpnt->sc_data_direction);
1784 }
1785 hd->ScsiLookup[scpnt_idx] = NULL;
1786 SCpnt->result = DID_RESET << 16;
1787 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
1788 mptscsih_freeChainBuffers(ioc, scpnt_idx);
1789 mpt_free_msg_frame(ioc, mf);
1790 return FAILED;
1791 }
1792 spin_lock_irq(host_lock);
1793 return SUCCESS;
1794}
1795
1796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1797/**
1798 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1799 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1800 *
1801 * (linux scsi_host_template.eh_dev_reset_handler routine)
1802 *
1803 * Returns SUCCESS or FAILED.
1804 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001805int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1807{
1808 MPT_SCSI_HOST *hd;
1809 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1810
1811 /* If we can't locate our host adapter structure, return FAILED status.
1812 */
1813 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1814 dtmprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
1815 "Can't locate host! (sc=%p)\n",
1816 SCpnt));
1817 return FAILED;
1818 }
1819
1820 if (hd->resetPending)
1821 return FAILED;
1822
1823 printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
1824 hd->ioc->name, SCpnt);
1825
1826 spin_unlock_irq(host_lock);
1827 if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1828 SCpnt->device->channel, SCpnt->device->id,
1829 0, 0, 5 /* 5 second timeout */)
1830 < 0){
1831 /* The TM request failed and the subsequent FW-reload failed!
1832 * Fatal error case.
1833 */
1834 printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
1835 hd->ioc->name, SCpnt);
1836 hd->tmPending = 0;
1837 hd->tmState = TM_STATE_NONE;
1838 spin_lock_irq(host_lock);
1839 return FAILED;
1840 }
1841 spin_lock_irq(host_lock);
1842 return SUCCESS;
1843
1844}
1845
1846/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1847/**
1848 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1849 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1850 *
1851 * (linux scsi_host_template.eh_bus_reset_handler routine)
1852 *
1853 * Returns SUCCESS or FAILED.
1854 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001855int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1857{
1858 MPT_SCSI_HOST *hd;
1859 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1860
1861 /* If we can't locate our host adapter structure, return FAILED status.
1862 */
1863 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1864 dtmprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
1865 "Can't locate host! (sc=%p)\n",
1866 SCpnt ) );
1867 return FAILED;
1868 }
1869
1870 printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
1871 hd->ioc->name, SCpnt);
1872
1873 if (hd->timeouts < -1)
1874 hd->timeouts++;
1875
1876 /* We are now ready to execute the task management request. */
1877 spin_unlock_irq(host_lock);
1878 if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1879 SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */)
1880 < 0){
1881
1882 /* The TM request failed and the subsequent FW-reload failed!
1883 * Fatal error case.
1884 */
1885 printk(MYIOC_s_WARN_FMT
1886 "Error processing TaskMgmt request (sc=%p)\n",
1887 hd->ioc->name, SCpnt);
1888 hd->tmPending = 0;
1889 hd->tmState = TM_STATE_NONE;
1890 spin_lock_irq(host_lock);
1891 return FAILED;
1892 }
1893 spin_lock_irq(host_lock);
1894 return SUCCESS;
1895}
1896
1897/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1898/**
1899 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1900 * new_eh variant
1901 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1902 *
1903 * (linux scsi_host_template.eh_host_reset_handler routine)
1904 *
1905 * Returns SUCCESS or FAILED.
1906 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001907int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1909{
1910 MPT_SCSI_HOST * hd;
1911 int status = SUCCESS;
1912 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1913
1914 /* If we can't locate the host to reset, then we failed. */
1915 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1916 dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
1917 "Can't locate host! (sc=%p)\n",
1918 SCpnt ) );
1919 return FAILED;
1920 }
1921
1922 printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
1923 hd->ioc->name, SCpnt);
1924
1925 /* If our attempts to reset the host failed, then return a failed
1926 * status. The host will be taken off line by the SCSI mid-layer.
1927 */
1928 spin_unlock_irq(host_lock);
1929 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1930 status = FAILED;
1931 } else {
1932 /* Make sure TM pending is cleared and TM state is set to
1933 * NONE.
1934 */
1935 hd->tmPending = 0;
1936 hd->tmState = TM_STATE_NONE;
1937 }
1938 spin_lock_irq(host_lock);
1939
1940
1941 dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
1942 "Status = %s\n",
1943 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1944
1945 return status;
1946}
1947
1948/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1949/**
1950 * mptscsih_tm_pending_wait - wait for pending task management request to
1951 * complete.
1952 * @hd: Pointer to MPT host structure.
1953 *
1954 * Returns {SUCCESS,FAILED}.
1955 */
1956static int
1957mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1958{
1959 unsigned long flags;
1960 int loop_count = 4 * 10; /* Wait 10 seconds */
1961 int status = FAILED;
1962
1963 do {
1964 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1965 if (hd->tmState == TM_STATE_NONE) {
1966 hd->tmState = TM_STATE_IN_PROGRESS;
1967 hd->tmPending = 1;
1968 status = SUCCESS;
1969 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1970 break;
1971 }
1972 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1973 msleep(250);
1974 } while (--loop_count);
1975
1976 return status;
1977}
1978
1979/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1980/**
1981 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1982 * @hd: Pointer to MPT host structure.
1983 *
1984 * Returns {SUCCESS,FAILED}.
1985 */
1986static int
1987mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1988{
1989 unsigned long flags;
1990 int loop_count = 4 * timeout;
1991 int status = FAILED;
1992
1993 do {
1994 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1995 if(hd->tmPending == 0) {
1996 status = SUCCESS;
1997 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1998 break;
1999 }
2000 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2001 msleep_interruptible(250);
2002 } while (--loop_count);
2003
2004 return status;
2005}
2006
2007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2008/**
2009 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2010 * @ioc: Pointer to MPT_ADAPTER structure
2011 * @mf: Pointer to SCSI task mgmt request frame
2012 * @mr: Pointer to SCSI task mgmt reply frame
2013 *
2014 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2015 * of any SCSI task management request.
2016 * This routine is registered with the MPT (base) driver at driver
2017 * load/init time via the mpt_register() API call.
2018 *
2019 * Returns 1 indicating alloc'd request frame ptr should be freed.
2020 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002021int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2023{
2024 SCSITaskMgmtReply_t *pScsiTmReply;
2025 SCSITaskMgmt_t *pScsiTmReq;
2026 MPT_SCSI_HOST *hd;
2027 unsigned long flags;
2028 u16 iocstatus;
2029 u8 tmType;
2030
2031 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2032 ioc->name, mf, mr));
2033 if (ioc->sh) {
2034 /* Depending on the thread, a timer is activated for
2035 * the TM request. Delete this timer on completion of TM.
2036 * Decrement count of outstanding TM requests.
2037 */
2038 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2039 } else {
2040 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2041 ioc->name));
2042 return 1;
2043 }
2044
2045 if (mr == NULL) {
2046 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2047 ioc->name, mf));
2048 return 1;
2049 } else {
2050 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2051 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2052
2053 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2054 tmType = pScsiTmReq->TaskType;
2055
2056 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2057 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2058 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2059
2060 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2061 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2062 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2063 /* Error? (anything non-zero?) */
2064 if (iocstatus) {
2065
2066 /* clear flags and continue.
2067 */
2068 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2069 hd->abortSCpnt = NULL;
2070
2071 /* If an internal command is present
2072 * or the TM failed - reload the FW.
2073 * FC FW may respond FAILED to an ABORT
2074 */
2075 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2076 if ((hd->cmdPtr) ||
2077 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2078 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2079 printk((KERN_WARNING
2080 " Firmware Reload FAILED!!\n"));
2081 }
2082 }
2083 }
2084 } else {
2085 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2086
2087 hd->abortSCpnt = NULL;
2088
2089 }
2090 }
2091
2092 spin_lock_irqsave(&ioc->FreeQlock, flags);
2093 hd->tmPending = 0;
2094 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2095 hd->tmState = TM_STATE_NONE;
2096
2097 return 1;
2098}
2099
2100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2101/*
2102 * This is anyones guess quite frankly.
2103 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002104int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2106 sector_t capacity, int geom[])
2107{
2108 int heads;
2109 int sectors;
2110 sector_t cylinders;
2111 ulong dummy;
2112
2113 heads = 64;
2114 sectors = 32;
2115
2116 dummy = heads * sectors;
2117 cylinders = capacity;
2118 sector_div(cylinders,dummy);
2119
2120 /*
2121 * Handle extended translation size for logical drives
2122 * > 1Gb
2123 */
2124 if ((ulong)capacity >= 0x200000) {
2125 heads = 255;
2126 sectors = 63;
2127 dummy = heads * sectors;
2128 cylinders = capacity;
2129 sector_div(cylinders,dummy);
2130 }
2131
2132 /* return result */
2133 geom[0] = heads;
2134 geom[1] = sectors;
2135 geom[2] = cylinders;
2136
2137 dprintk((KERN_NOTICE
2138 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2139 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2140
2141 return 0;
2142}
2143
2144/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2145/*
2146 * OS entry point to allow host driver to alloc memory
2147 * for each scsi device. Called once per device the bus scan.
2148 * Return non-zero if allocation fails.
2149 * Init memory once per id (not LUN).
2150 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002151int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152mptscsih_slave_alloc(struct scsi_device *device)
2153{
2154 struct Scsi_Host *host = device->host;
2155 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2156 VirtDevice *vdev;
2157 uint target = device->id;
2158
2159 if (hd == NULL)
2160 return -ENODEV;
2161
2162 if ((vdev = hd->Targets[target]) != NULL)
2163 goto out;
2164
2165 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
2166 if (!vdev) {
2167 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2168 hd->ioc->name, sizeof(VirtDevice));
2169 return -ENOMEM;
2170 }
2171
2172 memset(vdev, 0, sizeof(VirtDevice));
2173 vdev->tflags = MPT_TARGET_FLAGS_Q_YES;
2174 vdev->ioc_id = hd->ioc->id;
2175 vdev->target_id = device->id;
2176 vdev->bus_id = device->channel;
2177 vdev->raidVolume = 0;
2178 hd->Targets[device->id] = vdev;
2179 if (hd->ioc->bus_type == SCSI) {
2180 if (hd->ioc->spi_data.isRaid & (1 << device->id)) {
2181 vdev->raidVolume = 1;
2182 ddvtprintk((KERN_INFO
2183 "RAID Volume @ id %d\n", device->id));
2184 }
2185 } else {
2186 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2187 }
2188
2189 out:
2190 vdev->num_luns++;
2191 return 0;
2192}
2193
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002194static int
2195mptscsih_is_raid_volume(MPT_SCSI_HOST *hd, uint id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196{
2197 int i;
2198
2199 if (!hd->ioc->spi_data.isRaid || !hd->ioc->spi_data.pIocPg3)
2200 return 0;
2201
2202 for (i = 0; i < hd->ioc->spi_data.pIocPg3->NumPhysDisks; i++) {
2203 if (id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID)
2204 return 1;
2205 }
2206
2207 return 0;
2208}
2209
2210/*
2211 * OS entry point to allow for host driver to free allocated memory
2212 * Called if no device present or device being unloaded
2213 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002214void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215mptscsih_slave_destroy(struct scsi_device *device)
2216{
2217 struct Scsi_Host *host = device->host;
2218 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2219 VirtDevice *vdev;
2220 uint target = device->id;
2221 uint lun = device->lun;
2222
2223 if (hd == NULL)
2224 return;
2225
2226 mptscsih_search_running_cmds(hd, target, lun);
2227
2228 vdev = hd->Targets[target];
2229 vdev->luns[0] &= ~(1 << lun);
2230 if (--vdev->num_luns)
2231 return;
2232
2233 kfree(hd->Targets[target]);
2234 hd->Targets[target] = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002235
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 if (hd->ioc->bus_type == SCSI) {
2237 if (mptscsih_is_raid_volume(hd, target)) {
2238 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2239 } else {
2240 hd->ioc->spi_data.dvStatus[target] =
2241 MPT_SCSICFG_NEGOTIATE;
2242
2243 if (!hd->negoNvram) {
2244 hd->ioc->spi_data.dvStatus[target] |=
2245 MPT_SCSICFG_DV_NOT_DONE;
2246 }
2247 }
2248 }
2249}
2250
2251static void
2252mptscsih_set_queue_depth(struct scsi_device *device, MPT_SCSI_HOST *hd,
2253 VirtDevice *pTarget, int qdepth)
2254{
2255 int max_depth;
2256 int tagged;
2257
2258 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
2281 scsi_adjust_queue_depth(device, tagged, qdepth);
2282}
2283
2284
2285/*
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 );
2334 mptscsih_set_queue_depth(device, hd, pTarget, MPT_SCSI_CMD_PER_DEV_HIGH);
2335
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
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002354ssize_t
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355mptscsih_store_queue_depth(struct device *dev, const char *buf, size_t count)
2356{
2357 int depth;
2358 struct scsi_device *sdev = to_scsi_device(dev);
2359 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) sdev->host->hostdata;
2360 VirtDevice *pTarget;
2361
2362 depth = simple_strtoul(buf, NULL, 0);
2363 if (depth == 0)
2364 return -EINVAL;
2365 pTarget = hd->Targets[sdev->id];
2366 if (pTarget == NULL)
2367 return -EINVAL;
2368 mptscsih_set_queue_depth(sdev, (MPT_SCSI_HOST *) sdev->host->hostdata,
2369 pTarget, depth);
2370 return count;
2371}
2372
2373/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2374/*
2375 * Private routines...
2376 */
2377
2378/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2379/* Utility function to copy sense data from the scsi_cmnd buffer
2380 * to the FC and SCSI target structures.
2381 *
2382 */
2383static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002384mptscsih_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 -07002385{
2386 VirtDevice *target;
2387 SCSIIORequest_t *pReq;
2388 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
2389 int index;
2390
2391 /* Get target structure
2392 */
2393 pReq = (SCSIIORequest_t *) mf;
2394 index = (int) pReq->TargetID;
2395 target = hd->Targets[index];
2396
2397 if (sense_count) {
2398 u8 *sense_data;
2399 int req_index;
2400
2401 /* Copy the sense received into the scsi command block. */
2402 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2403 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2404 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2405
2406 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2407 */
2408 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2409 if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
2410 int idx;
2411 MPT_ADAPTER *ioc = hd->ioc;
2412
2413 idx = ioc->eventContext % ioc->eventLogSize;
2414 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2415 ioc->events[idx].eventContext = ioc->eventContext;
2416
2417 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2418 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
2419 (pReq->Bus << 8) || pReq->TargetID;
2420
2421 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2422
2423 ioc->eventContext++;
2424 }
2425 }
2426 } else {
2427 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2428 hd->ioc->name));
2429 }
2430}
2431
2432static u32
2433SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2434{
2435 MPT_SCSI_HOST *hd;
2436 int i;
2437
2438 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2439
2440 for (i = 0; i < hd->ioc->req_depth; i++) {
2441 if (hd->ScsiLookup[i] == sc) {
2442 return i;
2443 }
2444 }
2445
2446 return -1;
2447}
2448
2449/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002450int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2452{
2453 MPT_SCSI_HOST *hd;
2454 unsigned long flags;
2455
2456 dtmprintk((KERN_WARNING MYNAM
2457 ": IOC %s_reset routed to SCSI host driver!\n",
2458 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2459 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2460
2461 /* If a FW reload request arrives after base installed but
2462 * before all scsi hosts have been attached, then an alt_ioc
2463 * may have a NULL sh pointer.
2464 */
2465 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2466 return 0;
2467 else
2468 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2469
2470 if (reset_phase == MPT_IOC_SETUP_RESET) {
2471 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2472
2473 /* Clean Up:
2474 * 1. Set Hard Reset Pending Flag
2475 * All new commands go to doneQ
2476 */
2477 hd->resetPending = 1;
2478
2479 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2480 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2481
2482 /* 2. Flush running commands
2483 * Clean ScsiLookup (and associated memory)
2484 * AND clean mytaskQ
2485 */
2486
2487 /* 2b. Reply to OS all known outstanding I/O commands.
2488 */
2489 mptscsih_flush_running_cmds(hd);
2490
2491 /* 2c. If there was an internal command that
2492 * has not completed, configuration or io request,
2493 * free these resources.
2494 */
2495 if (hd->cmdPtr) {
2496 del_timer(&hd->timer);
2497 mpt_free_msg_frame(ioc, hd->cmdPtr);
2498 }
2499
2500 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2501
2502 } else {
2503 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2504
2505 /* Once a FW reload begins, all new OS commands are
2506 * redirected to the doneQ w/ a reset status.
2507 * Init all control structures.
2508 */
2509
2510 /* ScsiLookup initialization
2511 */
2512 {
2513 int ii;
2514 for (ii=0; ii < hd->ioc->req_depth; ii++)
2515 hd->ScsiLookup[ii] = NULL;
2516 }
2517
2518 /* 2. Chain Buffer initialization
2519 */
2520
2521 /* 4. Renegotiate to all devices, if SCSI
2522 */
2523 if (ioc->bus_type == SCSI) {
2524 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2525 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2526 }
2527
2528 /* 5. Enable new commands to be posted
2529 */
2530 spin_lock_irqsave(&ioc->FreeQlock, flags);
2531 hd->tmPending = 0;
2532 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2533 hd->resetPending = 0;
2534 hd->tmState = TM_STATE_NONE;
2535
2536 /* 6. If there was an internal command,
2537 * wake this process up.
2538 */
2539 if (hd->cmdPtr) {
2540 /*
2541 * Wake up the original calling thread
2542 */
2543 hd->pLocal = &hd->localReply;
2544 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002545 hd->scandv_wait_done = 1;
2546 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 hd->cmdPtr = NULL;
2548 }
2549
2550 /* 7. Set flag to force DV and re-read IOC Page 3
2551 */
2552 if (ioc->bus_type == SCSI) {
2553 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2554 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2555 }
2556
2557 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2558
2559 }
2560
2561 return 1; /* currently means nothing really */
2562}
2563
2564/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002565int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2567{
2568 MPT_SCSI_HOST *hd;
2569 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2570
2571 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2572 ioc->name, event));
2573
2574 switch (event) {
2575 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2576 /* FIXME! */
2577 break;
2578 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2579 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
2580 hd = NULL;
2581 if (ioc->sh) {
2582 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2583 if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1))
2584 hd->soft_resets++;
2585 }
2586 break;
2587 case MPI_EVENT_LOGOUT: /* 09 */
2588 /* FIXME! */
2589 break;
2590
2591 /*
2592 * CHECKME! Don't think we need to do
2593 * anything for these, but...
2594 */
2595 case MPI_EVENT_RESCAN: /* 06 */
2596 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2597 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2598 /*
2599 * CHECKME! Falling thru...
2600 */
2601 break;
2602
2603 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
2604#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
2605 /* negoNvram set to 0 if DV enabled and to USE_NVRAM if
2606 * if DV disabled. Need to check for target mode.
2607 */
2608 hd = NULL;
2609 if (ioc->sh)
2610 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2611
2612 if (hd && (ioc->bus_type == SCSI) && (hd->negoNvram == 0)) {
2613 ScsiCfgData *pSpi;
2614 Ioc3PhysDisk_t *pPDisk;
2615 int numPDisk;
2616 u8 reason;
2617 u8 physDiskNum;
2618
2619 reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
2620 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
2621 /* New or replaced disk.
2622 * Set DV flag and schedule DV.
2623 */
2624 pSpi = &ioc->spi_data;
2625 physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
2626 ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
2627 if (pSpi->pIocPg3) {
2628 pPDisk = pSpi->pIocPg3->PhysDisk;
2629 numPDisk =pSpi->pIocPg3->NumPhysDisks;
2630
2631 while (numPDisk) {
2632 if (physDiskNum == pPDisk->PhysDiskNum) {
2633 pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
2634 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
2635 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
2636 break;
2637 }
2638 pPDisk++;
2639 numPDisk--;
2640 }
2641
2642 if (numPDisk == 0) {
2643 /* The physical disk that needs DV was not found
2644 * in the stored IOC Page 3. The driver must reload
2645 * this page. DV routine will set the NEED_DV flag for
2646 * all phys disks that have DV_NOT_DONE set.
2647 */
2648 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2649 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
2650 }
2651 }
2652 }
2653 }
2654#endif
2655
2656#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
2657 printk("Raid Event RF: ");
2658 {
2659 u32 *m = (u32 *)pEvReply;
2660 int ii;
2661 int n = (int)pEvReply->MsgLength;
2662 for (ii=6; ii < n; ii++)
2663 printk(" %08x", le32_to_cpu(m[ii]));
2664 printk("\n");
2665 }
2666#endif
2667 break;
2668
2669 case MPI_EVENT_NONE: /* 00 */
2670 case MPI_EVENT_LOG_DATA: /* 01 */
2671 case MPI_EVENT_STATE_CHANGE: /* 02 */
2672 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2673 default:
2674 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2675 break;
2676 }
2677
2678 return 1; /* currently means nothing really */
2679}
2680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2682/*
2683 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2684 * @hd: Pointer to MPT_SCSI_HOST structure
2685 * @bus_id: Bus number (?)
2686 * @target_id: SCSI target id
2687 * @lun: SCSI LUN id
2688 * @data: Pointer to data
2689 * @dlen: Number of INQUIRY bytes
2690 *
2691 * NOTE: It's only SAFE to call this routine if data points to
2692 * sane & valid STANDARD INQUIRY data!
2693 *
2694 * Allocate and initialize memory for this target.
2695 * Save inquiry data.
2696 *
2697 */
2698static void
2699mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
2700{
2701 int indexed_lun, lun_index;
2702 VirtDevice *vdev;
2703 ScsiCfgData *pSpi;
2704 char data_56;
2705
2706 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
2707 hd->ioc->name, bus_id, target_id, lun, hd));
2708
2709 /*
2710 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2711 * (i.e. The targer is capable of supporting the specified peripheral device type
2712 * on this logical unit; however, the physical device is not currently connected
2713 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
2714 * capable of supporting a physical device on this logical unit). This is to work
2715 * around a bug in th emid-layer in some distributions in which the mid-layer will
2716 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2717 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002718 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002720
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 /* Is LUN supported? If so, upper 2 bits will be 0
2722 * in first byte of inquiry data.
2723 */
2724 if (data[0] & 0xe0)
2725 return;
2726
2727 if ((vdev = hd->Targets[target_id]) == NULL) {
2728 return;
2729 }
2730
2731 lun_index = (lun >> 5); /* 32 luns per lun_index */
2732 indexed_lun = (lun % 32);
2733 vdev->luns[lun_index] |= (1 << indexed_lun);
2734
2735 if (hd->ioc->bus_type == SCSI) {
2736 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2737 /* Treat all Processors as SAF-TE if
2738 * command line option is set */
2739 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2740 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2741 }else if ((data[0] == TYPE_PROCESSOR) &&
2742 !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2743 if ( dlen > 49 ) {
2744 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2745 if ( data[44] == 'S' &&
2746 data[45] == 'A' &&
2747 data[46] == 'F' &&
2748 data[47] == '-' &&
2749 data[48] == 'T' &&
2750 data[49] == 'E' ) {
2751 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2752 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2753 }
2754 }
2755 }
2756 if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2757 if ( dlen > 8 ) {
2758 memcpy (vdev->inq_data, data, 8);
2759 } else {
2760 memcpy (vdev->inq_data, data, dlen);
2761 }
2762
2763 /* If have not done DV, set the DV flag.
2764 */
2765 pSpi = &hd->ioc->spi_data;
2766 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2767 if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
2768 pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
2769 }
2770
2771 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2772
2773
2774 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2775 if (dlen > 56) {
2776 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2777 /* Update the target capabilities
2778 */
2779 data_56 = data[56];
2780 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2781 }
2782 }
2783 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2784 } else {
2785 /* Initial Inquiry may not request enough data bytes to
2786 * obtain byte 57. DV will; if target doesn't return
2787 * at least 57 bytes, data[56] will be zero. */
2788 if (dlen > 56) {
2789 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2790 /* Update the target capabilities
2791 */
2792 data_56 = data[56];
2793 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2794 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2795 }
2796 }
2797 }
2798 }
2799}
2800
2801/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2802/*
2803 * Update the target negotiation parameters based on the
2804 * the Inquiry data, adapter capabilities, and NVRAM settings.
2805 *
2806 */
2807static void
2808mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
2809{
2810 ScsiCfgData *pspi_data = &hd->ioc->spi_data;
2811 int id = (int) target->target_id;
2812 int nvram;
2813 VirtDevice *vdev;
2814 int ii;
2815 u8 width = MPT_NARROW;
2816 u8 factor = MPT_ASYNC;
2817 u8 offset = 0;
2818 u8 version, nfactor;
2819 u8 noQas = 1;
2820
2821 target->negoFlags = pspi_data->noQas;
2822
2823 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2824 * support. If available, default QAS to off and allow enabling.
2825 * If not available, default QAS to on, turn off for non-disks.
2826 */
2827
2828 /* Set flags based on Inquiry data
2829 */
2830 version = target->inq_data[2] & 0x07;
2831 if (version < 2) {
2832 width = 0;
2833 factor = MPT_ULTRA2;
2834 offset = pspi_data->maxSyncOffset;
2835 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2836 } else {
2837 if (target->inq_data[7] & 0x20) {
2838 width = 1;
2839 }
2840
2841 if (target->inq_data[7] & 0x10) {
2842 factor = pspi_data->minSyncFactor;
2843 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2844 /* bits 2 & 3 show Clocking support */
2845 if ((byte56 & 0x0C) == 0)
2846 factor = MPT_ULTRA2;
2847 else {
2848 if ((byte56 & 0x03) == 0)
2849 factor = MPT_ULTRA160;
2850 else {
2851 factor = MPT_ULTRA320;
2852 if (byte56 & 0x02)
2853 {
2854 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2855 noQas = 0;
2856 }
2857 if (target->inq_data[0] == TYPE_TAPE) {
2858 if (byte56 & 0x01)
2859 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2860 }
2861 }
2862 }
2863 } else {
2864 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2865 noQas = 0;
2866 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002867
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 offset = pspi_data->maxSyncOffset;
2869
2870 /* If RAID, never disable QAS
2871 * else if non RAID, do not disable
2872 * QAS if bit 1 is set
2873 * bit 1 QAS support, non-raid only
2874 * bit 0 IU support
2875 */
2876 if (target->raidVolume == 1) {
2877 noQas = 0;
2878 }
2879 } else {
2880 factor = MPT_ASYNC;
2881 offset = 0;
2882 }
2883 }
2884
2885 if ( (target->inq_data[7] & 0x02) == 0) {
2886 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2887 }
2888
2889 /* Update tflags based on NVRAM settings. (SCSI only)
2890 */
2891 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2892 nvram = pspi_data->nvram[id];
2893 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2894
2895 if (width)
2896 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2897
2898 if (offset > 0) {
2899 /* Ensure factor is set to the
2900 * maximum of: adapter, nvram, inquiry
2901 */
2902 if (nfactor) {
2903 if (nfactor < pspi_data->minSyncFactor )
2904 nfactor = pspi_data->minSyncFactor;
2905
2906 factor = max(factor, nfactor);
2907 if (factor == MPT_ASYNC)
2908 offset = 0;
2909 } else {
2910 offset = 0;
2911 factor = MPT_ASYNC;
2912 }
2913 } else {
2914 factor = MPT_ASYNC;
2915 }
2916 }
2917
2918 /* Make sure data is consistent
2919 */
2920 if ((!width) && (factor < MPT_ULTRA2)) {
2921 factor = MPT_ULTRA2;
2922 }
2923
2924 /* Save the data to the target structure.
2925 */
2926 target->minSyncFactor = factor;
2927 target->maxOffset = offset;
2928 target->maxWidth = width;
2929
2930 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2931
2932 /* Disable unused features.
2933 */
2934 if (!width)
2935 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2936
2937 if (!offset)
2938 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2939
2940 if ( factor > MPT_ULTRA320 )
2941 noQas = 0;
2942
2943 /* GEM, processor WORKAROUND
2944 */
2945 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2946 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2947 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2948 } else {
2949 if (noQas && (pspi_data->noQas == 0)) {
2950 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2951 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2952
2953 /* Disable QAS in a mixed configuration case
2954 */
2955
2956 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2957 for (ii = 0; ii < id; ii++) {
2958 if ( (vdev = hd->Targets[ii]) ) {
2959 vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2960 mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 }
2963 }
2964 }
2965
2966 /* Write SDP1 on this I/O to this target */
2967 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2968 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2969 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2970 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2971 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2972 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2973 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2974 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2975 }
2976}
2977
2978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2979/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
2980 * Else set the NEED_DV flag after Read Capacity Issued (disks)
2981 * or Mode Sense (cdroms).
2982 *
2983 * Tapes, initTarget will set this flag on completion of Inquiry command.
2984 * Called only if DV_NOT_DONE flag is set
2985 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002986static void
2987mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989 u8 cmd;
2990 ScsiCfgData *pSpi;
2991
2992 ddvtprintk((" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
2993 pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0]));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002994
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
2996 return;
2997
2998 cmd = pReq->CDB[0];
2999
3000 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
3001 pSpi = &hd->ioc->spi_data;
3002 if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
3003 /* Set NEED_DV for all hidden disks
3004 */
3005 Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk;
3006 int numPDisk = pSpi->pIocPg3->NumPhysDisks;
3007
3008 while (numPDisk) {
3009 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
3010 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
3011 pPDisk++;
3012 numPDisk--;
3013 }
3014 }
3015 pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
3016 ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
3017 }
3018}
3019
3020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3021/*
3022 * If no Target, bus reset on 1st I/O. Set the flag to
3023 * prevent any future negotiations to this device.
3024 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003025static void
3026mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027{
3028
3029 if ((hd->Targets) && (hd->Targets[target_id] == NULL))
3030 hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
3031
3032 return;
3033}
3034
3035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3036/*
3037 * SCSI Config Page functionality ...
3038 */
3039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3040/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
3041 * based on width, factor and offset parameters.
3042 * @width: bus width
3043 * @factor: sync factor
3044 * @offset: sync offset
3045 * @requestedPtr: pointer to requested values (updated)
3046 * @configurationPtr: pointer to configuration values (updated)
3047 * @flags: flags to block WDTR or SDTR negotiation
3048 *
3049 * Return: None.
3050 *
3051 * Remark: Called by writeSDP1 and _dv_params
3052 */
3053static void
3054mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3055{
3056 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3057 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3058
3059 *configurationPtr = 0;
3060 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3061 *requestedPtr |= (offset << 16) | (factor << 8);
3062
3063 if (width && offset && !nowide && !nosync) {
3064 if (factor < MPT_ULTRA160) {
3065 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3066 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3067 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3068 if (flags & MPT_TAPE_NEGO_IDP)
3069 *requestedPtr |= 0x08000000;
3070 } else if (factor < MPT_ULTRA2) {
3071 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3072 }
3073 }
3074
3075 if (nowide)
3076 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3077
3078 if (nosync)
3079 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3080
3081 return;
3082}
3083
3084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3085/* mptscsih_writeSDP1 - write SCSI Device Page 1
3086 * @hd: Pointer to a SCSI Host Strucutre
3087 * @portnum: IOC port number
3088 * @target_id: writeSDP1 for single ID
3089 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3090 *
3091 * Return: -EFAULT if read of config page header fails
3092 * or 0 if success.
3093 *
3094 * Remark: If a target has been found, the settings from the
3095 * target structure are used, else the device is set
3096 * to async/narrow.
3097 *
3098 * Remark: Called during init and after a FW reload.
3099 * Remark: We do not wait for a return, write pages sequentially.
3100 */
3101static int
3102mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3103{
3104 MPT_ADAPTER *ioc = hd->ioc;
3105 Config_t *pReq;
3106 SCSIDevicePage1_t *pData;
3107 VirtDevice *pTarget;
3108 MPT_FRAME_HDR *mf;
3109 dma_addr_t dataDma;
3110 u16 req_idx;
3111 u32 frameOffset;
3112 u32 requested, configuration, flagsLength;
3113 int ii, nvram;
3114 int id = 0, maxid = 0;
3115 u8 width;
3116 u8 factor;
3117 u8 offset;
3118 u8 bus = 0;
3119 u8 negoFlags;
3120 u8 maxwidth, maxoffset, maxfactor;
3121
3122 if (ioc->spi_data.sdp1length == 0)
3123 return 0;
3124
3125 if (flags & MPT_SCSICFG_ALL_IDS) {
3126 id = 0;
3127 maxid = ioc->sh->max_id - 1;
3128 } else if (ioc->sh) {
3129 id = target_id;
3130 maxid = min_t(int, id, ioc->sh->max_id - 1);
3131 }
3132
3133 for (; id <= maxid; id++) {
3134
3135 if (id == ioc->pfacts[portnum].PortSCSIID)
3136 continue;
3137
3138 /* Use NVRAM to get adapter and target maximums
3139 * Data over-riden by target structure information, if present
3140 */
3141 maxwidth = ioc->spi_data.maxBusWidth;
3142 maxoffset = ioc->spi_data.maxSyncOffset;
3143 maxfactor = ioc->spi_data.minSyncFactor;
3144 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3145 nvram = ioc->spi_data.nvram[id];
3146
3147 if (maxwidth)
3148 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3149
3150 if (maxoffset > 0) {
3151 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3152 if (maxfactor == 0) {
3153 /* Key for async */
3154 maxfactor = MPT_ASYNC;
3155 maxoffset = 0;
3156 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3157 maxfactor = ioc->spi_data.minSyncFactor;
3158 }
3159 } else
3160 maxfactor = MPT_ASYNC;
3161 }
3162
3163 /* Set the negotiation flags.
3164 */
3165 negoFlags = ioc->spi_data.noQas;
3166 if (!maxwidth)
3167 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3168
3169 if (!maxoffset)
3170 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3171
3172 if (flags & MPT_SCSICFG_USE_NVRAM) {
3173 width = maxwidth;
3174 factor = maxfactor;
3175 offset = maxoffset;
3176 } else {
3177 width = 0;
3178 factor = MPT_ASYNC;
3179 offset = 0;
3180 //negoFlags = 0;
3181 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3182 }
3183
3184 /* If id is not a raid volume, get the updated
3185 * transmission settings from the target structure.
3186 */
3187 if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3188 width = pTarget->maxWidth;
3189 factor = pTarget->minSyncFactor;
3190 offset = pTarget->maxOffset;
3191 negoFlags = pTarget->negoFlags;
3192 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003193
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3195 /* Force to async and narrow if DV has not been executed
3196 * for this ID
3197 */
3198 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3199 width = 0;
3200 factor = MPT_ASYNC;
3201 offset = 0;
3202 }
3203#endif
3204
3205 if (flags & MPT_SCSICFG_BLK_NEGO)
3206 negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
3207
3208 mptscsih_setDevicePage1Flags(width, factor, offset,
3209 &requested, &configuration, negoFlags);
3210 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3211 target_id, width, factor, offset, negoFlags, requested, configuration));
3212
3213 /* Get a MF for this command.
3214 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003215 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3217 ioc->name));
3218 return -EAGAIN;
3219 }
3220
3221 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3222 hd->ioc->name, mf, id, requested, configuration));
3223
3224
3225 /* Set the request and the data pointers.
3226 * Request takes: 36 bytes (32 bit SGE)
3227 * SCSI Device Page 1 requires 16 bytes
3228 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3229 * and MF size >= 64 bytes.
3230 * Place data at end of MF.
3231 */
3232 pReq = (Config_t *)mf;
3233
3234 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3235 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3236
3237 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3238 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3239
3240 /* Complete the request frame (same for all requests).
3241 */
3242 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3243 pReq->Reserved = 0;
3244 pReq->ChainOffset = 0;
3245 pReq->Function = MPI_FUNCTION_CONFIG;
3246 pReq->ExtPageLength = 0;
3247 pReq->ExtPageType = 0;
3248 pReq->MsgFlags = 0;
3249 for (ii=0; ii < 8; ii++) {
3250 pReq->Reserved2[ii] = 0;
3251 }
3252 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3253 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3254 pReq->Header.PageNumber = 1;
3255 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3256 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3257
3258 /* Add a SGE to the config request.
3259 */
3260 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3261
3262 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3263
3264 /* Set up the common data portion
3265 */
3266 pData->Header.PageVersion = pReq->Header.PageVersion;
3267 pData->Header.PageLength = pReq->Header.PageLength;
3268 pData->Header.PageNumber = pReq->Header.PageNumber;
3269 pData->Header.PageType = pReq->Header.PageType;
3270 pData->RequestedParameters = cpu_to_le32(requested);
3271 pData->Reserved = 0;
3272 pData->Configuration = cpu_to_le32(configuration);
3273
3274 dprintk((MYIOC_s_INFO_FMT
3275 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3276 ioc->name, id, (id | (bus<<8)),
3277 requested, configuration));
3278
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003279 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
3281
3282 return 0;
3283}
3284
3285/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3286/* mptscsih_writeIOCPage4 - write IOC Page 4
3287 * @hd: Pointer to a SCSI Host Structure
3288 * @target_id: write IOC Page4 for this ID & Bus
3289 *
3290 * Return: -EAGAIN if unable to obtain a Message Frame
3291 * or 0 if success.
3292 *
3293 * Remark: We do not wait for a return, write pages sequentially.
3294 */
3295static int
3296mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3297{
3298 MPT_ADAPTER *ioc = hd->ioc;
3299 Config_t *pReq;
3300 IOCPage4_t *IOCPage4Ptr;
3301 MPT_FRAME_HDR *mf;
3302 dma_addr_t dataDma;
3303 u16 req_idx;
3304 u32 frameOffset;
3305 u32 flagsLength;
3306 int ii;
3307
3308 /* Get a MF for this command.
3309 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003310 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
3312 ioc->name));
3313 return -EAGAIN;
3314 }
3315
3316 /* Set the request and the data pointers.
3317 * Place data at end of MF.
3318 */
3319 pReq = (Config_t *)mf;
3320
3321 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3322 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3323
3324 /* Complete the request frame (same for all requests).
3325 */
3326 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3327 pReq->Reserved = 0;
3328 pReq->ChainOffset = 0;
3329 pReq->Function = MPI_FUNCTION_CONFIG;
3330 pReq->ExtPageLength = 0;
3331 pReq->ExtPageType = 0;
3332 pReq->MsgFlags = 0;
3333 for (ii=0; ii < 8; ii++) {
3334 pReq->Reserved2[ii] = 0;
3335 }
3336
3337 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3338 dataDma = ioc->spi_data.IocPg4_dma;
3339 ii = IOCPage4Ptr->ActiveSEP++;
3340 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3341 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3342 pReq->Header = IOCPage4Ptr->Header;
3343 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3344
3345 /* Add a SGE to the config request.
3346 */
3347 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3348 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3349
3350 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3351
3352 dinitprintk((MYIOC_s_INFO_FMT
3353 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3354 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3355
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003356 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
3358 return 0;
3359}
3360
3361/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3362/*
3363 * Bus Scan and Domain Validation functionality ...
3364 */
3365
3366/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3367/*
3368 * mptscsih_scandv_complete - Scan and DV callback routine registered
3369 * to Fustion MPT (base) driver.
3370 *
3371 * @ioc: Pointer to MPT_ADAPTER structure
3372 * @mf: Pointer to original MPT request frame
3373 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3374 *
3375 * This routine is called from mpt.c::mpt_interrupt() at the completion
3376 * of any SCSI IO request.
3377 * This routine is registered with the Fusion MPT (base) driver at driver
3378 * load/init time via the mpt_register() API call.
3379 *
3380 * Returns 1 indicating alloc'd request frame ptr should be freed.
3381 *
3382 * Remark: Sets a completion code and (possibly) saves sense data
3383 * in the IOC member localReply structure.
3384 * Used ONLY for DV and other internal commands.
3385 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003386int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3388{
3389 MPT_SCSI_HOST *hd;
3390 SCSIIORequest_t *pReq;
3391 int completionCode;
3392 u16 req_idx;
3393
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003394 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3395
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 if ((mf == NULL) ||
3397 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3398 printk(MYIOC_s_ERR_FMT
3399 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3400 ioc->name, mf?"BAD":"NULL", (void *) mf);
3401 goto wakeup;
3402 }
3403
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 del_timer(&hd->timer);
3405 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3406 hd->ScsiLookup[req_idx] = NULL;
3407 pReq = (SCSIIORequest_t *) mf;
3408
3409 if (mf != hd->cmdPtr) {
3410 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3411 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3412 }
3413 hd->cmdPtr = NULL;
3414
3415 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3416 hd->ioc->name, mf, mr, req_idx));
3417
3418 hd->pLocal = &hd->localReply;
3419 hd->pLocal->scsiStatus = 0;
3420
3421 /* If target struct exists, clear sense valid flag.
3422 */
3423 if (mr == NULL) {
3424 completionCode = MPT_SCANDV_GOOD;
3425 } else {
3426 SCSIIOReply_t *pReply;
3427 u16 status;
3428 u8 scsi_status;
3429
3430 pReply = (SCSIIOReply_t *) mr;
3431
3432 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3433 scsi_status = pReply->SCSIStatus;
3434
3435 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3436 status, pReply->SCSIState, scsi_status,
3437 le32_to_cpu(pReply->IOCLogInfo)));
3438
3439 switch(status) {
3440
3441 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3442 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3443 break;
3444
3445 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3446 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3447 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3448 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3449 completionCode = MPT_SCANDV_DID_RESET;
3450 break;
3451
3452 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3453 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3454 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3455 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3456 ConfigReply_t *pr = (ConfigReply_t *)mr;
3457 completionCode = MPT_SCANDV_GOOD;
3458 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3459 hd->pLocal->header.PageLength = pr->Header.PageLength;
3460 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3461 hd->pLocal->header.PageType = pr->Header.PageType;
3462
3463 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3464 /* If the RAID Volume request is successful,
3465 * return GOOD, else indicate that
3466 * some type of error occurred.
3467 */
3468 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
3469 if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
3470 completionCode = MPT_SCANDV_GOOD;
3471 else
3472 completionCode = MPT_SCANDV_SOME_ERROR;
3473
3474 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3475 u8 *sense_data;
3476 int sz;
3477
3478 /* save sense data in global structure
3479 */
3480 completionCode = MPT_SCANDV_SENSE;
3481 hd->pLocal->scsiStatus = scsi_status;
3482 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3483 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3484
3485 sz = min_t(int, pReq->SenseBufferLength,
3486 SCSI_STD_SENSE_BYTES);
3487 memcpy(hd->pLocal->sense, sense_data, sz);
3488
3489 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3490 sense_data));
3491 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3492 if (pReq->CDB[0] == INQUIRY)
3493 completionCode = MPT_SCANDV_ISSUE_SENSE;
3494 else
3495 completionCode = MPT_SCANDV_DID_RESET;
3496 }
3497 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3498 completionCode = MPT_SCANDV_DID_RESET;
3499 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3500 completionCode = MPT_SCANDV_DID_RESET;
3501 else {
3502 completionCode = MPT_SCANDV_GOOD;
3503 hd->pLocal->scsiStatus = scsi_status;
3504 }
3505 break;
3506
3507 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3508 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3509 completionCode = MPT_SCANDV_DID_RESET;
3510 else
3511 completionCode = MPT_SCANDV_SOME_ERROR;
3512 break;
3513
3514 default:
3515 completionCode = MPT_SCANDV_SOME_ERROR;
3516 break;
3517
3518 } /* switch(status) */
3519
3520 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3521 completionCode));
3522 } /* end of address reply case */
3523
3524 hd->pLocal->completion = completionCode;
3525
3526 /* MF and RF are freed in mpt_interrupt
3527 */
3528wakeup:
3529 /* Free Chain buffers (will never chain) in scan or dv */
3530 //mptscsih_freeChainBuffers(ioc, req_idx);
3531
3532 /*
3533 * Wake up the original calling thread
3534 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003535 hd->scandv_wait_done = 1;
3536 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
3538 return 1;
3539}
3540
3541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3542/* mptscsih_timer_expired - Call back for timer process.
3543 * Used only for dv functionality.
3544 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3545 *
3546 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003547void
3548mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549{
3550 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3551
3552 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3553
3554 if (hd->cmdPtr) {
3555 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3556
3557 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3558 /* Desire to issue a task management request here.
3559 * TM requests MUST be single threaded.
3560 * If old eh code and no TM current, issue request.
3561 * If new eh code, do nothing. Wait for OS cmd timeout
3562 * for bus reset.
3563 */
3564 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3565 } else {
3566 /* Perform a FW reload */
3567 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3568 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3569 }
3570 }
3571 } else {
3572 /* This should NEVER happen */
3573 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3574 }
3575
3576 /* No more processing.
3577 * TM call will generate an interrupt for SCSI TM Management.
3578 * The FW will reply to all outstanding commands, callback will finish cleanup.
3579 * Hard reset clean-up will free all resources.
3580 */
3581 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3582
3583 return;
3584}
3585
3586#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3588/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3589 * @hd: Pointer to scsi host structure
3590 * @action: What do be done.
3591 * @id: Logical target id.
3592 * @bus: Target locations bus.
3593 *
3594 * Returns: < 0 on a fatal error
3595 * 0 on success
3596 *
3597 * Remark: Wait to return until reply processed by the ISR.
3598 */
3599static int
3600mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3601{
3602 MpiRaidActionRequest_t *pReq;
3603 MPT_FRAME_HDR *mf;
3604 int in_isr;
3605
3606 in_isr = in_interrupt();
3607 if (in_isr) {
3608 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3609 hd->ioc->name));
3610 return -EPERM;
3611 }
3612
3613 /* Get and Populate a free Frame
3614 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003615 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3617 hd->ioc->name));
3618 return -EAGAIN;
3619 }
3620 pReq = (MpiRaidActionRequest_t *)mf;
3621 pReq->Action = action;
3622 pReq->Reserved1 = 0;
3623 pReq->ChainOffset = 0;
3624 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3625 pReq->VolumeID = io->id;
3626 pReq->VolumeBus = io->bus;
3627 pReq->PhysDiskNum = io->physDiskNum;
3628 pReq->MsgFlags = 0;
3629 pReq->Reserved2 = 0;
3630 pReq->ActionDataWord = 0; /* Reserved for this action */
3631 //pReq->ActionDataSGE = 0;
3632
3633 mpt_add_sge((char *)&pReq->ActionDataSGE,
3634 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3635
3636 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3637 hd->ioc->name, action, io->id));
3638
3639 hd->pLocal = NULL;
3640 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003641 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642
3643 /* Save cmd pointer, for resource free if timeout or
3644 * FW reload occurs
3645 */
3646 hd->cmdPtr = mf;
3647
3648 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003649 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3650 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651
3652 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3653 return -1;
3654
3655 return 0;
3656}
3657#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3658
3659/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3660/**
3661 * mptscsih_do_cmd - Do internal command.
3662 * @hd: MPT_SCSI_HOST pointer
3663 * @io: INTERNAL_CMD pointer.
3664 *
3665 * Issue the specified internally generated command and do command
3666 * specific cleanup. For bus scan / DV only.
3667 * NOTES: If command is Inquiry and status is good,
3668 * initialize a target structure, save the data
3669 *
3670 * Remark: Single threaded access only.
3671 *
3672 * Return:
3673 * < 0 if an illegal command or no resources
3674 *
3675 * 0 if good
3676 *
3677 * > 0 if command complete but some type of completion error.
3678 */
3679static int
3680mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3681{
3682 MPT_FRAME_HDR *mf;
3683 SCSIIORequest_t *pScsiReq;
3684 SCSIIORequest_t ReqCopy;
3685 int my_idx, ii, dir;
3686 int rc, cmdTimeout;
3687 int in_isr;
3688 char cmdLen;
3689 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3690 char cmd = io->cmd;
3691
3692 in_isr = in_interrupt();
3693 if (in_isr) {
3694 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3695 hd->ioc->name));
3696 return -EPERM;
3697 }
3698
3699
3700 /* Set command specific information
3701 */
3702 switch (cmd) {
3703 case INQUIRY:
3704 cmdLen = 6;
3705 dir = MPI_SCSIIO_CONTROL_READ;
3706 CDB[0] = cmd;
3707 CDB[4] = io->size;
3708 cmdTimeout = 10;
3709 break;
3710
3711 case TEST_UNIT_READY:
3712 cmdLen = 6;
3713 dir = MPI_SCSIIO_CONTROL_READ;
3714 cmdTimeout = 10;
3715 break;
3716
3717 case START_STOP:
3718 cmdLen = 6;
3719 dir = MPI_SCSIIO_CONTROL_READ;
3720 CDB[0] = cmd;
3721 CDB[4] = 1; /*Spin up the disk */
3722 cmdTimeout = 15;
3723 break;
3724
3725 case REQUEST_SENSE:
3726 cmdLen = 6;
3727 CDB[0] = cmd;
3728 CDB[4] = io->size;
3729 dir = MPI_SCSIIO_CONTROL_READ;
3730 cmdTimeout = 10;
3731 break;
3732
3733 case READ_BUFFER:
3734 cmdLen = 10;
3735 dir = MPI_SCSIIO_CONTROL_READ;
3736 CDB[0] = cmd;
3737 if (io->flags & MPT_ICFLAG_ECHO) {
3738 CDB[1] = 0x0A;
3739 } else {
3740 CDB[1] = 0x02;
3741 }
3742
3743 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3744 CDB[1] |= 0x01;
3745 }
3746 CDB[6] = (io->size >> 16) & 0xFF;
3747 CDB[7] = (io->size >> 8) & 0xFF;
3748 CDB[8] = io->size & 0xFF;
3749 cmdTimeout = 10;
3750 break;
3751
3752 case WRITE_BUFFER:
3753 cmdLen = 10;
3754 dir = MPI_SCSIIO_CONTROL_WRITE;
3755 CDB[0] = cmd;
3756 if (io->flags & MPT_ICFLAG_ECHO) {
3757 CDB[1] = 0x0A;
3758 } else {
3759 CDB[1] = 0x02;
3760 }
3761 CDB[6] = (io->size >> 16) & 0xFF;
3762 CDB[7] = (io->size >> 8) & 0xFF;
3763 CDB[8] = io->size & 0xFF;
3764 cmdTimeout = 10;
3765 break;
3766
3767 case RESERVE:
3768 cmdLen = 6;
3769 dir = MPI_SCSIIO_CONTROL_READ;
3770 CDB[0] = cmd;
3771 cmdTimeout = 10;
3772 break;
3773
3774 case RELEASE:
3775 cmdLen = 6;
3776 dir = MPI_SCSIIO_CONTROL_READ;
3777 CDB[0] = cmd;
3778 cmdTimeout = 10;
3779 break;
3780
3781 case SYNCHRONIZE_CACHE:
3782 cmdLen = 10;
3783 dir = MPI_SCSIIO_CONTROL_READ;
3784 CDB[0] = cmd;
3785// CDB[1] = 0x02; /* set immediate bit */
3786 cmdTimeout = 10;
3787 break;
3788
3789 default:
3790 /* Error Case */
3791 return -EFAULT;
3792 }
3793
3794 /* Get and Populate a free Frame
3795 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003796 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3798 hd->ioc->name));
3799 return -EBUSY;
3800 }
3801
3802 pScsiReq = (SCSIIORequest_t *) mf;
3803
3804 /* Get the request index */
3805 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3806 ADD_INDEX_LOG(my_idx); /* for debug */
3807
3808 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3809 pScsiReq->TargetID = io->physDiskNum;
3810 pScsiReq->Bus = 0;
3811 pScsiReq->ChainOffset = 0;
3812 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3813 } else {
3814 pScsiReq->TargetID = io->id;
3815 pScsiReq->Bus = io->bus;
3816 pScsiReq->ChainOffset = 0;
3817 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3818 }
3819
3820 pScsiReq->CDBLength = cmdLen;
3821 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3822
3823 pScsiReq->Reserved = 0;
3824
3825 pScsiReq->MsgFlags = mpt_msg_flags();
3826 /* MsgContext set in mpt_get_msg_fram call */
3827
3828 for (ii=0; ii < 8; ii++)
3829 pScsiReq->LUN[ii] = 0;
3830 pScsiReq->LUN[1] = io->lun;
3831
3832 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3833 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3834 else
3835 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3836
3837 if (cmd == REQUEST_SENSE) {
3838 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3839 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3840 hd->ioc->name, cmd));
3841 }
3842
3843 for (ii=0; ii < 16; ii++)
3844 pScsiReq->CDB[ii] = CDB[ii];
3845
3846 pScsiReq->DataLength = cpu_to_le32(io->size);
3847 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3848 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3849
3850 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3851 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3852
3853 if (dir == MPI_SCSIIO_CONTROL_READ) {
3854 mpt_add_sge((char *) &pScsiReq->SGL,
3855 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3856 io->data_dma);
3857 } else {
3858 mpt_add_sge((char *) &pScsiReq->SGL,
3859 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3860 io->data_dma);
3861 }
3862
3863 /* The ISR will free the request frame, but we need
3864 * the information to initialize the target. Duplicate.
3865 */
3866 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3867
3868 /* Issue this command after:
3869 * finish init
3870 * add timer
3871 * Wait until the reply has been received
3872 * ScsiScanDvCtx callback function will
3873 * set hd->pLocal;
3874 * set scandv_wait_done and call wake_up
3875 */
3876 hd->pLocal = NULL;
3877 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003878 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
3880 /* Save cmd pointer, for resource free if timeout or
3881 * FW reload occurs
3882 */
3883 hd->cmdPtr = mf;
3884
3885 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003886 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3887 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888
3889 if (hd->pLocal) {
3890 rc = hd->pLocal->completion;
3891 hd->pLocal->skip = 0;
3892
3893 /* Always set fatal error codes in some cases.
3894 */
3895 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3896 rc = -ENXIO;
3897 else if (rc == MPT_SCANDV_SOME_ERROR)
3898 rc = -rc;
3899 } else {
3900 rc = -EFAULT;
3901 /* This should never happen. */
3902 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3903 hd->ioc->name));
3904 }
3905
3906 return rc;
3907}
3908
3909/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3910/**
3911 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3912 * @hd: Pointer to MPT_SCSI_HOST structure
3913 * @portnum: IOC port number
3914 *
3915 * Uses the ISR, but with special processing.
3916 * MUST be single-threaded.
3917 *
3918 * Return: 0 on completion
3919 */
3920static int
3921mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
3922{
3923 MPT_ADAPTER *ioc= hd->ioc;
3924 VirtDevice *pTarget;
3925 SCSIDevicePage1_t *pcfg1Data = NULL;
3926 INTERNAL_CMD iocmd;
3927 CONFIGPARMS cfg;
3928 dma_addr_t cfg1_dma_addr = -1;
3929 ConfigPageHeader_t header1;
3930 int bus = 0;
3931 int id = 0;
3932 int lun;
3933 int indexed_lun, lun_index;
3934 int hostId = ioc->pfacts[portnum].PortSCSIID;
3935 int max_id;
3936 int requested, configuration, data;
3937 int doConfig = 0;
3938 u8 flags, factor;
3939
3940 max_id = ioc->sh->max_id - 1;
3941
3942 /* Following parameters will not change
3943 * in this routine.
3944 */
3945 iocmd.cmd = SYNCHRONIZE_CACHE;
3946 iocmd.flags = 0;
3947 iocmd.physDiskNum = -1;
3948 iocmd.data = NULL;
3949 iocmd.data_dma = -1;
3950 iocmd.size = 0;
3951 iocmd.rsvd = iocmd.rsvd2 = 0;
3952
3953 /* No SCSI hosts
3954 */
3955 if (hd->Targets == NULL)
3956 return 0;
3957
3958 /* Skip the host
3959 */
3960 if (id == hostId)
3961 id++;
3962
3963 /* Write SDP1 for all SCSI devices
3964 * Alloc memory and set up config buffer
3965 */
3966 if (ioc->bus_type == SCSI) {
3967 if (ioc->spi_data.sdp1length > 0) {
3968 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3969 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3970
3971 if (pcfg1Data != NULL) {
3972 doConfig = 1;
3973 header1.PageVersion = ioc->spi_data.sdp1version;
3974 header1.PageLength = ioc->spi_data.sdp1length;
3975 header1.PageNumber = 1;
3976 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3977 cfg.hdr = &header1;
3978 cfg.physAddr = cfg1_dma_addr;
3979 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3980 cfg.dir = 1;
3981 cfg.timeout = 0;
3982 }
3983 }
3984 }
3985
3986 /* loop through all devices on this port
3987 */
3988 while (bus < MPT_MAX_BUS) {
3989 iocmd.bus = bus;
3990 iocmd.id = id;
3991 pTarget = hd->Targets[(int)id];
3992
3993 if (doConfig) {
3994
3995 /* Set the negotiation flags */
3996 if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3997 flags = pTarget->negoFlags;
3998 } else {
3999 flags = hd->ioc->spi_data.noQas;
4000 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4001 data = hd->ioc->spi_data.nvram[id];
4002
4003 if (data & MPT_NVRAM_WIDE_DISABLE)
4004 flags |= MPT_TARGET_NO_NEGO_WIDE;
4005
4006 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
4007 if ((factor == 0) || (factor == MPT_ASYNC))
4008 flags |= MPT_TARGET_NO_NEGO_SYNC;
4009 }
4010 }
4011
4012 /* Force to async, narrow */
4013 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
4014 &configuration, flags);
4015 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
4016 "offset=0 negoFlags=%x request=%x config=%x\n",
4017 id, flags, requested, configuration));
4018 pcfg1Data->RequestedParameters = le32_to_cpu(requested);
4019 pcfg1Data->Reserved = 0;
4020 pcfg1Data->Configuration = le32_to_cpu(configuration);
4021 cfg.pageAddr = (bus<<8) | id;
4022 mpt_config(hd->ioc, &cfg);
4023 }
4024
4025 /* If target Ptr NULL or if this target is NOT a disk, skip.
4026 */
4027 if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
4028 for (lun=0; lun <= MPT_LAST_LUN; lun++) {
4029 /* If LUN present, issue the command
4030 */
4031 lun_index = (lun >> 5); /* 32 luns per lun_index */
4032 indexed_lun = (lun % 32);
4033 if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
4034 iocmd.lun = lun;
4035 (void) mptscsih_do_cmd(hd, &iocmd);
4036 }
4037 }
4038 }
4039
4040 /* get next relevant device */
4041 id++;
4042
4043 if (id == hostId)
4044 id++;
4045
4046 if (id > max_id) {
4047 id = 0;
4048 bus++;
4049 }
4050 }
4051
4052 if (pcfg1Data) {
4053 pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
4054 }
4055
4056 return 0;
4057}
4058
4059#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
4060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4061/**
4062 * mptscsih_domainValidation - Top level handler for domain validation.
4063 * @hd: Pointer to MPT_SCSI_HOST structure.
4064 *
4065 * Uses the ISR, but with special processing.
4066 * Called from schedule, should not be in interrupt mode.
4067 * While thread alive, do dv for all devices needing dv
4068 *
4069 * Return: None.
4070 */
4071static void
4072mptscsih_domainValidation(void *arg)
4073{
4074 MPT_SCSI_HOST *hd;
4075 MPT_ADAPTER *ioc;
4076 unsigned long flags;
4077 int id, maxid, dvStatus, did;
4078 int ii, isPhysDisk;
4079
4080 spin_lock_irqsave(&dvtaskQ_lock, flags);
4081 dvtaskQ_active = 1;
4082 if (dvtaskQ_release) {
4083 dvtaskQ_active = 0;
4084 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4085 return;
4086 }
4087 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4088
4089 /* For this ioc, loop through all devices and do dv to each device.
4090 * When complete with this ioc, search through the ioc list, and
4091 * for each scsi ioc found, do dv for all devices. Exit when no
4092 * device needs dv.
4093 */
4094 did = 1;
4095 while (did) {
4096 did = 0;
4097 list_for_each_entry(ioc, &ioc_list, list) {
4098 spin_lock_irqsave(&dvtaskQ_lock, flags);
4099 if (dvtaskQ_release) {
4100 dvtaskQ_active = 0;
4101 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4102 return;
4103 }
4104 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4105
4106 msleep(250);
4107
4108 /* DV only to SCSI adapters */
4109 if (ioc->bus_type != SCSI)
4110 continue;
4111
4112 /* Make sure everything looks ok */
4113 if (ioc->sh == NULL)
4114 continue;
4115
4116 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4117 if (hd == NULL)
4118 continue;
4119
4120 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4121 mpt_read_ioc_pg_3(ioc);
4122 if (ioc->spi_data.pIocPg3) {
4123 Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
4124 int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
4125
4126 while (numPDisk) {
4127 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4128 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4129
4130 pPDisk++;
4131 numPDisk--;
4132 }
4133 }
4134 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4135 }
4136
4137 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4138
4139 for (id = 0; id < maxid; id++) {
4140 spin_lock_irqsave(&dvtaskQ_lock, flags);
4141 if (dvtaskQ_release) {
4142 dvtaskQ_active = 0;
4143 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4144 return;
4145 }
4146 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4147 dvStatus = hd->ioc->spi_data.dvStatus[id];
4148
4149 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4150 did++;
4151 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4152 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4153
4154 msleep(250);
4155
4156 /* If hidden phys disk, block IO's to all
4157 * raid volumes
4158 * else, process normally
4159 */
4160 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
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 (mptscsih_doDv(hd, 0, id) == 1) {
4170 /* Untagged device was busy, try again
4171 */
4172 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4173 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4174 } else {
4175 /* DV is complete. Clear flags.
4176 */
4177 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4178 }
4179
4180 if (isPhysDisk) {
4181 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4182 if (hd->ioc->spi_data.isRaid & (1 << ii)) {
4183 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4184 }
4185 }
4186 }
4187
4188 if (hd->ioc->spi_data.noQas)
4189 mptscsih_qas_check(hd, id);
4190 }
4191 }
4192 }
4193 }
4194
4195 spin_lock_irqsave(&dvtaskQ_lock, flags);
4196 dvtaskQ_active = 0;
4197 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4198
4199 return;
4200}
4201
4202/* Search IOC page 3 to determine if this is hidden physical disk
4203 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004204static int
4205mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206{
4207 if (ioc->spi_data.pIocPg3) {
4208 Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
4209 int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
4210
4211 while (numPDisk) {
4212 if (pPDisk->PhysDiskID == id) {
4213 return 1;
4214 }
4215 pPDisk++;
4216 numPDisk--;
4217 }
4218 }
4219 return 0;
4220}
4221
4222/* Write SDP1 if no QAS has been enabled
4223 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004224static void
4225mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226{
4227 VirtDevice *pTarget;
4228 int ii;
4229
4230 if (hd->Targets == NULL)
4231 return;
4232
4233 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4234 if (ii == id)
4235 continue;
4236
4237 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4238 continue;
4239
4240 pTarget = hd->Targets[ii];
4241
4242 if ((pTarget != NULL) && (!pTarget->raidVolume)) {
4243 if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4244 pTarget->negoFlags |= hd->ioc->spi_data.noQas;
4245 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4246 mptscsih_writeSDP1(hd, 0, ii, 0);
4247 }
4248 } else {
4249 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4250 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4251 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4252 }
4253 }
4254 }
4255 return;
4256}
4257
4258
4259
4260#define MPT_GET_NVRAM_VALS 0x01
4261#define MPT_UPDATE_MAX 0x02
4262#define MPT_SET_MAX 0x04
4263#define MPT_SET_MIN 0x08
4264#define MPT_FALLBACK 0x10
4265#define MPT_SAVE 0x20
4266
4267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4268/**
4269 * mptscsih_doDv - Perform domain validation to a target.
4270 * @hd: Pointer to MPT_SCSI_HOST structure.
4271 * @portnum: IOC port number.
4272 * @target: Physical ID of this target
4273 *
4274 * Uses the ISR, but with special processing.
4275 * MUST be single-threaded.
4276 * Test will exit if target is at async & narrow.
4277 *
4278 * Return: None.
4279 */
4280static int
4281mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4282{
4283 MPT_ADAPTER *ioc = hd->ioc;
4284 VirtDevice *pTarget;
4285 SCSIDevicePage1_t *pcfg1Data;
4286 SCSIDevicePage0_t *pcfg0Data;
4287 u8 *pbuf1;
4288 u8 *pbuf2;
4289 u8 *pDvBuf;
4290 dma_addr_t dvbuf_dma = -1;
4291 dma_addr_t buf1_dma = -1;
4292 dma_addr_t buf2_dma = -1;
4293 dma_addr_t cfg1_dma_addr = -1;
4294 dma_addr_t cfg0_dma_addr = -1;
4295 ConfigPageHeader_t header1;
4296 ConfigPageHeader_t header0;
4297 DVPARAMETERS dv;
4298 INTERNAL_CMD iocmd;
4299 CONFIGPARMS cfg;
4300 int dv_alloc = 0;
4301 int rc, sz = 0;
4302 int bufsize = 0;
4303 int dataBufSize = 0;
4304 int echoBufSize = 0;
4305 int notDone;
4306 int patt;
4307 int repeat;
4308 int retcode = 0;
4309 int nfactor = MPT_ULTRA320;
4310 char firstPass = 1;
4311 char doFallback = 0;
4312 char readPage0;
4313 char bus, lun;
4314 char inq0 = 0;
4315
4316 if (ioc->spi_data.sdp1length == 0)
4317 return 0;
4318
4319 if (ioc->spi_data.sdp0length == 0)
4320 return 0;
4321
4322 /* If multiple buses are used, require that the initiator
4323 * id be the same on all buses.
4324 */
4325 if (id == ioc->pfacts[0].PortSCSIID)
4326 return 0;
4327
4328 lun = 0;
4329 bus = (u8) bus_number;
4330 ddvtprintk((MYIOC_s_NOTE_FMT
4331 "DV started: bus=%d, id=%d dv @ %p\n",
4332 ioc->name, bus, id, &dv));
4333
4334 /* Prep DV structure
4335 */
4336 memset (&dv, 0, sizeof(DVPARAMETERS));
4337 dv.id = id;
4338
4339 /* Populate tmax with the current maximum
4340 * transfer parameters for this target.
4341 * Exit if narrow and async.
4342 */
4343 dv.cmd = MPT_GET_NVRAM_VALS;
4344 mptscsih_dv_parms(hd, &dv, NULL);
4345
4346 /* Prep SCSI IO structure
4347 */
4348 iocmd.id = id;
4349 iocmd.bus = bus;
4350 iocmd.lun = lun;
4351 iocmd.flags = 0;
4352 iocmd.physDiskNum = -1;
4353 iocmd.rsvd = iocmd.rsvd2 = 0;
4354
4355 pTarget = hd->Targets[id];
4356
4357 /* Use tagged commands if possible.
4358 */
4359 if (pTarget) {
4360 if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
4361 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4362 else {
4363 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4364 return 0;
4365
4366 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4367 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4368 return 0;
4369 }
4370 }
4371
4372 /* Prep cfg structure
4373 */
4374 cfg.pageAddr = (bus<<8) | id;
4375 cfg.hdr = NULL;
4376
4377 /* Prep SDP0 header
4378 */
4379 header0.PageVersion = ioc->spi_data.sdp0version;
4380 header0.PageLength = ioc->spi_data.sdp0length;
4381 header0.PageNumber = 0;
4382 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4383
4384 /* Prep SDP1 header
4385 */
4386 header1.PageVersion = ioc->spi_data.sdp1version;
4387 header1.PageLength = ioc->spi_data.sdp1length;
4388 header1.PageNumber = 1;
4389 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4390
4391 if (header0.PageLength & 1)
4392 dv_alloc = (header0.PageLength * 4) + 4;
4393
4394 dv_alloc += (2048 + (header1.PageLength * 4));
4395
4396 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4397 if (pDvBuf == NULL)
4398 return 0;
4399
4400 sz = 0;
4401 pbuf1 = (u8 *)pDvBuf;
4402 buf1_dma = dvbuf_dma;
4403 sz +=1024;
4404
4405 pbuf2 = (u8 *) (pDvBuf + sz);
4406 buf2_dma = dvbuf_dma + sz;
4407 sz +=1024;
4408
4409 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4410 cfg0_dma_addr = dvbuf_dma + sz;
4411 sz += header0.PageLength * 4;
4412
4413 /* 8-byte alignment
4414 */
4415 if (header0.PageLength & 1)
4416 sz += 4;
4417
4418 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4419 cfg1_dma_addr = dvbuf_dma + sz;
4420
4421 /* Skip this ID? Set cfg.hdr to force config page write
4422 */
4423 {
4424 ScsiCfgData *pspi_data = &hd->ioc->spi_data;
4425 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4426 /* Set the factor from nvram */
4427 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4428 if (nfactor < pspi_data->minSyncFactor )
4429 nfactor = pspi_data->minSyncFactor;
4430
4431 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4432 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4433
4434 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4435 ioc->name, bus, id, lun));
4436
4437 dv.cmd = MPT_SET_MAX;
4438 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4439 cfg.hdr = &header1;
4440
4441 /* Save the final negotiated settings to
4442 * SCSI device page 1.
4443 */
4444 cfg.physAddr = cfg1_dma_addr;
4445 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4446 cfg.dir = 1;
4447 mpt_config(hd->ioc, &cfg);
4448 goto target_done;
4449 }
4450 }
4451 }
4452
4453 /* Finish iocmd inititialization - hidden or visible disk? */
4454 if (ioc->spi_data.pIocPg3) {
4455 /* Search IOC page 3 for matching id
4456 */
4457 Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
4458 int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
4459
4460 while (numPDisk) {
4461 if (pPDisk->PhysDiskID == id) {
4462 /* match */
4463 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4464 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4465
4466 /* Quiesce the IM
4467 */
4468 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4469 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4470 goto target_done;
4471 }
4472 break;
4473 }
4474 pPDisk++;
4475 numPDisk--;
4476 }
4477 }
4478
4479 /* RAID Volume ID's may double for a physical device. If RAID but
4480 * not a physical ID as well, skip DV.
4481 */
4482 if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
4483 goto target_done;
4484
4485
4486 /* Basic Test.
4487 * Async & Narrow - Inquiry
4488 * Async & Narrow - Inquiry
4489 * Maximum transfer rate - Inquiry
4490 * Compare buffers:
4491 * If compare, test complete.
4492 * If miscompare and first pass, repeat
4493 * If miscompare and not first pass, fall back and repeat
4494 */
4495 hd->pLocal = NULL;
4496 readPage0 = 0;
4497 sz = SCSI_MAX_INQUIRY_BYTES;
4498 rc = MPT_SCANDV_GOOD;
4499 while (1) {
4500 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4501 retcode = 0;
4502 dv.cmd = MPT_SET_MIN;
4503 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4504
4505 cfg.hdr = &header1;
4506 cfg.physAddr = cfg1_dma_addr;
4507 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4508 cfg.dir = 1;
4509 if (mpt_config(hd->ioc, &cfg) != 0)
4510 goto target_done;
4511
4512 /* Wide - narrow - wide workaround case
4513 */
4514 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4515 /* Send an untagged command to reset disk Qs corrupted
4516 * when a parity error occurs on a Request Sense.
4517 */
4518 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4519 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4520 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4521
4522 iocmd.cmd = REQUEST_SENSE;
4523 iocmd.data_dma = buf1_dma;
4524 iocmd.data = pbuf1;
4525 iocmd.size = 0x12;
4526 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4527 goto target_done;
4528 else {
4529 if (hd->pLocal == NULL)
4530 goto target_done;
4531 rc = hd->pLocal->completion;
4532 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4533 dv.max.width = 0;
4534 doFallback = 0;
4535 } else
4536 goto target_done;
4537 }
4538 } else
4539 goto target_done;
4540 }
4541
4542 iocmd.cmd = INQUIRY;
4543 iocmd.data_dma = buf1_dma;
4544 iocmd.data = pbuf1;
4545 iocmd.size = sz;
4546 memset(pbuf1, 0x00, sz);
4547 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4548 goto target_done;
4549 else {
4550 if (hd->pLocal == NULL)
4551 goto target_done;
4552 rc = hd->pLocal->completion;
4553 if (rc == MPT_SCANDV_GOOD) {
4554 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4555 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4556 retcode = 1;
4557 else
4558 retcode = 0;
4559
4560 goto target_done;
4561 }
4562 } else if (rc == MPT_SCANDV_SENSE) {
4563 ;
4564 } else {
4565 /* If first command doesn't complete
4566 * with a good status or with a check condition,
4567 * exit.
4568 */
4569 goto target_done;
4570 }
4571 }
4572
4573 /* Reset the size for disks
4574 */
4575 inq0 = (*pbuf1) & 0x1F;
4576 if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
4577 sz = 0x40;
4578 iocmd.size = sz;
4579 }
4580
4581 /* Another GEM workaround. Check peripheral device type,
4582 * if PROCESSOR, quit DV.
4583 */
4584 if (inq0 == TYPE_PROCESSOR) {
4585 mptscsih_initTarget(hd,
4586 bus,
4587 id,
4588 lun,
4589 pbuf1,
4590 sz);
4591 goto target_done;
4592 }
4593
4594 if (inq0 > 0x08)
4595 goto target_done;
4596
4597 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4598 goto target_done;
4599
4600 if (sz == 0x40) {
4601 if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
4602 && (pTarget->minSyncFactor > 0x09)) {
4603 if ((pbuf1[56] & 0x04) == 0)
4604 ;
4605 else if ((pbuf1[56] & 0x01) == 1) {
4606 pTarget->minSyncFactor =
4607 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4608 } else {
4609 pTarget->minSyncFactor =
4610 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4611 }
4612
4613 dv.max.factor = pTarget->minSyncFactor;
4614
4615 if ((pbuf1[56] & 0x02) == 0) {
4616 pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
4617 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
4618 ddvprintk((MYIOC_s_NOTE_FMT
4619 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
4620 ioc->name, id, pbuf1[56]));
4621 }
4622 }
4623 }
4624
4625 if (doFallback)
4626 dv.cmd = MPT_FALLBACK;
4627 else
4628 dv.cmd = MPT_SET_MAX;
4629
4630 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4631 if (mpt_config(hd->ioc, &cfg) != 0)
4632 goto target_done;
4633
4634 if ((!dv.now.width) && (!dv.now.offset))
4635 goto target_done;
4636
4637 iocmd.cmd = INQUIRY;
4638 iocmd.data_dma = buf2_dma;
4639 iocmd.data = pbuf2;
4640 iocmd.size = sz;
4641 memset(pbuf2, 0x00, sz);
4642 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4643 goto target_done;
4644 else if (hd->pLocal == NULL)
4645 goto target_done;
4646 else {
4647 /* Save the return code.
4648 * If this is the first pass,
4649 * read SCSI Device Page 0
4650 * and update the target max parameters.
4651 */
4652 rc = hd->pLocal->completion;
4653 doFallback = 0;
4654 if (rc == MPT_SCANDV_GOOD) {
4655 if (!readPage0) {
4656 u32 sdp0_info;
4657 u32 sdp0_nego;
4658
4659 cfg.hdr = &header0;
4660 cfg.physAddr = cfg0_dma_addr;
4661 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4662 cfg.dir = 0;
4663
4664 if (mpt_config(hd->ioc, &cfg) != 0)
4665 goto target_done;
4666
4667 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4668 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4669
4670 /* Quantum and Fujitsu workarounds.
4671 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4672 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4673 * Resetart with a request for U160.
4674 */
4675 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4676 doFallback = 1;
4677 } else {
4678 dv.cmd = MPT_UPDATE_MAX;
4679 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4680 /* Update the SCSI device page 1 area
4681 */
4682 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4683 readPage0 = 1;
4684 }
4685 }
4686
4687 /* Quantum workaround. Restart this test will the fallback
4688 * flag set.
4689 */
4690 if (doFallback == 0) {
4691 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4692 if (!firstPass)
4693 doFallback = 1;
4694 } else {
4695 ddvprintk((MYIOC_s_NOTE_FMT
4696 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4697 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4698 mptscsih_initTarget(hd,
4699 bus,
4700 id,
4701 lun,
4702 pbuf1,
4703 sz);
4704 break; /* test complete */
4705 }
4706 }
4707
4708
4709 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4710 doFallback = 1; /* set fallback flag */
4711 else if ((rc == MPT_SCANDV_DID_RESET) ||
4712 (rc == MPT_SCANDV_SENSE) ||
4713 (rc == MPT_SCANDV_FALLBACK))
4714 doFallback = 1; /* set fallback flag */
4715 else
4716 goto target_done;
4717
4718 firstPass = 0;
4719 }
4720 }
4721 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4722
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004723 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 goto target_done;
4725
4726 inq0 = (*pbuf1) & 0x1F;
4727
4728 /* Continue only for disks
4729 */
4730 if (inq0 != 0)
4731 goto target_done;
4732
4733 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4734 goto target_done;
4735
4736 /* Start the Enhanced Test.
4737 * 0) issue TUR to clear out check conditions
4738 * 1) read capacity of echo (regular) buffer
4739 * 2) reserve device
4740 * 3) do write-read-compare data pattern test
4741 * 4) release
4742 * 5) update nego parms to target struct
4743 */
4744 cfg.hdr = &header1;
4745 cfg.physAddr = cfg1_dma_addr;
4746 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4747 cfg.dir = 1;
4748
4749 iocmd.cmd = TEST_UNIT_READY;
4750 iocmd.data_dma = -1;
4751 iocmd.data = NULL;
4752 iocmd.size = 0;
4753 notDone = 1;
4754 while (notDone) {
4755 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4756 goto target_done;
4757
4758 if (hd->pLocal == NULL)
4759 goto target_done;
4760
4761 rc = hd->pLocal->completion;
4762 if (rc == MPT_SCANDV_GOOD)
4763 notDone = 0;
4764 else if (rc == MPT_SCANDV_SENSE) {
4765 u8 skey = hd->pLocal->sense[2] & 0x0F;
4766 u8 asc = hd->pLocal->sense[12];
4767 u8 ascq = hd->pLocal->sense[13];
4768 ddvprintk((MYIOC_s_INFO_FMT
4769 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4770 ioc->name, skey, asc, ascq));
4771
4772 if (skey == UNIT_ATTENTION)
4773 notDone++; /* repeat */
4774 else if ((skey == NOT_READY) &&
4775 (asc == 0x04)&&(ascq == 0x01)) {
4776 /* wait then repeat */
4777 mdelay (2000);
4778 notDone++;
4779 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4780 /* no medium, try read test anyway */
4781 notDone = 0;
4782 } else {
4783 /* All other errors are fatal.
4784 */
4785 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4786 ioc->name));
4787 goto target_done;
4788 }
4789 } else
4790 goto target_done;
4791 }
4792
4793 iocmd.cmd = READ_BUFFER;
4794 iocmd.data_dma = buf1_dma;
4795 iocmd.data = pbuf1;
4796 iocmd.size = 4;
4797 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4798
4799 dataBufSize = 0;
4800 echoBufSize = 0;
4801 for (patt = 0; patt < 2; patt++) {
4802 if (patt == 0)
4803 iocmd.flags |= MPT_ICFLAG_ECHO;
4804 else
4805 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4806
4807 notDone = 1;
4808 while (notDone) {
4809 bufsize = 0;
4810
4811 /* If not ready after 8 trials,
4812 * give up on this device.
4813 */
4814 if (notDone > 8)
4815 goto target_done;
4816
4817 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4818 goto target_done;
4819 else if (hd->pLocal == NULL)
4820 goto target_done;
4821 else {
4822 rc = hd->pLocal->completion;
4823 ddvprintk(("ReadBuffer Comp Code %d", rc));
4824 ddvprintk((" buff: %0x %0x %0x %0x\n",
4825 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4826
4827 if (rc == MPT_SCANDV_GOOD) {
4828 notDone = 0;
4829 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4830 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
4831 } else {
4832 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4833 }
4834 } else if (rc == MPT_SCANDV_SENSE) {
4835 u8 skey = hd->pLocal->sense[2] & 0x0F;
4836 u8 asc = hd->pLocal->sense[12];
4837 u8 ascq = hd->pLocal->sense[13];
4838 ddvprintk((MYIOC_s_INFO_FMT
4839 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4840 ioc->name, skey, asc, ascq));
4841 if (skey == ILLEGAL_REQUEST) {
4842 notDone = 0;
4843 } else if (skey == UNIT_ATTENTION) {
4844 notDone++; /* repeat */
4845 } else if ((skey == NOT_READY) &&
4846 (asc == 0x04)&&(ascq == 0x01)) {
4847 /* wait then repeat */
4848 mdelay (2000);
4849 notDone++;
4850 } else {
4851 /* All other errors are fatal.
4852 */
4853 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4854 ioc->name));
4855 goto target_done;
4856 }
4857 } else {
4858 /* All other errors are fatal
4859 */
4860 goto target_done;
4861 }
4862 }
4863 }
4864
4865 if (iocmd.flags & MPT_ICFLAG_ECHO)
4866 echoBufSize = bufsize;
4867 else
4868 dataBufSize = bufsize;
4869 }
4870 sz = 0;
4871 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4872
4873 /* Use echo buffers if possible,
4874 * Exit if both buffers are 0.
4875 */
4876 if (echoBufSize > 0) {
4877 iocmd.flags |= MPT_ICFLAG_ECHO;
4878 if (dataBufSize > 0)
4879 bufsize = min(echoBufSize, dataBufSize);
4880 else
4881 bufsize = echoBufSize;
4882 } else if (dataBufSize == 0)
4883 goto target_done;
4884
4885 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4886 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4887
4888 /* Data buffers for write-read-compare test max 1K.
4889 */
4890 sz = min(bufsize, 1024);
4891
4892 /* --- loop ----
4893 * On first pass, always issue a reserve.
4894 * On additional loops, only if a reset has occurred.
4895 * iocmd.flags indicates if echo or regular buffer
4896 */
4897 for (patt = 0; patt < 4; patt++) {
4898 ddvprintk(("Pattern %d\n", patt));
4899 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4900 iocmd.cmd = TEST_UNIT_READY;
4901 iocmd.data_dma = -1;
4902 iocmd.data = NULL;
4903 iocmd.size = 0;
4904 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4905 goto target_done;
4906
4907 iocmd.cmd = RELEASE;
4908 iocmd.data_dma = -1;
4909 iocmd.data = NULL;
4910 iocmd.size = 0;
4911 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4912 goto target_done;
4913 else if (hd->pLocal == NULL)
4914 goto target_done;
4915 else {
4916 rc = hd->pLocal->completion;
4917 ddvprintk(("Release rc %d\n", rc));
4918 if (rc == MPT_SCANDV_GOOD)
4919 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4920 else
4921 goto target_done;
4922 }
4923 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4924 }
4925 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4926
4927 repeat = 5;
4928 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4929 iocmd.cmd = RESERVE;
4930 iocmd.data_dma = -1;
4931 iocmd.data = NULL;
4932 iocmd.size = 0;
4933 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4934 goto target_done;
4935 else if (hd->pLocal == NULL)
4936 goto target_done;
4937 else {
4938 rc = hd->pLocal->completion;
4939 if (rc == MPT_SCANDV_GOOD) {
4940 iocmd.flags |= MPT_ICFLAG_RESERVED;
4941 } else if (rc == MPT_SCANDV_SENSE) {
4942 /* Wait if coming ready
4943 */
4944 u8 skey = hd->pLocal->sense[2] & 0x0F;
4945 u8 asc = hd->pLocal->sense[12];
4946 u8 ascq = hd->pLocal->sense[13];
4947 ddvprintk((MYIOC_s_INFO_FMT
4948 "DV: Reserve Failed: ", ioc->name));
4949 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4950 skey, asc, ascq));
4951
4952 if ((skey == NOT_READY) && (asc == 0x04)&&
4953 (ascq == 0x01)) {
4954 /* wait then repeat */
4955 mdelay (2000);
4956 notDone++;
4957 } else {
4958 ddvprintk((MYIOC_s_INFO_FMT
4959 "DV: Reserved Failed.", ioc->name));
4960 goto target_done;
4961 }
4962 } else {
4963 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4964 ioc->name));
4965 goto target_done;
4966 }
4967 }
4968 }
4969
4970 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4971 iocmd.cmd = WRITE_BUFFER;
4972 iocmd.data_dma = buf1_dma;
4973 iocmd.data = pbuf1;
4974 iocmd.size = sz;
4975 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4976 goto target_done;
4977 else if (hd->pLocal == NULL)
4978 goto target_done;
4979 else {
4980 rc = hd->pLocal->completion;
4981 if (rc == MPT_SCANDV_GOOD)
4982 ; /* Issue read buffer */
4983 else if (rc == MPT_SCANDV_DID_RESET) {
4984 /* If using echo buffers, reset to data buffers.
4985 * Else do Fallback and restart
4986 * this test (re-issue reserve
4987 * because of bus reset).
4988 */
4989 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4990 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4991 } else {
4992 dv.cmd = MPT_FALLBACK;
4993 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4994
4995 if (mpt_config(hd->ioc, &cfg) != 0)
4996 goto target_done;
4997
4998 if ((!dv.now.width) && (!dv.now.offset))
4999 goto target_done;
5000 }
5001
5002 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5003 patt = -1;
5004 continue;
5005 } else if (rc == MPT_SCANDV_SENSE) {
5006 /* Restart data test if UA, else quit.
5007 */
5008 u8 skey = hd->pLocal->sense[2] & 0x0F;
5009 ddvprintk((MYIOC_s_INFO_FMT
5010 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5011 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5012 if (skey == UNIT_ATTENTION) {
5013 patt = -1;
5014 continue;
5015 } else if (skey == ILLEGAL_REQUEST) {
5016 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5017 if (dataBufSize >= bufsize) {
5018 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5019 patt = -1;
5020 continue;
5021 }
5022 }
5023 goto target_done;
5024 }
5025 else
5026 goto target_done;
5027 } else {
5028 /* fatal error */
5029 goto target_done;
5030 }
5031 }
5032
5033 iocmd.cmd = READ_BUFFER;
5034 iocmd.data_dma = buf2_dma;
5035 iocmd.data = pbuf2;
5036 iocmd.size = sz;
5037 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5038 goto target_done;
5039 else if (hd->pLocal == NULL)
5040 goto target_done;
5041 else {
5042 rc = hd->pLocal->completion;
5043 if (rc == MPT_SCANDV_GOOD) {
5044 /* If buffers compare,
5045 * go to next pattern,
5046 * else, do a fallback and restart
5047 * data transfer test.
5048 */
5049 if (memcmp (pbuf1, pbuf2, sz) == 0) {
5050 ; /* goto next pattern */
5051 } else {
5052 /* Miscompare with Echo buffer, go to data buffer,
5053 * if that buffer exists.
5054 * Miscompare with Data buffer, check first 4 bytes,
5055 * some devices return capacity. Exit in this case.
5056 */
5057 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5058 if (dataBufSize >= bufsize)
5059 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5060 else
5061 goto target_done;
5062 } else {
5063 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
5064 /* Argh. Device returning wrong data.
5065 * Quit DV for this device.
5066 */
5067 goto target_done;
5068 }
5069
5070 /* Had an actual miscompare. Slow down.*/
5071 dv.cmd = MPT_FALLBACK;
5072 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5073
5074 if (mpt_config(hd->ioc, &cfg) != 0)
5075 goto target_done;
5076
5077 if ((!dv.now.width) && (!dv.now.offset))
5078 goto target_done;
5079 }
5080
5081 patt = -1;
5082 continue;
5083 }
5084 } else if (rc == MPT_SCANDV_DID_RESET) {
5085 /* Do Fallback and restart
5086 * this test (re-issue reserve
5087 * because of bus reset).
5088 */
5089 dv.cmd = MPT_FALLBACK;
5090 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5091
5092 if (mpt_config(hd->ioc, &cfg) != 0)
5093 goto target_done;
5094
5095 if ((!dv.now.width) && (!dv.now.offset))
5096 goto target_done;
5097
5098 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5099 patt = -1;
5100 continue;
5101 } else if (rc == MPT_SCANDV_SENSE) {
5102 /* Restart data test if UA, else quit.
5103 */
5104 u8 skey = hd->pLocal->sense[2] & 0x0F;
5105 ddvprintk((MYIOC_s_INFO_FMT
5106 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5107 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5108 if (skey == UNIT_ATTENTION) {
5109 patt = -1;
5110 continue;
5111 }
5112 else
5113 goto target_done;
5114 } else {
5115 /* fatal error */
5116 goto target_done;
5117 }
5118 }
5119
5120 } /* --- end of patt loop ---- */
5121
5122target_done:
5123 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5124 iocmd.cmd = RELEASE;
5125 iocmd.data_dma = -1;
5126 iocmd.data = NULL;
5127 iocmd.size = 0;
5128 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5129 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5130 ioc->name, id);
5131 else if (hd->pLocal) {
5132 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5133 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5134 } else {
5135 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5136 ioc->name, id);
5137 }
5138 }
5139
5140
5141 /* Set if cfg1_dma_addr contents is valid
5142 */
5143 if ((cfg.hdr != NULL) && (retcode == 0)){
5144 /* If disk, not U320, disable QAS
5145 */
5146 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5147 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
5148 ddvprintk((MYIOC_s_NOTE_FMT
5149 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5150 }
5151
5152 dv.cmd = MPT_SAVE;
5153 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5154
5155 /* Double writes to SDP1 can cause problems,
5156 * skip save of the final negotiated settings to
5157 * SCSI device page 1.
5158 *
5159 cfg.hdr = &header1;
5160 cfg.physAddr = cfg1_dma_addr;
5161 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5162 cfg.dir = 1;
5163 mpt_config(hd->ioc, &cfg);
5164 */
5165 }
5166
5167 /* If this is a RAID Passthrough, enable internal IOs
5168 */
5169 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5170 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5171 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5172 }
5173
5174 /* Done with the DV scan of the current target
5175 */
5176 if (pDvBuf)
5177 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5178
5179 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5180 ioc->name, id));
5181
5182 return retcode;
5183}
5184
5185/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5186/* mptscsih_dv_parms - perform a variety of operations on the
5187 * parameters used for negotiation.
5188 * @hd: Pointer to a SCSI host.
5189 * @dv: Pointer to a structure that contains the maximum and current
5190 * negotiated parameters.
5191 */
5192static void
5193mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5194{
5195 VirtDevice *pTarget;
5196 SCSIDevicePage0_t *pPage0;
5197 SCSIDevicePage1_t *pPage1;
5198 int val = 0, data, configuration;
5199 u8 width = 0;
5200 u8 offset = 0;
5201 u8 factor = 0;
5202 u8 negoFlags = 0;
5203 u8 cmd = dv->cmd;
5204 u8 id = dv->id;
5205
5206 switch (cmd) {
5207 case MPT_GET_NVRAM_VALS:
5208 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5209 hd->ioc->name));
5210 /* Get the NVRAM values and save in tmax
5211 * If not an LVD bus, the adapter minSyncFactor has been
5212 * already throttled back.
5213 */
5214 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
5215 width = pTarget->maxWidth;
5216 offset = pTarget->maxOffset;
5217 factor = pTarget->minSyncFactor;
5218 negoFlags = pTarget->negoFlags;
5219 } else {
5220 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5221 data = hd->ioc->spi_data.nvram[id];
5222 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5223 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5224 factor = MPT_ASYNC;
5225 else {
5226 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5227 if ((factor == 0) || (factor == MPT_ASYNC)){
5228 factor = MPT_ASYNC;
5229 offset = 0;
5230 }
5231 }
5232 } else {
5233 width = MPT_NARROW;
5234 offset = 0;
5235 factor = MPT_ASYNC;
5236 }
5237
5238 /* Set the negotiation flags */
5239 negoFlags = hd->ioc->spi_data.noQas;
5240 if (!width)
5241 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5242
5243 if (!offset)
5244 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5245 }
5246
5247 /* limit by adapter capabilities */
5248 width = min(width, hd->ioc->spi_data.maxBusWidth);
5249 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5250 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5251
5252 /* Check Consistency */
5253 if (offset && (factor < MPT_ULTRA2) && !width)
5254 factor = MPT_ULTRA2;
5255
5256 dv->max.width = width;
5257 dv->max.offset = offset;
5258 dv->max.factor = factor;
5259 dv->max.flags = negoFlags;
5260 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5261 id, width, factor, offset, negoFlags));
5262 break;
5263
5264 case MPT_UPDATE_MAX:
5265 ddvprintk((MYIOC_s_NOTE_FMT
5266 "Updating with SDP0 Data: ", hd->ioc->name));
5267 /* Update tmax values with those from Device Page 0.*/
5268 pPage0 = (SCSIDevicePage0_t *) pPage;
5269 if (pPage0) {
5270 val = cpu_to_le32(pPage0->NegotiatedParameters);
5271 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5272 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5273 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5274 }
5275
5276 dv->now.width = dv->max.width;
5277 dv->now.offset = dv->max.offset;
5278 dv->now.factor = dv->max.factor;
5279 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5280 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5281 break;
5282
5283 case MPT_SET_MAX:
5284 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5285 hd->ioc->name));
5286 /* Set current to the max values. Update the config page.*/
5287 dv->now.width = dv->max.width;
5288 dv->now.offset = dv->max.offset;
5289 dv->now.factor = dv->max.factor;
5290 dv->now.flags = dv->max.flags;
5291
5292 pPage1 = (SCSIDevicePage1_t *)pPage;
5293 if (pPage1) {
5294 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5295 dv->now.offset, &val, &configuration, dv->now.flags);
5296 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5297 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5298 pPage1->RequestedParameters = le32_to_cpu(val);
5299 pPage1->Reserved = 0;
5300 pPage1->Configuration = le32_to_cpu(configuration);
5301 }
5302
5303 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x request=%x configuration=%x\n",
5304 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5305 break;
5306
5307 case MPT_SET_MIN:
5308 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5309 hd->ioc->name));
5310 /* Set page to asynchronous and narrow
5311 * Do not update now, breaks fallback routine. */
5312 width = MPT_NARROW;
5313 offset = 0;
5314 factor = MPT_ASYNC;
5315 negoFlags = dv->max.flags;
5316
5317 pPage1 = (SCSIDevicePage1_t *)pPage;
5318 if (pPage1) {
5319 mptscsih_setDevicePage1Flags (width, factor,
5320 offset, &val, &configuration, negoFlags);
5321 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5322 id, width, factor, offset, negoFlags, val, configuration));
5323 pPage1->RequestedParameters = le32_to_cpu(val);
5324 pPage1->Reserved = 0;
5325 pPage1->Configuration = le32_to_cpu(configuration);
5326 }
5327 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5328 id, width, factor, offset, val, configuration, negoFlags));
5329 break;
5330
5331 case MPT_FALLBACK:
5332 ddvprintk((MYIOC_s_NOTE_FMT
5333 "Fallback: Start: offset %d, factor %x, width %d \n",
5334 hd->ioc->name, dv->now.offset,
5335 dv->now.factor, dv->now.width));
5336 width = dv->now.width;
5337 offset = dv->now.offset;
5338 factor = dv->now.factor;
5339 if ((offset) && (dv->max.width)) {
5340 if (factor < MPT_ULTRA160)
5341 factor = MPT_ULTRA160;
5342 else if (factor < MPT_ULTRA2) {
5343 factor = MPT_ULTRA2;
5344 width = MPT_WIDE;
5345 } else if ((factor == MPT_ULTRA2) && width) {
5346 factor = MPT_ULTRA2;
5347 width = MPT_NARROW;
5348 } else if (factor < MPT_ULTRA) {
5349 factor = MPT_ULTRA;
5350 width = MPT_WIDE;
5351 } else if ((factor == MPT_ULTRA) && width) {
5352 width = MPT_NARROW;
5353 } else if (factor < MPT_FAST) {
5354 factor = MPT_FAST;
5355 width = MPT_WIDE;
5356 } else if ((factor == MPT_FAST) && width) {
5357 factor = MPT_FAST;
5358 width = MPT_NARROW;
5359 } else if (factor < MPT_SCSI) {
5360 factor = MPT_SCSI;
5361 width = MPT_WIDE;
5362 } else if ((factor == MPT_SCSI) && width) {
5363 factor = MPT_SCSI;
5364 width = MPT_NARROW;
5365 } else {
5366 factor = MPT_ASYNC;
5367 offset = 0;
5368 }
5369
5370 } else if (offset) {
5371 width = MPT_NARROW;
5372 if (factor < MPT_ULTRA)
5373 factor = MPT_ULTRA;
5374 else if (factor < MPT_FAST)
5375 factor = MPT_FAST;
5376 else if (factor < MPT_SCSI)
5377 factor = MPT_SCSI;
5378 else {
5379 factor = MPT_ASYNC;
5380 offset = 0;
5381 }
5382
5383 } else {
5384 width = MPT_NARROW;
5385 factor = MPT_ASYNC;
5386 }
5387 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5388 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5389
5390 dv->now.width = width;
5391 dv->now.offset = offset;
5392 dv->now.factor = factor;
5393 dv->now.flags = dv->max.flags;
5394
5395 pPage1 = (SCSIDevicePage1_t *)pPage;
5396 if (pPage1) {
5397 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5398 &configuration, dv->now.flags);
5399 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x flags=%x request=%x config=%x\n",
5400 id, width, offset, factor, dv->now.flags, val, configuration));
5401
5402 pPage1->RequestedParameters = le32_to_cpu(val);
5403 pPage1->Reserved = 0;
5404 pPage1->Configuration = le32_to_cpu(configuration);
5405 }
5406
5407 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5408 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5409 break;
5410
5411 case MPT_SAVE:
5412 ddvprintk((MYIOC_s_NOTE_FMT
5413 "Saving to Target structure: ", hd->ioc->name));
5414 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5415 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5416
5417 /* Save these values to target structures
5418 * or overwrite nvram (phys disks only).
5419 */
5420
5421 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
5422 pTarget->maxWidth = dv->now.width;
5423 pTarget->maxOffset = dv->now.offset;
5424 pTarget->minSyncFactor = dv->now.factor;
5425 pTarget->negoFlags = dv->now.flags;
5426 } else {
5427 /* Preserv all flags, use
5428 * read-modify-write algorithm
5429 */
5430 if (hd->ioc->spi_data.nvram) {
5431 data = hd->ioc->spi_data.nvram[id];
5432
5433 if (dv->now.width)
5434 data &= ~MPT_NVRAM_WIDE_DISABLE;
5435 else
5436 data |= MPT_NVRAM_WIDE_DISABLE;
5437
5438 if (!dv->now.offset)
5439 factor = MPT_ASYNC;
5440
5441 data &= ~MPT_NVRAM_SYNC_MASK;
5442 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5443
5444 hd->ioc->spi_data.nvram[id] = data;
5445 }
5446 }
5447 break;
5448 }
5449}
5450
5451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5452/* mptscsih_fillbuf - fill a buffer with a special data pattern
5453 * cleanup. For bus scan only.
5454 *
5455 * @buffer: Pointer to data buffer to be filled.
5456 * @size: Number of bytes to fill
5457 * @index: Pattern index
5458 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5459 */
5460static void
5461mptscsih_fillbuf(char *buffer, int size, int index, int width)
5462{
5463 char *ptr = buffer;
5464 int ii;
5465 char byte;
5466 short val;
5467
5468 switch (index) {
5469 case 0:
5470
5471 if (width) {
5472 /* Pattern: 0000 FFFF 0000 FFFF
5473 */
5474 for (ii=0; ii < size; ii++, ptr++) {
5475 if (ii & 0x02)
5476 *ptr = 0xFF;
5477 else
5478 *ptr = 0x00;
5479 }
5480 } else {
5481 /* Pattern: 00 FF 00 FF
5482 */
5483 for (ii=0; ii < size; ii++, ptr++) {
5484 if (ii & 0x01)
5485 *ptr = 0xFF;
5486 else
5487 *ptr = 0x00;
5488 }
5489 }
5490 break;
5491
5492 case 1:
5493 if (width) {
5494 /* Pattern: 5555 AAAA 5555 AAAA 5555
5495 */
5496 for (ii=0; ii < size; ii++, ptr++) {
5497 if (ii & 0x02)
5498 *ptr = 0xAA;
5499 else
5500 *ptr = 0x55;
5501 }
5502 } else {
5503 /* Pattern: 55 AA 55 AA 55
5504 */
5505 for (ii=0; ii < size; ii++, ptr++) {
5506 if (ii & 0x01)
5507 *ptr = 0xAA;
5508 else
5509 *ptr = 0x55;
5510 }
5511 }
5512 break;
5513
5514 case 2:
5515 /* Pattern: 00 01 02 03 04 05
5516 * ... FE FF 00 01..
5517 */
5518 for (ii=0; ii < size; ii++, ptr++)
5519 *ptr = (char) ii;
5520 break;
5521
5522 case 3:
5523 if (width) {
5524 /* Wide Pattern: FFFE 0001 FFFD 0002
5525 * ... 4000 DFFF 8000 EFFF
5526 */
5527 byte = 0;
5528 for (ii=0; ii < size/2; ii++) {
5529 /* Create the base pattern
5530 */
5531 val = (1 << byte);
5532 /* every 64 (0x40) bytes flip the pattern
5533 * since we fill 2 bytes / iteration,
5534 * test for ii = 0x20
5535 */
5536 if (ii & 0x20)
5537 val = ~(val);
5538
5539 if (ii & 0x01) {
5540 *ptr = (char)( (val & 0xFF00) >> 8);
5541 ptr++;
5542 *ptr = (char)(val & 0xFF);
5543 byte++;
5544 byte &= 0x0F;
5545 } else {
5546 val = ~val;
5547 *ptr = (char)( (val & 0xFF00) >> 8);
5548 ptr++;
5549 *ptr = (char)(val & 0xFF);
5550 }
5551
5552 ptr++;
5553 }
5554 } else {
5555 /* Narrow Pattern: FE 01 FD 02 FB 04
5556 * .. 7F 80 01 FE 02 FD ... 80 7F
5557 */
5558 byte = 0;
5559 for (ii=0; ii < size; ii++, ptr++) {
5560 /* Base pattern - first 32 bytes
5561 */
5562 if (ii & 0x01) {
5563 *ptr = (1 << byte);
5564 byte++;
5565 byte &= 0x07;
5566 } else {
5567 *ptr = (char) (~(1 << byte));
5568 }
5569
5570 /* Flip the pattern every 32 bytes
5571 */
5572 if (ii & 0x20)
5573 *ptr = ~(*ptr);
5574 }
5575 }
5576 break;
5577 }
5578}
5579#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5580
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005581EXPORT_SYMBOL(mptscsih_remove);
5582EXPORT_SYMBOL(mptscsih_shutdown);
5583#ifdef CONFIG_PM
5584EXPORT_SYMBOL(mptscsih_suspend);
5585EXPORT_SYMBOL(mptscsih_resume);
5586#endif
5587EXPORT_SYMBOL(mptscsih_proc_info);
5588EXPORT_SYMBOL(mptscsih_info);
5589EXPORT_SYMBOL(mptscsih_qcmd);
5590EXPORT_SYMBOL(mptscsih_slave_alloc);
5591EXPORT_SYMBOL(mptscsih_slave_destroy);
5592EXPORT_SYMBOL(mptscsih_slave_configure);
5593EXPORT_SYMBOL(mptscsih_abort);
5594EXPORT_SYMBOL(mptscsih_dev_reset);
5595EXPORT_SYMBOL(mptscsih_bus_reset);
5596EXPORT_SYMBOL(mptscsih_host_reset);
5597EXPORT_SYMBOL(mptscsih_bios_param);
5598EXPORT_SYMBOL(mptscsih_io_done);
5599EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5600EXPORT_SYMBOL(mptscsih_scandv_complete);
5601EXPORT_SYMBOL(mptscsih_event_process);
5602EXPORT_SYMBOL(mptscsih_ioc_reset);
5603EXPORT_SYMBOL(mptscsih_store_queue_depth);
5604EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005606/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/