blob: cf058a399dab6e558277ad52d6bd3bafef0515d1 [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 0d0c7972005-04-22 18:02:09 -04001001 if (hd->Targets != NULL) {
1002 /*
1003 * Free pointer array.
1004 */
1005 kfree(hd->Targets);
1006 hd->Targets = NULL;
1007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001009 dprintk((MYIOC_s_INFO_FMT
1010 "Free'd ScsiLookup (%d) memory\n",
1011 hd->ioc->name, sz1));
1012
1013 if (hd->info_kbuf != NULL)
1014 kfree(hd->info_kbuf);
1015
1016 /* NULL the Scsi_Host pointer
1017 */
1018 hd->ioc->sh = NULL;
1019
1020 scsi_host_put(host);
1021
1022 mpt_detach(pdev);
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024}
1025
1026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1027/*
1028 * mptscsih_shutdown - reboot notifier
1029 *
1030 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001031void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032mptscsih_shutdown(struct device * dev)
1033{
1034 MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev));
1035 struct Scsi_Host *host = ioc->sh;
1036 MPT_SCSI_HOST *hd;
1037
1038 if(!host)
1039 return;
1040
1041 hd = (MPT_SCSI_HOST *)host->hostdata;
1042
1043 /* Flush the cache of this adapter
1044 */
1045 if(hd != NULL)
1046 mptscsih_synchronize_cache(hd, 0);
1047
1048}
1049
1050#ifdef CONFIG_PM
1051/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1052/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001053 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 *
1055 *
1056 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001057int
Pavel Machek8d189f72005-04-16 15:25:28 -07001058mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
1060 mptscsih_shutdown(&pdev->dev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001061 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/*
1066 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1067 *
1068 *
1069 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001070int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071mptscsih_resume(struct pci_dev *pdev)
1072{
1073 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1074 struct Scsi_Host *host = ioc->sh;
1075 MPT_SCSI_HOST *hd;
1076
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001077 mpt_resume(pdev);
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if(!host)
1080 return 0;
1081
1082 hd = (MPT_SCSI_HOST *)host->hostdata;
1083 if(!hd)
1084 return 0;
1085
1086#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1087 {
1088 unsigned long lflags;
1089 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1090 if (!dvtaskQ_active) {
1091 dvtaskQ_active = 1;
1092 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001093 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001095 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 } else {
1097 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1098 }
1099 }
1100#endif
1101 return 0;
1102}
1103
1104#endif
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1107/**
1108 * mptscsih_info - Return information about MPT adapter
1109 * @SChost: Pointer to Scsi_Host structure
1110 *
1111 * (linux scsi_host_template.info routine)
1112 *
1113 * Returns pointer to buffer where information was written.
1114 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001115const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116mptscsih_info(struct Scsi_Host *SChost)
1117{
1118 MPT_SCSI_HOST *h;
1119 int size = 0;
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001124 if (h->info_kbuf == NULL)
1125 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1126 return h->info_kbuf;
1127 h->info_kbuf[0] = '\0';
1128
1129 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1130 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
1132
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001133 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
1136struct info_str {
1137 char *buffer;
1138 int length;
1139 int offset;
1140 int pos;
1141};
1142
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001143static void
1144mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
1146 if (info->pos + len > info->length)
1147 len = info->length - info->pos;
1148
1149 if (info->pos + len < info->offset) {
1150 info->pos += len;
1151 return;
1152 }
1153
1154 if (info->pos < info->offset) {
1155 data += (info->offset - info->pos);
1156 len -= (info->offset - info->pos);
1157 }
1158
1159 if (len > 0) {
1160 memcpy(info->buffer + info->pos, data, len);
1161 info->pos += len;
1162 }
1163}
1164
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001165static int
1166mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
1168 va_list args;
1169 char buf[81];
1170 int len;
1171
1172 va_start(args, fmt);
1173 len = vsprintf(buf, fmt, args);
1174 va_end(args);
1175
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001176 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return len;
1178}
1179
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180static int
1181mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
1183 struct info_str info;
1184
1185 info.buffer = pbuf;
1186 info.length = len;
1187 info.offset = offset;
1188 info.pos = 0;
1189
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001190 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1191 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1192 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1193 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
1195 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1196}
1197
1198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1199/**
1200 * mptscsih_proc_info - Return information about MPT adapter
1201 *
1202 * (linux scsi_host_template.info routine)
1203 *
1204 * buffer: if write, user data; if read, buffer for user
1205 * length: if write, return length;
1206 * offset: if write, 0; if read, the current offset into the buffer from
1207 * the previous read.
1208 * hostno: scsi host number
1209 * func: if write = 1; if read = 0
1210 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1213 int length, int func)
1214{
1215 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1216 MPT_ADAPTER *ioc = hd->ioc;
1217 int size = 0;
1218
1219 if (func) {
1220 /*
1221 * write is not supported
1222 */
1223 } else {
1224 if (start)
1225 *start = buffer;
1226
1227 size = mptscsih_host_info(ioc, buffer, offset, length);
1228 }
1229
1230 return size;
1231}
1232
1233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1234#define ADD_INDEX_LOG(req_ent) do { } while(0)
1235
1236/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1237/**
1238 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1239 * @SCpnt: Pointer to scsi_cmnd structure
1240 * @done: Pointer SCSI mid-layer IO completion function
1241 *
1242 * (linux scsi_host_template.queuecommand routine)
1243 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1244 * from a linux scsi_cmnd request and send it to the IOC.
1245 *
1246 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1247 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001248int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1250{
1251 MPT_SCSI_HOST *hd;
1252 MPT_FRAME_HDR *mf;
1253 SCSIIORequest_t *pScsiReq;
1254 VirtDevice *pTarget;
1255 int target;
1256 int lun;
1257 u32 datalen;
1258 u32 scsictl;
1259 u32 scsidir;
1260 u32 cmd_len;
1261 int my_idx;
1262 int ii;
1263
1264 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
1265 target = SCpnt->device->id;
1266 lun = SCpnt->device->lun;
1267 SCpnt->scsi_done = done;
1268
1269 pTarget = hd->Targets[target];
1270
1271 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1272 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1273
1274 if (hd->resetPending) {
1275 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1276 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1277 return SCSI_MLQUEUE_HOST_BUSY;
1278 }
1279
1280 /*
1281 * Put together a MPT SCSI request...
1282 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1285 hd->ioc->name));
1286 return SCSI_MLQUEUE_HOST_BUSY;
1287 }
1288
1289 pScsiReq = (SCSIIORequest_t *) mf;
1290
1291 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1292
1293 ADD_INDEX_LOG(my_idx);
1294
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001295 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 * Seems we may receive a buffer (datalen>0) even when there
1297 * will be no data transfer! GRRRRR...
1298 */
1299 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1300 datalen = SCpnt->request_bufflen;
1301 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1302 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1303 datalen = SCpnt->request_bufflen;
1304 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1305 } else {
1306 datalen = 0;
1307 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1308 }
1309
1310 /* Default to untagged. Once a target structure has been allocated,
1311 * use the Inquiry data to determine if device supports tagged.
1312 */
1313 if ( pTarget
1314 && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
1315 && (SCpnt->device->tagged_supported)) {
1316 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1317 } else {
1318 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1319 }
1320
1321 /* Use the above information to set up the message frame
1322 */
1323 pScsiReq->TargetID = (u8) target;
1324 pScsiReq->Bus = (u8) SCpnt->device->channel;
1325 pScsiReq->ChainOffset = 0;
1326 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1327 pScsiReq->CDBLength = SCpnt->cmd_len;
1328 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1329 pScsiReq->Reserved = 0;
1330 pScsiReq->MsgFlags = mpt_msg_flags();
1331 pScsiReq->LUN[0] = 0;
1332 pScsiReq->LUN[1] = lun;
1333 pScsiReq->LUN[2] = 0;
1334 pScsiReq->LUN[3] = 0;
1335 pScsiReq->LUN[4] = 0;
1336 pScsiReq->LUN[5] = 0;
1337 pScsiReq->LUN[6] = 0;
1338 pScsiReq->LUN[7] = 0;
1339 pScsiReq->Control = cpu_to_le32(scsictl);
1340
1341 /*
1342 * Write SCSI CDB into the message
1343 */
1344 cmd_len = SCpnt->cmd_len;
1345 for (ii=0; ii < cmd_len; ii++)
1346 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1347
1348 for (ii=cmd_len; ii < 16; ii++)
1349 pScsiReq->CDB[ii] = 0;
1350
1351 /* DataLength */
1352 pScsiReq->DataLength = cpu_to_le32(datalen);
1353
1354 /* SenseBuffer low address */
1355 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1356 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1357
1358 /* Now add the SG list
1359 * Always have a SGE even if null length.
1360 */
1361 if (datalen == 0) {
1362 /* Add a NULL SGE */
1363 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1364 (dma_addr_t) -1);
1365 } else {
1366 /* Add a 32 or 64 bit SGE */
1367 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1368 goto fail;
1369 }
1370
1371 hd->ScsiLookup[my_idx] = SCpnt;
1372 SCpnt->host_scribble = NULL;
1373
1374#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1375 if (hd->ioc->bus_type == SCSI) {
1376 int dvStatus = hd->ioc->spi_data.dvStatus[target];
1377 int issueCmd = 1;
1378
1379 if (dvStatus || hd->ioc->spi_data.forceDv) {
1380
1381 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1382 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1383 unsigned long lflags;
1384 /* Schedule DV if necessary */
1385 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1386 if (!dvtaskQ_active) {
1387 dvtaskQ_active = 1;
1388 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001389 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001391 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
1393 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1394 }
1395 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1396 }
1397
1398 /* Trying to do DV to this target, extend timeout.
1399 * Wait to issue until flag is clear
1400 */
1401 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1402 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1403 issueCmd = 0;
1404 }
1405
1406 /* Set the DV flags.
1407 */
1408 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
1409 mptscsih_set_dvflags(hd, pScsiReq);
1410
1411 if (!issueCmd)
1412 goto fail;
1413 }
1414 }
1415#endif
1416
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001417 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1419 hd->ioc->name, SCpnt, mf, my_idx));
1420 DBG_DUMP_REQUEST_FRAME(mf)
1421 return 0;
1422
1423 fail:
1424 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1425 mpt_free_msg_frame(hd->ioc, mf);
1426 return SCSI_MLQUEUE_HOST_BUSY;
1427}
1428
1429/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1430/*
1431 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1432 * with a SCSI IO request
1433 * @hd: Pointer to the MPT_SCSI_HOST instance
1434 * @req_idx: Index of the SCSI IO request frame.
1435 *
1436 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1437 * No return.
1438 */
1439static void
1440mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1441{
1442 MPT_FRAME_HDR *chain;
1443 unsigned long flags;
1444 int chain_idx;
1445 int next;
1446
1447 /* Get the first chain index and reset
1448 * tracker state.
1449 */
1450 chain_idx = ioc->ReqToChain[req_idx];
1451 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1452
1453 while (chain_idx != MPT_HOST_NO_CHAIN) {
1454
1455 /* Save the next chain buffer index */
1456 next = ioc->ChainToChain[chain_idx];
1457
1458 /* Free this chain buffer and reset
1459 * tracker
1460 */
1461 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1462
1463 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1464 + (chain_idx * ioc->req_sz));
1465
1466 spin_lock_irqsave(&ioc->FreeQlock, flags);
1467 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1468 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1469
1470 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1471 ioc->name, chain_idx));
1472
1473 /* handle next */
1474 chain_idx = next;
1475 }
1476 return;
1477}
1478
1479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1480/*
1481 * Reset Handling
1482 */
1483
1484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1485/*
1486 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1487 * Fall through to mpt_HardResetHandler if: not operational, too many
1488 * failed TM requests or handshake failure.
1489 *
1490 * @ioc: Pointer to MPT_ADAPTER structure
1491 * @type: Task Management type
1492 * @target: Logical Target ID for reset (if appropriate)
1493 * @lun: Logical Unit for reset (if appropriate)
1494 * @ctx2abort: Context for the task to be aborted (if appropriate)
1495 *
1496 * Remark: Currently invoked from a non-interrupt thread (_bh).
1497 *
1498 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1499 * will be active.
1500 *
1501 * Returns 0 for SUCCESS or -1 if FAILED.
1502 */
1503static int
1504mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1505{
1506 MPT_ADAPTER *ioc;
1507 int rc = -1;
1508 int doTask = 1;
1509 u32 ioc_raw_state;
1510 unsigned long flags;
1511
1512 /* If FW is being reloaded currently, return success to
1513 * the calling function.
1514 */
1515 if (hd == NULL)
1516 return 0;
1517
1518 ioc = hd->ioc;
1519 if (ioc == NULL) {
1520 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1521 return FAILED;
1522 }
1523 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1524
1525 // SJR - CHECKME - Can we avoid this here?
1526 // (mpt_HardResetHandler has this check...)
1527 spin_lock_irqsave(&ioc->diagLock, flags);
1528 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1529 spin_unlock_irqrestore(&ioc->diagLock, flags);
1530 return FAILED;
1531 }
1532 spin_unlock_irqrestore(&ioc->diagLock, flags);
1533
1534 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1535 * If we time out and not bus reset, then we return a FAILED status to the caller.
1536 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1537 * successful. Otherwise, reload the FW.
1538 */
1539 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1540 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
1541 dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: "
1542 "Timed out waiting for last TM (%d) to complete! \n",
1543 hd->ioc->name, hd->tmPending));
1544 return FAILED;
1545 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1546 dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: "
1547 "Timed out waiting for last TM (%d) to complete! \n",
1548 hd->ioc->name, hd->tmPending));
1549 return FAILED;
1550 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
1551 dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: "
1552 "Timed out waiting for last TM (%d) to complete! \n",
1553 hd->ioc->name, hd->tmPending));
1554 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1555 return FAILED;
1556
1557 doTask = 0;
1558 }
1559 } else {
1560 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1561 hd->tmPending |= (1 << type);
1562 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1563 }
1564
1565 /* Is operational?
1566 */
1567 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1568
1569#ifdef MPT_DEBUG_RESET
1570 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1571 printk(MYIOC_s_WARN_FMT
1572 "TM Handler: IOC Not operational(0x%x)!\n",
1573 hd->ioc->name, ioc_raw_state);
1574 }
1575#endif
1576
1577 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1578 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1579
1580 /* Isse the Task Mgmt request.
1581 */
1582 if (hd->hard_resets < -1)
1583 hd->hard_resets++;
1584 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1585 if (rc) {
1586 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1587 } else {
1588 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1589 }
1590 }
1591
1592 /* Only fall through to the HRH if this is a bus reset
1593 */
1594 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1595 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1596 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1597 hd->ioc->name));
1598 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1599 }
1600
1601 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1602
1603 return rc;
1604}
1605
1606
1607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1608/*
1609 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1610 * @hd: Pointer to MPT_SCSI_HOST structure
1611 * @type: Task Management type
1612 * @target: Logical Target ID for reset (if appropriate)
1613 * @lun: Logical Unit for reset (if appropriate)
1614 * @ctx2abort: Context for the task to be aborted (if appropriate)
1615 *
1616 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1617 * or a non-interrupt thread. In the former, must not call schedule().
1618 *
1619 * Not all fields are meaningfull for all task types.
1620 *
1621 * Returns 0 for SUCCESS, -999 for "no msg frames",
1622 * else other non-zero value returned.
1623 */
1624static int
1625mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1626{
1627 MPT_FRAME_HDR *mf;
1628 SCSITaskMgmt_t *pScsiTm;
1629 int ii;
1630 int retval;
1631
1632 /* Return Fail to calling function if no message frames available.
1633 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001634 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1636 hd->ioc->name));
1637 //return FAILED;
1638 return -999;
1639 }
1640 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1641 hd->ioc->name, mf));
1642
1643 /* Format the Request
1644 */
1645 pScsiTm = (SCSITaskMgmt_t *) mf;
1646 pScsiTm->TargetID = target;
1647 pScsiTm->Bus = channel;
1648 pScsiTm->ChainOffset = 0;
1649 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1650
1651 pScsiTm->Reserved = 0;
1652 pScsiTm->TaskType = type;
1653 pScsiTm->Reserved1 = 0;
1654 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1655 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1656
1657 for (ii= 0; ii < 8; ii++) {
1658 pScsiTm->LUN[ii] = 0;
1659 }
1660 pScsiTm->LUN[1] = lun;
1661
1662 for (ii=0; ii < 7; ii++)
1663 pScsiTm->Reserved2[ii] = 0;
1664
1665 pScsiTm->TaskMsgContext = ctx2abort;
1666
1667 dtmprintk((MYIOC_s_INFO_FMT
1668 "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1669 hd->ioc->name, ctx2abort, type));
1670
1671 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1672
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001673 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1675 CAN_SLEEP)) != 0) {
1676 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1677 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1678 hd->ioc, mf));
1679 mpt_free_msg_frame(hd->ioc, mf);
1680 return retval;
1681 }
1682
1683 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1684 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1685 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1686 hd->ioc, mf));
1687 mpt_free_msg_frame(hd->ioc, mf);
1688 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1689 hd->ioc->name));
1690 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1691 }
1692
1693 return retval;
1694}
1695
1696/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1697/**
1698 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1699 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1700 *
1701 * (linux scsi_host_template.eh_abort_handler routine)
1702 *
1703 * Returns SUCCESS or FAILED.
1704 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001705int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706mptscsih_abort(struct scsi_cmnd * SCpnt)
1707{
1708 MPT_SCSI_HOST *hd;
1709 MPT_ADAPTER *ioc;
1710 MPT_FRAME_HDR *mf;
1711 u32 ctx2abort;
1712 int scpnt_idx;
1713 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1714
1715 /* If we can't locate our host adapter structure, return FAILED status.
1716 */
1717 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1718 SCpnt->result = DID_RESET << 16;
1719 SCpnt->scsi_done(SCpnt);
1720 dfailprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
1721 "Can't locate host! (sc=%p)\n",
1722 SCpnt));
1723 return FAILED;
1724 }
1725
1726 ioc = hd->ioc;
1727 if (hd->resetPending)
1728 return FAILED;
1729
1730 printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
1731 hd->ioc->name, SCpnt);
1732
1733 if (hd->timeouts < -1)
1734 hd->timeouts++;
1735
1736 /* Find this command
1737 */
1738 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
1739 /* Cmd not found in ScsiLookup.
1740 * Do OS callback.
1741 */
1742 SCpnt->result = DID_RESET << 16;
1743 dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
1744 "Command not in the active list! (sc=%p)\n",
1745 hd->ioc->name, SCpnt));
1746 return SUCCESS;
1747 }
1748
1749 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1750 * (the IO to be ABORT'd)
1751 *
1752 * NOTE: Since we do not byteswap MsgContext, we do not
1753 * swap it here either. It is an opaque cookie to
1754 * the controller, so it does not matter. -DaveM
1755 */
1756 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1757 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1758
1759 hd->abortSCpnt = SCpnt;
1760
1761 spin_unlock_irq(host_lock);
1762 if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1763 SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
1764 ctx2abort, 2 /* 2 second timeout */)
1765 < 0) {
1766
1767 /* The TM request failed and the subsequent FW-reload failed!
1768 * Fatal error case.
1769 */
1770 printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
1771 hd->ioc->name, SCpnt);
1772
1773 /* We must clear our pending flag before clearing our state.
1774 */
1775 hd->tmPending = 0;
1776 hd->tmState = TM_STATE_NONE;
1777
1778 spin_lock_irq(host_lock);
1779
1780 /* Unmap the DMA buffers, if any. */
1781 if (SCpnt->use_sg) {
1782 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer,
1783 SCpnt->use_sg, SCpnt->sc_data_direction);
1784 } else if (SCpnt->request_bufflen) {
1785 pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle,
1786 SCpnt->request_bufflen, SCpnt->sc_data_direction);
1787 }
1788 hd->ScsiLookup[scpnt_idx] = NULL;
1789 SCpnt->result = DID_RESET << 16;
1790 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
1791 mptscsih_freeChainBuffers(ioc, scpnt_idx);
1792 mpt_free_msg_frame(ioc, mf);
1793 return FAILED;
1794 }
1795 spin_lock_irq(host_lock);
1796 return SUCCESS;
1797}
1798
1799/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1800/**
1801 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1802 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1803 *
1804 * (linux scsi_host_template.eh_dev_reset_handler routine)
1805 *
1806 * Returns SUCCESS or FAILED.
1807 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001808int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1810{
1811 MPT_SCSI_HOST *hd;
1812 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1813
1814 /* If we can't locate our host adapter structure, return FAILED status.
1815 */
1816 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1817 dtmprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
1818 "Can't locate host! (sc=%p)\n",
1819 SCpnt));
1820 return FAILED;
1821 }
1822
1823 if (hd->resetPending)
1824 return FAILED;
1825
1826 printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
1827 hd->ioc->name, SCpnt);
1828
1829 spin_unlock_irq(host_lock);
1830 if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1831 SCpnt->device->channel, SCpnt->device->id,
1832 0, 0, 5 /* 5 second timeout */)
1833 < 0){
1834 /* The TM request failed and the subsequent FW-reload failed!
1835 * Fatal error case.
1836 */
1837 printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
1838 hd->ioc->name, SCpnt);
1839 hd->tmPending = 0;
1840 hd->tmState = TM_STATE_NONE;
1841 spin_lock_irq(host_lock);
1842 return FAILED;
1843 }
1844 spin_lock_irq(host_lock);
1845 return SUCCESS;
1846
1847}
1848
1849/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1850/**
1851 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1852 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1853 *
1854 * (linux scsi_host_template.eh_bus_reset_handler routine)
1855 *
1856 * Returns SUCCESS or FAILED.
1857 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001858int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1860{
1861 MPT_SCSI_HOST *hd;
1862 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1863
1864 /* If we can't locate our host adapter structure, return FAILED status.
1865 */
1866 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1867 dtmprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
1868 "Can't locate host! (sc=%p)\n",
1869 SCpnt ) );
1870 return FAILED;
1871 }
1872
1873 printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
1874 hd->ioc->name, SCpnt);
1875
1876 if (hd->timeouts < -1)
1877 hd->timeouts++;
1878
1879 /* We are now ready to execute the task management request. */
1880 spin_unlock_irq(host_lock);
1881 if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1882 SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */)
1883 < 0){
1884
1885 /* The TM request failed and the subsequent FW-reload failed!
1886 * Fatal error case.
1887 */
1888 printk(MYIOC_s_WARN_FMT
1889 "Error processing TaskMgmt request (sc=%p)\n",
1890 hd->ioc->name, SCpnt);
1891 hd->tmPending = 0;
1892 hd->tmState = TM_STATE_NONE;
1893 spin_lock_irq(host_lock);
1894 return FAILED;
1895 }
1896 spin_lock_irq(host_lock);
1897 return SUCCESS;
1898}
1899
1900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1901/**
1902 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1903 * new_eh variant
1904 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1905 *
1906 * (linux scsi_host_template.eh_host_reset_handler routine)
1907 *
1908 * Returns SUCCESS or FAILED.
1909 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001910int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1912{
1913 MPT_SCSI_HOST * hd;
1914 int status = SUCCESS;
1915 spinlock_t *host_lock = SCpnt->device->host->host_lock;
1916
1917 /* If we can't locate the host to reset, then we failed. */
1918 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
1919 dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
1920 "Can't locate host! (sc=%p)\n",
1921 SCpnt ) );
1922 return FAILED;
1923 }
1924
1925 printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
1926 hd->ioc->name, SCpnt);
1927
1928 /* If our attempts to reset the host failed, then return a failed
1929 * status. The host will be taken off line by the SCSI mid-layer.
1930 */
1931 spin_unlock_irq(host_lock);
1932 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1933 status = FAILED;
1934 } else {
1935 /* Make sure TM pending is cleared and TM state is set to
1936 * NONE.
1937 */
1938 hd->tmPending = 0;
1939 hd->tmState = TM_STATE_NONE;
1940 }
1941 spin_lock_irq(host_lock);
1942
1943
1944 dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
1945 "Status = %s\n",
1946 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1947
1948 return status;
1949}
1950
1951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1952/**
1953 * mptscsih_tm_pending_wait - wait for pending task management request to
1954 * complete.
1955 * @hd: Pointer to MPT host structure.
1956 *
1957 * Returns {SUCCESS,FAILED}.
1958 */
1959static int
1960mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1961{
1962 unsigned long flags;
1963 int loop_count = 4 * 10; /* Wait 10 seconds */
1964 int status = FAILED;
1965
1966 do {
1967 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1968 if (hd->tmState == TM_STATE_NONE) {
1969 hd->tmState = TM_STATE_IN_PROGRESS;
1970 hd->tmPending = 1;
1971 status = SUCCESS;
1972 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1973 break;
1974 }
1975 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1976 msleep(250);
1977 } while (--loop_count);
1978
1979 return status;
1980}
1981
1982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1983/**
1984 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1985 * @hd: Pointer to MPT host structure.
1986 *
1987 * Returns {SUCCESS,FAILED}.
1988 */
1989static int
1990mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1991{
1992 unsigned long flags;
1993 int loop_count = 4 * timeout;
1994 int status = FAILED;
1995
1996 do {
1997 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1998 if(hd->tmPending == 0) {
1999 status = SUCCESS;
2000 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2001 break;
2002 }
2003 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2004 msleep_interruptible(250);
2005 } while (--loop_count);
2006
2007 return status;
2008}
2009
2010/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2011/**
2012 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2013 * @ioc: Pointer to MPT_ADAPTER structure
2014 * @mf: Pointer to SCSI task mgmt request frame
2015 * @mr: Pointer to SCSI task mgmt reply frame
2016 *
2017 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2018 * of any SCSI task management request.
2019 * This routine is registered with the MPT (base) driver at driver
2020 * load/init time via the mpt_register() API call.
2021 *
2022 * Returns 1 indicating alloc'd request frame ptr should be freed.
2023 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002024int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2026{
2027 SCSITaskMgmtReply_t *pScsiTmReply;
2028 SCSITaskMgmt_t *pScsiTmReq;
2029 MPT_SCSI_HOST *hd;
2030 unsigned long flags;
2031 u16 iocstatus;
2032 u8 tmType;
2033
2034 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2035 ioc->name, mf, mr));
2036 if (ioc->sh) {
2037 /* Depending on the thread, a timer is activated for
2038 * the TM request. Delete this timer on completion of TM.
2039 * Decrement count of outstanding TM requests.
2040 */
2041 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2042 } else {
2043 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2044 ioc->name));
2045 return 1;
2046 }
2047
2048 if (mr == NULL) {
2049 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2050 ioc->name, mf));
2051 return 1;
2052 } else {
2053 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2054 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2055
2056 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2057 tmType = pScsiTmReq->TaskType;
2058
2059 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2060 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2061 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2062
2063 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2064 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2065 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2066 /* Error? (anything non-zero?) */
2067 if (iocstatus) {
2068
2069 /* clear flags and continue.
2070 */
2071 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2072 hd->abortSCpnt = NULL;
2073
2074 /* If an internal command is present
2075 * or the TM failed - reload the FW.
2076 * FC FW may respond FAILED to an ABORT
2077 */
2078 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2079 if ((hd->cmdPtr) ||
2080 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2081 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2082 printk((KERN_WARNING
2083 " Firmware Reload FAILED!!\n"));
2084 }
2085 }
2086 }
2087 } else {
2088 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2089
2090 hd->abortSCpnt = NULL;
2091
2092 }
2093 }
2094
2095 spin_lock_irqsave(&ioc->FreeQlock, flags);
2096 hd->tmPending = 0;
2097 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2098 hd->tmState = TM_STATE_NONE;
2099
2100 return 1;
2101}
2102
2103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2104/*
2105 * This is anyones guess quite frankly.
2106 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002107int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2109 sector_t capacity, int geom[])
2110{
2111 int heads;
2112 int sectors;
2113 sector_t cylinders;
2114 ulong dummy;
2115
2116 heads = 64;
2117 sectors = 32;
2118
2119 dummy = heads * sectors;
2120 cylinders = capacity;
2121 sector_div(cylinders,dummy);
2122
2123 /*
2124 * Handle extended translation size for logical drives
2125 * > 1Gb
2126 */
2127 if ((ulong)capacity >= 0x200000) {
2128 heads = 255;
2129 sectors = 63;
2130 dummy = heads * sectors;
2131 cylinders = capacity;
2132 sector_div(cylinders,dummy);
2133 }
2134
2135 /* return result */
2136 geom[0] = heads;
2137 geom[1] = sectors;
2138 geom[2] = cylinders;
2139
2140 dprintk((KERN_NOTICE
2141 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2142 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2143
2144 return 0;
2145}
2146
2147/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2148/*
2149 * OS entry point to allow host driver to alloc memory
2150 * for each scsi device. Called once per device the bus scan.
2151 * Return non-zero if allocation fails.
2152 * Init memory once per id (not LUN).
2153 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002154int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155mptscsih_slave_alloc(struct scsi_device *device)
2156{
2157 struct Scsi_Host *host = device->host;
2158 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2159 VirtDevice *vdev;
2160 uint target = device->id;
2161
2162 if (hd == NULL)
2163 return -ENODEV;
2164
2165 if ((vdev = hd->Targets[target]) != NULL)
2166 goto out;
2167
2168 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
2169 if (!vdev) {
2170 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2171 hd->ioc->name, sizeof(VirtDevice));
2172 return -ENOMEM;
2173 }
2174
2175 memset(vdev, 0, sizeof(VirtDevice));
2176 vdev->tflags = MPT_TARGET_FLAGS_Q_YES;
2177 vdev->ioc_id = hd->ioc->id;
2178 vdev->target_id = device->id;
2179 vdev->bus_id = device->channel;
2180 vdev->raidVolume = 0;
2181 hd->Targets[device->id] = vdev;
2182 if (hd->ioc->bus_type == SCSI) {
2183 if (hd->ioc->spi_data.isRaid & (1 << device->id)) {
2184 vdev->raidVolume = 1;
2185 ddvtprintk((KERN_INFO
2186 "RAID Volume @ id %d\n", device->id));
2187 }
2188 } else {
2189 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2190 }
2191
2192 out:
2193 vdev->num_luns++;
2194 return 0;
2195}
2196
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002197static int
2198mptscsih_is_raid_volume(MPT_SCSI_HOST *hd, uint id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199{
2200 int i;
2201
2202 if (!hd->ioc->spi_data.isRaid || !hd->ioc->spi_data.pIocPg3)
2203 return 0;
2204
2205 for (i = 0; i < hd->ioc->spi_data.pIocPg3->NumPhysDisks; i++) {
2206 if (id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID)
2207 return 1;
2208 }
2209
2210 return 0;
2211}
2212
2213/*
2214 * OS entry point to allow for host driver to free allocated memory
2215 * Called if no device present or device being unloaded
2216 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002217void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218mptscsih_slave_destroy(struct scsi_device *device)
2219{
2220 struct Scsi_Host *host = device->host;
2221 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
2222 VirtDevice *vdev;
2223 uint target = device->id;
2224 uint lun = device->lun;
2225
2226 if (hd == NULL)
2227 return;
2228
2229 mptscsih_search_running_cmds(hd, target, lun);
2230
2231 vdev = hd->Targets[target];
2232 vdev->luns[0] &= ~(1 << lun);
2233 if (--vdev->num_luns)
2234 return;
2235
2236 kfree(hd->Targets[target]);
2237 hd->Targets[target] = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002238
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 if (hd->ioc->bus_type == SCSI) {
2240 if (mptscsih_is_raid_volume(hd, target)) {
2241 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2242 } else {
2243 hd->ioc->spi_data.dvStatus[target] =
2244 MPT_SCSICFG_NEGOTIATE;
2245
2246 if (!hd->negoNvram) {
2247 hd->ioc->spi_data.dvStatus[target] |=
2248 MPT_SCSICFG_DV_NOT_DONE;
2249 }
2250 }
2251 }
2252}
2253
2254static void
2255mptscsih_set_queue_depth(struct scsi_device *device, MPT_SCSI_HOST *hd,
2256 VirtDevice *pTarget, int qdepth)
2257{
2258 int max_depth;
2259 int tagged;
2260
2261 if (hd->ioc->bus_type == SCSI) {
2262 if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2263 if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
2264 max_depth = 1;
2265 else if (((pTarget->inq_data[0] & 0x1f) == 0x00) &&
2266 (pTarget->minSyncFactor <= MPT_ULTRA160 ))
2267 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2268 else
2269 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2270 } else {
2271 /* error case - No Inq. Data */
2272 max_depth = 1;
2273 }
2274 } else
2275 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2276
2277 if (qdepth > max_depth)
2278 qdepth = max_depth;
2279 if (qdepth == 1)
2280 tagged = 0;
2281 else
2282 tagged = MSG_SIMPLE_TAG;
2283
2284 scsi_adjust_queue_depth(device, tagged, qdepth);
2285}
2286
2287
2288/*
2289 * OS entry point to adjust the queue_depths on a per-device basis.
2290 * Called once per device the bus scan. Use it to force the queue_depth
2291 * member to 1 if a device does not support Q tags.
2292 * Return non-zero if fails.
2293 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002294int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295mptscsih_slave_configure(struct scsi_device *device)
2296{
2297 struct Scsi_Host *sh = device->host;
2298 VirtDevice *pTarget;
2299 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2300
2301 if ((hd == NULL) || (hd->Targets == NULL)) {
2302 return 0;
2303 }
2304
2305 dsprintk((MYIOC_s_INFO_FMT
2306 "device @ %p, id=%d, LUN=%d, channel=%d\n",
2307 hd->ioc->name, device, device->id, device->lun, device->channel));
2308 dsprintk((MYIOC_s_INFO_FMT
2309 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2310 hd->ioc->name, device->sdtr, device->wdtr,
2311 device->ppr, device->inquiry_len));
2312
2313 if (device->id > sh->max_id) {
2314 /* error case, should never happen */
2315 scsi_adjust_queue_depth(device, 0, 1);
2316 goto slave_configure_exit;
2317 }
2318
2319 pTarget = hd->Targets[device->id];
2320
2321 if (pTarget == NULL) {
2322 /* Driver doesn't know about this device.
2323 * Kernel may generate a "Dummy Lun 0" which
2324 * may become a real Lun if a
2325 * "scsi add-single-device" command is executed
2326 * while the driver is active (hot-plug a
2327 * device). LSI Raid controllers need
2328 * queue_depth set to DEV_HIGH for this reason.
2329 */
2330 scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
2331 MPT_SCSI_CMD_PER_DEV_HIGH);
2332 goto slave_configure_exit;
2333 }
2334
2335 mptscsih_initTarget(hd, device->channel, device->id, device->lun,
2336 device->inquiry, device->inquiry_len );
2337 mptscsih_set_queue_depth(device, hd, pTarget, MPT_SCSI_CMD_PER_DEV_HIGH);
2338
2339 dsprintk((MYIOC_s_INFO_FMT
2340 "Queue depth=%d, tflags=%x\n",
2341 hd->ioc->name, device->queue_depth, pTarget->tflags));
2342
2343 dsprintk((MYIOC_s_INFO_FMT
2344 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2345 hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor));
2346
2347slave_configure_exit:
2348
2349 dsprintk((MYIOC_s_INFO_FMT
2350 "tagged %d, simple %d, ordered %d\n",
2351 hd->ioc->name,device->tagged_supported, device->simple_tags,
2352 device->ordered_tags));
2353
2354 return 0;
2355}
2356
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002357ssize_t
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358mptscsih_store_queue_depth(struct device *dev, const char *buf, size_t count)
2359{
2360 int depth;
2361 struct scsi_device *sdev = to_scsi_device(dev);
2362 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) sdev->host->hostdata;
2363 VirtDevice *pTarget;
2364
2365 depth = simple_strtoul(buf, NULL, 0);
2366 if (depth == 0)
2367 return -EINVAL;
2368 pTarget = hd->Targets[sdev->id];
2369 if (pTarget == NULL)
2370 return -EINVAL;
2371 mptscsih_set_queue_depth(sdev, (MPT_SCSI_HOST *) sdev->host->hostdata,
2372 pTarget, depth);
2373 return count;
2374}
2375
2376/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2377/*
2378 * Private routines...
2379 */
2380
2381/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2382/* Utility function to copy sense data from the scsi_cmnd buffer
2383 * to the FC and SCSI target structures.
2384 *
2385 */
2386static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002387mptscsih_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 -07002388{
2389 VirtDevice *target;
2390 SCSIIORequest_t *pReq;
2391 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
2392 int index;
2393
2394 /* Get target structure
2395 */
2396 pReq = (SCSIIORequest_t *) mf;
2397 index = (int) pReq->TargetID;
2398 target = hd->Targets[index];
2399
2400 if (sense_count) {
2401 u8 *sense_data;
2402 int req_index;
2403
2404 /* Copy the sense received into the scsi command block. */
2405 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2406 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2407 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2408
2409 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2410 */
2411 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
2412 if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
2413 int idx;
2414 MPT_ADAPTER *ioc = hd->ioc;
2415
2416 idx = ioc->eventContext % ioc->eventLogSize;
2417 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2418 ioc->events[idx].eventContext = ioc->eventContext;
2419
2420 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2421 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
2422 (pReq->Bus << 8) || pReq->TargetID;
2423
2424 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2425
2426 ioc->eventContext++;
2427 }
2428 }
2429 } else {
2430 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2431 hd->ioc->name));
2432 }
2433}
2434
2435static u32
2436SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2437{
2438 MPT_SCSI_HOST *hd;
2439 int i;
2440
2441 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2442
2443 for (i = 0; i < hd->ioc->req_depth; i++) {
2444 if (hd->ScsiLookup[i] == sc) {
2445 return i;
2446 }
2447 }
2448
2449 return -1;
2450}
2451
2452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002453int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2455{
2456 MPT_SCSI_HOST *hd;
2457 unsigned long flags;
2458
2459 dtmprintk((KERN_WARNING MYNAM
2460 ": IOC %s_reset routed to SCSI host driver!\n",
2461 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2462 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2463
2464 /* If a FW reload request arrives after base installed but
2465 * before all scsi hosts have been attached, then an alt_ioc
2466 * may have a NULL sh pointer.
2467 */
2468 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2469 return 0;
2470 else
2471 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2472
2473 if (reset_phase == MPT_IOC_SETUP_RESET) {
2474 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2475
2476 /* Clean Up:
2477 * 1. Set Hard Reset Pending Flag
2478 * All new commands go to doneQ
2479 */
2480 hd->resetPending = 1;
2481
2482 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2483 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2484
2485 /* 2. Flush running commands
2486 * Clean ScsiLookup (and associated memory)
2487 * AND clean mytaskQ
2488 */
2489
2490 /* 2b. Reply to OS all known outstanding I/O commands.
2491 */
2492 mptscsih_flush_running_cmds(hd);
2493
2494 /* 2c. If there was an internal command that
2495 * has not completed, configuration or io request,
2496 * free these resources.
2497 */
2498 if (hd->cmdPtr) {
2499 del_timer(&hd->timer);
2500 mpt_free_msg_frame(ioc, hd->cmdPtr);
2501 }
2502
2503 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2504
2505 } else {
2506 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2507
2508 /* Once a FW reload begins, all new OS commands are
2509 * redirected to the doneQ w/ a reset status.
2510 * Init all control structures.
2511 */
2512
2513 /* ScsiLookup initialization
2514 */
2515 {
2516 int ii;
2517 for (ii=0; ii < hd->ioc->req_depth; ii++)
2518 hd->ScsiLookup[ii] = NULL;
2519 }
2520
2521 /* 2. Chain Buffer initialization
2522 */
2523
2524 /* 4. Renegotiate to all devices, if SCSI
2525 */
2526 if (ioc->bus_type == SCSI) {
2527 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2528 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2529 }
2530
2531 /* 5. Enable new commands to be posted
2532 */
2533 spin_lock_irqsave(&ioc->FreeQlock, flags);
2534 hd->tmPending = 0;
2535 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2536 hd->resetPending = 0;
2537 hd->tmState = TM_STATE_NONE;
2538
2539 /* 6. If there was an internal command,
2540 * wake this process up.
2541 */
2542 if (hd->cmdPtr) {
2543 /*
2544 * Wake up the original calling thread
2545 */
2546 hd->pLocal = &hd->localReply;
2547 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002548 hd->scandv_wait_done = 1;
2549 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 hd->cmdPtr = NULL;
2551 }
2552
2553 /* 7. Set flag to force DV and re-read IOC Page 3
2554 */
2555 if (ioc->bus_type == SCSI) {
2556 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2557 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2558 }
2559
2560 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2561
2562 }
2563
2564 return 1; /* currently means nothing really */
2565}
2566
2567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002568int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2570{
2571 MPT_SCSI_HOST *hd;
2572 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2573
2574 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2575 ioc->name, event));
2576
2577 switch (event) {
2578 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2579 /* FIXME! */
2580 break;
2581 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2582 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
2583 hd = NULL;
2584 if (ioc->sh) {
2585 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2586 if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1))
2587 hd->soft_resets++;
2588 }
2589 break;
2590 case MPI_EVENT_LOGOUT: /* 09 */
2591 /* FIXME! */
2592 break;
2593
2594 /*
2595 * CHECKME! Don't think we need to do
2596 * anything for these, but...
2597 */
2598 case MPI_EVENT_RESCAN: /* 06 */
2599 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2600 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2601 /*
2602 * CHECKME! Falling thru...
2603 */
2604 break;
2605
2606 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
2607#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
2608 /* negoNvram set to 0 if DV enabled and to USE_NVRAM if
2609 * if DV disabled. Need to check for target mode.
2610 */
2611 hd = NULL;
2612 if (ioc->sh)
2613 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2614
2615 if (hd && (ioc->bus_type == SCSI) && (hd->negoNvram == 0)) {
2616 ScsiCfgData *pSpi;
2617 Ioc3PhysDisk_t *pPDisk;
2618 int numPDisk;
2619 u8 reason;
2620 u8 physDiskNum;
2621
2622 reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
2623 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
2624 /* New or replaced disk.
2625 * Set DV flag and schedule DV.
2626 */
2627 pSpi = &ioc->spi_data;
2628 physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
2629 ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
2630 if (pSpi->pIocPg3) {
2631 pPDisk = pSpi->pIocPg3->PhysDisk;
2632 numPDisk =pSpi->pIocPg3->NumPhysDisks;
2633
2634 while (numPDisk) {
2635 if (physDiskNum == pPDisk->PhysDiskNum) {
2636 pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
2637 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
2638 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
2639 break;
2640 }
2641 pPDisk++;
2642 numPDisk--;
2643 }
2644
2645 if (numPDisk == 0) {
2646 /* The physical disk that needs DV was not found
2647 * in the stored IOC Page 3. The driver must reload
2648 * this page. DV routine will set the NEED_DV flag for
2649 * all phys disks that have DV_NOT_DONE set.
2650 */
2651 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2652 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
2653 }
2654 }
2655 }
2656 }
2657#endif
2658
2659#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
2660 printk("Raid Event RF: ");
2661 {
2662 u32 *m = (u32 *)pEvReply;
2663 int ii;
2664 int n = (int)pEvReply->MsgLength;
2665 for (ii=6; ii < n; ii++)
2666 printk(" %08x", le32_to_cpu(m[ii]));
2667 printk("\n");
2668 }
2669#endif
2670 break;
2671
2672 case MPI_EVENT_NONE: /* 00 */
2673 case MPI_EVENT_LOG_DATA: /* 01 */
2674 case MPI_EVENT_STATE_CHANGE: /* 02 */
2675 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2676 default:
2677 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2678 break;
2679 }
2680
2681 return 1; /* currently means nothing really */
2682}
2683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2685/*
2686 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2687 * @hd: Pointer to MPT_SCSI_HOST structure
2688 * @bus_id: Bus number (?)
2689 * @target_id: SCSI target id
2690 * @lun: SCSI LUN id
2691 * @data: Pointer to data
2692 * @dlen: Number of INQUIRY bytes
2693 *
2694 * NOTE: It's only SAFE to call this routine if data points to
2695 * sane & valid STANDARD INQUIRY data!
2696 *
2697 * Allocate and initialize memory for this target.
2698 * Save inquiry data.
2699 *
2700 */
2701static void
2702mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
2703{
2704 int indexed_lun, lun_index;
2705 VirtDevice *vdev;
2706 ScsiCfgData *pSpi;
2707 char data_56;
2708
2709 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
2710 hd->ioc->name, bus_id, target_id, lun, hd));
2711
2712 /*
2713 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2714 * (i.e. The targer is capable of supporting the specified peripheral device type
2715 * on this logical unit; however, the physical device is not currently connected
2716 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
2717 * capable of supporting a physical device on this logical unit). This is to work
2718 * around a bug in th emid-layer in some distributions in which the mid-layer will
2719 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2720 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002721 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002723
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 /* Is LUN supported? If so, upper 2 bits will be 0
2725 * in first byte of inquiry data.
2726 */
2727 if (data[0] & 0xe0)
2728 return;
2729
2730 if ((vdev = hd->Targets[target_id]) == NULL) {
2731 return;
2732 }
2733
2734 lun_index = (lun >> 5); /* 32 luns per lun_index */
2735 indexed_lun = (lun % 32);
2736 vdev->luns[lun_index] |= (1 << indexed_lun);
2737
2738 if (hd->ioc->bus_type == SCSI) {
2739 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2740 /* Treat all Processors as SAF-TE if
2741 * command line option is set */
2742 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2743 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2744 }else if ((data[0] == TYPE_PROCESSOR) &&
2745 !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2746 if ( dlen > 49 ) {
2747 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2748 if ( data[44] == 'S' &&
2749 data[45] == 'A' &&
2750 data[46] == 'F' &&
2751 data[47] == '-' &&
2752 data[48] == 'T' &&
2753 data[49] == 'E' ) {
2754 vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2755 mptscsih_writeIOCPage4(hd, target_id, bus_id);
2756 }
2757 }
2758 }
2759 if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2760 if ( dlen > 8 ) {
2761 memcpy (vdev->inq_data, data, 8);
2762 } else {
2763 memcpy (vdev->inq_data, data, dlen);
2764 }
2765
2766 /* If have not done DV, set the DV flag.
2767 */
2768 pSpi = &hd->ioc->spi_data;
2769 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2770 if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
2771 pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
2772 }
2773
2774 vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2775
2776
2777 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2778 if (dlen > 56) {
2779 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2780 /* Update the target capabilities
2781 */
2782 data_56 = data[56];
2783 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2784 }
2785 }
2786 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2787 } else {
2788 /* Initial Inquiry may not request enough data bytes to
2789 * obtain byte 57. DV will; if target doesn't return
2790 * at least 57 bytes, data[56] will be zero. */
2791 if (dlen > 56) {
2792 if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2793 /* Update the target capabilities
2794 */
2795 data_56 = data[56];
2796 vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
2797 mptscsih_setTargetNegoParms(hd, vdev, data_56);
2798 }
2799 }
2800 }
2801 }
2802}
2803
2804/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2805/*
2806 * Update the target negotiation parameters based on the
2807 * the Inquiry data, adapter capabilities, and NVRAM settings.
2808 *
2809 */
2810static void
2811mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
2812{
2813 ScsiCfgData *pspi_data = &hd->ioc->spi_data;
2814 int id = (int) target->target_id;
2815 int nvram;
2816 VirtDevice *vdev;
2817 int ii;
2818 u8 width = MPT_NARROW;
2819 u8 factor = MPT_ASYNC;
2820 u8 offset = 0;
2821 u8 version, nfactor;
2822 u8 noQas = 1;
2823
2824 target->negoFlags = pspi_data->noQas;
2825
2826 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2827 * support. If available, default QAS to off and allow enabling.
2828 * If not available, default QAS to on, turn off for non-disks.
2829 */
2830
2831 /* Set flags based on Inquiry data
2832 */
2833 version = target->inq_data[2] & 0x07;
2834 if (version < 2) {
2835 width = 0;
2836 factor = MPT_ULTRA2;
2837 offset = pspi_data->maxSyncOffset;
2838 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2839 } else {
2840 if (target->inq_data[7] & 0x20) {
2841 width = 1;
2842 }
2843
2844 if (target->inq_data[7] & 0x10) {
2845 factor = pspi_data->minSyncFactor;
2846 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2847 /* bits 2 & 3 show Clocking support */
2848 if ((byte56 & 0x0C) == 0)
2849 factor = MPT_ULTRA2;
2850 else {
2851 if ((byte56 & 0x03) == 0)
2852 factor = MPT_ULTRA160;
2853 else {
2854 factor = MPT_ULTRA320;
2855 if (byte56 & 0x02)
2856 {
2857 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2858 noQas = 0;
2859 }
2860 if (target->inq_data[0] == TYPE_TAPE) {
2861 if (byte56 & 0x01)
2862 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2863 }
2864 }
2865 }
2866 } else {
2867 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2868 noQas = 0;
2869 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002870
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 offset = pspi_data->maxSyncOffset;
2872
2873 /* If RAID, never disable QAS
2874 * else if non RAID, do not disable
2875 * QAS if bit 1 is set
2876 * bit 1 QAS support, non-raid only
2877 * bit 0 IU support
2878 */
2879 if (target->raidVolume == 1) {
2880 noQas = 0;
2881 }
2882 } else {
2883 factor = MPT_ASYNC;
2884 offset = 0;
2885 }
2886 }
2887
2888 if ( (target->inq_data[7] & 0x02) == 0) {
2889 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2890 }
2891
2892 /* Update tflags based on NVRAM settings. (SCSI only)
2893 */
2894 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2895 nvram = pspi_data->nvram[id];
2896 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2897
2898 if (width)
2899 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2900
2901 if (offset > 0) {
2902 /* Ensure factor is set to the
2903 * maximum of: adapter, nvram, inquiry
2904 */
2905 if (nfactor) {
2906 if (nfactor < pspi_data->minSyncFactor )
2907 nfactor = pspi_data->minSyncFactor;
2908
2909 factor = max(factor, nfactor);
2910 if (factor == MPT_ASYNC)
2911 offset = 0;
2912 } else {
2913 offset = 0;
2914 factor = MPT_ASYNC;
2915 }
2916 } else {
2917 factor = MPT_ASYNC;
2918 }
2919 }
2920
2921 /* Make sure data is consistent
2922 */
2923 if ((!width) && (factor < MPT_ULTRA2)) {
2924 factor = MPT_ULTRA2;
2925 }
2926
2927 /* Save the data to the target structure.
2928 */
2929 target->minSyncFactor = factor;
2930 target->maxOffset = offset;
2931 target->maxWidth = width;
2932
2933 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2934
2935 /* Disable unused features.
2936 */
2937 if (!width)
2938 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2939
2940 if (!offset)
2941 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2942
2943 if ( factor > MPT_ULTRA320 )
2944 noQas = 0;
2945
2946 /* GEM, processor WORKAROUND
2947 */
2948 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2949 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2950 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2951 } else {
2952 if (noQas && (pspi_data->noQas == 0)) {
2953 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2954 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2955
2956 /* Disable QAS in a mixed configuration case
2957 */
2958
2959 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2960 for (ii = 0; ii < id; ii++) {
2961 if ( (vdev = hd->Targets[ii]) ) {
2962 vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2963 mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 }
2966 }
2967 }
2968
2969 /* Write SDP1 on this I/O to this target */
2970 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2971 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2972 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2973 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2974 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2975 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2976 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2977 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2978 }
2979}
2980
2981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2982/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
2983 * Else set the NEED_DV flag after Read Capacity Issued (disks)
2984 * or Mode Sense (cdroms).
2985 *
2986 * Tapes, initTarget will set this flag on completion of Inquiry command.
2987 * Called only if DV_NOT_DONE flag is set
2988 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002989static void
2990mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991{
2992 u8 cmd;
2993 ScsiCfgData *pSpi;
2994
2995 ddvtprintk((" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
2996 pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0]));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002997
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
2999 return;
3000
3001 cmd = pReq->CDB[0];
3002
3003 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
3004 pSpi = &hd->ioc->spi_data;
3005 if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
3006 /* Set NEED_DV for all hidden disks
3007 */
3008 Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk;
3009 int numPDisk = pSpi->pIocPg3->NumPhysDisks;
3010
3011 while (numPDisk) {
3012 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
3013 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
3014 pPDisk++;
3015 numPDisk--;
3016 }
3017 }
3018 pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
3019 ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
3020 }
3021}
3022
3023/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3024/*
3025 * If no Target, bus reset on 1st I/O. Set the flag to
3026 * prevent any future negotiations to this device.
3027 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003028static void
3029mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030{
3031
3032 if ((hd->Targets) && (hd->Targets[target_id] == NULL))
3033 hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
3034
3035 return;
3036}
3037
3038/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3039/*
3040 * SCSI Config Page functionality ...
3041 */
3042/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3043/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
3044 * based on width, factor and offset parameters.
3045 * @width: bus width
3046 * @factor: sync factor
3047 * @offset: sync offset
3048 * @requestedPtr: pointer to requested values (updated)
3049 * @configurationPtr: pointer to configuration values (updated)
3050 * @flags: flags to block WDTR or SDTR negotiation
3051 *
3052 * Return: None.
3053 *
3054 * Remark: Called by writeSDP1 and _dv_params
3055 */
3056static void
3057mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3058{
3059 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3060 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3061
3062 *configurationPtr = 0;
3063 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3064 *requestedPtr |= (offset << 16) | (factor << 8);
3065
3066 if (width && offset && !nowide && !nosync) {
3067 if (factor < MPT_ULTRA160) {
3068 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3069 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3070 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3071 if (flags & MPT_TAPE_NEGO_IDP)
3072 *requestedPtr |= 0x08000000;
3073 } else if (factor < MPT_ULTRA2) {
3074 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3075 }
3076 }
3077
3078 if (nowide)
3079 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3080
3081 if (nosync)
3082 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3083
3084 return;
3085}
3086
3087/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3088/* mptscsih_writeSDP1 - write SCSI Device Page 1
3089 * @hd: Pointer to a SCSI Host Strucutre
3090 * @portnum: IOC port number
3091 * @target_id: writeSDP1 for single ID
3092 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3093 *
3094 * Return: -EFAULT if read of config page header fails
3095 * or 0 if success.
3096 *
3097 * Remark: If a target has been found, the settings from the
3098 * target structure are used, else the device is set
3099 * to async/narrow.
3100 *
3101 * Remark: Called during init and after a FW reload.
3102 * Remark: We do not wait for a return, write pages sequentially.
3103 */
3104static int
3105mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3106{
3107 MPT_ADAPTER *ioc = hd->ioc;
3108 Config_t *pReq;
3109 SCSIDevicePage1_t *pData;
3110 VirtDevice *pTarget;
3111 MPT_FRAME_HDR *mf;
3112 dma_addr_t dataDma;
3113 u16 req_idx;
3114 u32 frameOffset;
3115 u32 requested, configuration, flagsLength;
3116 int ii, nvram;
3117 int id = 0, maxid = 0;
3118 u8 width;
3119 u8 factor;
3120 u8 offset;
3121 u8 bus = 0;
3122 u8 negoFlags;
3123 u8 maxwidth, maxoffset, maxfactor;
3124
3125 if (ioc->spi_data.sdp1length == 0)
3126 return 0;
3127
3128 if (flags & MPT_SCSICFG_ALL_IDS) {
3129 id = 0;
3130 maxid = ioc->sh->max_id - 1;
3131 } else if (ioc->sh) {
3132 id = target_id;
3133 maxid = min_t(int, id, ioc->sh->max_id - 1);
3134 }
3135
3136 for (; id <= maxid; id++) {
3137
3138 if (id == ioc->pfacts[portnum].PortSCSIID)
3139 continue;
3140
3141 /* Use NVRAM to get adapter and target maximums
3142 * Data over-riden by target structure information, if present
3143 */
3144 maxwidth = ioc->spi_data.maxBusWidth;
3145 maxoffset = ioc->spi_data.maxSyncOffset;
3146 maxfactor = ioc->spi_data.minSyncFactor;
3147 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3148 nvram = ioc->spi_data.nvram[id];
3149
3150 if (maxwidth)
3151 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3152
3153 if (maxoffset > 0) {
3154 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3155 if (maxfactor == 0) {
3156 /* Key for async */
3157 maxfactor = MPT_ASYNC;
3158 maxoffset = 0;
3159 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3160 maxfactor = ioc->spi_data.minSyncFactor;
3161 }
3162 } else
3163 maxfactor = MPT_ASYNC;
3164 }
3165
3166 /* Set the negotiation flags.
3167 */
3168 negoFlags = ioc->spi_data.noQas;
3169 if (!maxwidth)
3170 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3171
3172 if (!maxoffset)
3173 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3174
3175 if (flags & MPT_SCSICFG_USE_NVRAM) {
3176 width = maxwidth;
3177 factor = maxfactor;
3178 offset = maxoffset;
3179 } else {
3180 width = 0;
3181 factor = MPT_ASYNC;
3182 offset = 0;
3183 //negoFlags = 0;
3184 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3185 }
3186
3187 /* If id is not a raid volume, get the updated
3188 * transmission settings from the target structure.
3189 */
3190 if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
3191 width = pTarget->maxWidth;
3192 factor = pTarget->minSyncFactor;
3193 offset = pTarget->maxOffset;
3194 negoFlags = pTarget->negoFlags;
3195 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003196
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3198 /* Force to async and narrow if DV has not been executed
3199 * for this ID
3200 */
3201 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3202 width = 0;
3203 factor = MPT_ASYNC;
3204 offset = 0;
3205 }
3206#endif
3207
3208 if (flags & MPT_SCSICFG_BLK_NEGO)
3209 negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
3210
3211 mptscsih_setDevicePage1Flags(width, factor, offset,
3212 &requested, &configuration, negoFlags);
3213 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3214 target_id, width, factor, offset, negoFlags, requested, configuration));
3215
3216 /* Get a MF for this command.
3217 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003218 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3220 ioc->name));
3221 return -EAGAIN;
3222 }
3223
3224 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3225 hd->ioc->name, mf, id, requested, configuration));
3226
3227
3228 /* Set the request and the data pointers.
3229 * Request takes: 36 bytes (32 bit SGE)
3230 * SCSI Device Page 1 requires 16 bytes
3231 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3232 * and MF size >= 64 bytes.
3233 * Place data at end of MF.
3234 */
3235 pReq = (Config_t *)mf;
3236
3237 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3238 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3239
3240 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3241 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3242
3243 /* Complete the request frame (same for all requests).
3244 */
3245 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3246 pReq->Reserved = 0;
3247 pReq->ChainOffset = 0;
3248 pReq->Function = MPI_FUNCTION_CONFIG;
3249 pReq->ExtPageLength = 0;
3250 pReq->ExtPageType = 0;
3251 pReq->MsgFlags = 0;
3252 for (ii=0; ii < 8; ii++) {
3253 pReq->Reserved2[ii] = 0;
3254 }
3255 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3256 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3257 pReq->Header.PageNumber = 1;
3258 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3259 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3260
3261 /* Add a SGE to the config request.
3262 */
3263 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3264
3265 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3266
3267 /* Set up the common data portion
3268 */
3269 pData->Header.PageVersion = pReq->Header.PageVersion;
3270 pData->Header.PageLength = pReq->Header.PageLength;
3271 pData->Header.PageNumber = pReq->Header.PageNumber;
3272 pData->Header.PageType = pReq->Header.PageType;
3273 pData->RequestedParameters = cpu_to_le32(requested);
3274 pData->Reserved = 0;
3275 pData->Configuration = cpu_to_le32(configuration);
3276
3277 dprintk((MYIOC_s_INFO_FMT
3278 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3279 ioc->name, id, (id | (bus<<8)),
3280 requested, configuration));
3281
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003282 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 }
3284
3285 return 0;
3286}
3287
3288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3289/* mptscsih_writeIOCPage4 - write IOC Page 4
3290 * @hd: Pointer to a SCSI Host Structure
3291 * @target_id: write IOC Page4 for this ID & Bus
3292 *
3293 * Return: -EAGAIN if unable to obtain a Message Frame
3294 * or 0 if success.
3295 *
3296 * Remark: We do not wait for a return, write pages sequentially.
3297 */
3298static int
3299mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3300{
3301 MPT_ADAPTER *ioc = hd->ioc;
3302 Config_t *pReq;
3303 IOCPage4_t *IOCPage4Ptr;
3304 MPT_FRAME_HDR *mf;
3305 dma_addr_t dataDma;
3306 u16 req_idx;
3307 u32 frameOffset;
3308 u32 flagsLength;
3309 int ii;
3310
3311 /* Get a MF for this command.
3312 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003313 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
3315 ioc->name));
3316 return -EAGAIN;
3317 }
3318
3319 /* Set the request and the data pointers.
3320 * Place data at end of MF.
3321 */
3322 pReq = (Config_t *)mf;
3323
3324 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3325 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3326
3327 /* Complete the request frame (same for all requests).
3328 */
3329 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3330 pReq->Reserved = 0;
3331 pReq->ChainOffset = 0;
3332 pReq->Function = MPI_FUNCTION_CONFIG;
3333 pReq->ExtPageLength = 0;
3334 pReq->ExtPageType = 0;
3335 pReq->MsgFlags = 0;
3336 for (ii=0; ii < 8; ii++) {
3337 pReq->Reserved2[ii] = 0;
3338 }
3339
3340 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3341 dataDma = ioc->spi_data.IocPg4_dma;
3342 ii = IOCPage4Ptr->ActiveSEP++;
3343 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3344 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3345 pReq->Header = IOCPage4Ptr->Header;
3346 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3347
3348 /* Add a SGE to the config request.
3349 */
3350 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3351 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3352
3353 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3354
3355 dinitprintk((MYIOC_s_INFO_FMT
3356 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3357 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3358
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003359 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360
3361 return 0;
3362}
3363
3364/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3365/*
3366 * Bus Scan and Domain Validation functionality ...
3367 */
3368
3369/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3370/*
3371 * mptscsih_scandv_complete - Scan and DV callback routine registered
3372 * to Fustion MPT (base) driver.
3373 *
3374 * @ioc: Pointer to MPT_ADAPTER structure
3375 * @mf: Pointer to original MPT request frame
3376 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3377 *
3378 * This routine is called from mpt.c::mpt_interrupt() at the completion
3379 * of any SCSI IO request.
3380 * This routine is registered with the Fusion MPT (base) driver at driver
3381 * load/init time via the mpt_register() API call.
3382 *
3383 * Returns 1 indicating alloc'd request frame ptr should be freed.
3384 *
3385 * Remark: Sets a completion code and (possibly) saves sense data
3386 * in the IOC member localReply structure.
3387 * Used ONLY for DV and other internal commands.
3388 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003389int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3391{
3392 MPT_SCSI_HOST *hd;
3393 SCSIIORequest_t *pReq;
3394 int completionCode;
3395 u16 req_idx;
3396
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003397 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 if ((mf == NULL) ||
3400 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3401 printk(MYIOC_s_ERR_FMT
3402 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3403 ioc->name, mf?"BAD":"NULL", (void *) mf);
3404 goto wakeup;
3405 }
3406
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 del_timer(&hd->timer);
3408 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3409 hd->ScsiLookup[req_idx] = NULL;
3410 pReq = (SCSIIORequest_t *) mf;
3411
3412 if (mf != hd->cmdPtr) {
3413 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3414 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3415 }
3416 hd->cmdPtr = NULL;
3417
3418 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3419 hd->ioc->name, mf, mr, req_idx));
3420
3421 hd->pLocal = &hd->localReply;
3422 hd->pLocal->scsiStatus = 0;
3423
3424 /* If target struct exists, clear sense valid flag.
3425 */
3426 if (mr == NULL) {
3427 completionCode = MPT_SCANDV_GOOD;
3428 } else {
3429 SCSIIOReply_t *pReply;
3430 u16 status;
3431 u8 scsi_status;
3432
3433 pReply = (SCSIIOReply_t *) mr;
3434
3435 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3436 scsi_status = pReply->SCSIStatus;
3437
3438 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3439 status, pReply->SCSIState, scsi_status,
3440 le32_to_cpu(pReply->IOCLogInfo)));
3441
3442 switch(status) {
3443
3444 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3445 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3446 break;
3447
3448 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3449 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3450 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3451 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3452 completionCode = MPT_SCANDV_DID_RESET;
3453 break;
3454
3455 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3456 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3457 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3458 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3459 ConfigReply_t *pr = (ConfigReply_t *)mr;
3460 completionCode = MPT_SCANDV_GOOD;
3461 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3462 hd->pLocal->header.PageLength = pr->Header.PageLength;
3463 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3464 hd->pLocal->header.PageType = pr->Header.PageType;
3465
3466 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3467 /* If the RAID Volume request is successful,
3468 * return GOOD, else indicate that
3469 * some type of error occurred.
3470 */
3471 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
3472 if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
3473 completionCode = MPT_SCANDV_GOOD;
3474 else
3475 completionCode = MPT_SCANDV_SOME_ERROR;
3476
3477 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3478 u8 *sense_data;
3479 int sz;
3480
3481 /* save sense data in global structure
3482 */
3483 completionCode = MPT_SCANDV_SENSE;
3484 hd->pLocal->scsiStatus = scsi_status;
3485 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3486 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3487
3488 sz = min_t(int, pReq->SenseBufferLength,
3489 SCSI_STD_SENSE_BYTES);
3490 memcpy(hd->pLocal->sense, sense_data, sz);
3491
3492 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3493 sense_data));
3494 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3495 if (pReq->CDB[0] == INQUIRY)
3496 completionCode = MPT_SCANDV_ISSUE_SENSE;
3497 else
3498 completionCode = MPT_SCANDV_DID_RESET;
3499 }
3500 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3501 completionCode = MPT_SCANDV_DID_RESET;
3502 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3503 completionCode = MPT_SCANDV_DID_RESET;
3504 else {
3505 completionCode = MPT_SCANDV_GOOD;
3506 hd->pLocal->scsiStatus = scsi_status;
3507 }
3508 break;
3509
3510 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3511 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3512 completionCode = MPT_SCANDV_DID_RESET;
3513 else
3514 completionCode = MPT_SCANDV_SOME_ERROR;
3515 break;
3516
3517 default:
3518 completionCode = MPT_SCANDV_SOME_ERROR;
3519 break;
3520
3521 } /* switch(status) */
3522
3523 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3524 completionCode));
3525 } /* end of address reply case */
3526
3527 hd->pLocal->completion = completionCode;
3528
3529 /* MF and RF are freed in mpt_interrupt
3530 */
3531wakeup:
3532 /* Free Chain buffers (will never chain) in scan or dv */
3533 //mptscsih_freeChainBuffers(ioc, req_idx);
3534
3535 /*
3536 * Wake up the original calling thread
3537 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003538 hd->scandv_wait_done = 1;
3539 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540
3541 return 1;
3542}
3543
3544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3545/* mptscsih_timer_expired - Call back for timer process.
3546 * Used only for dv functionality.
3547 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3548 *
3549 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003550void
3551mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552{
3553 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3554
3555 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3556
3557 if (hd->cmdPtr) {
3558 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3559
3560 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3561 /* Desire to issue a task management request here.
3562 * TM requests MUST be single threaded.
3563 * If old eh code and no TM current, issue request.
3564 * If new eh code, do nothing. Wait for OS cmd timeout
3565 * for bus reset.
3566 */
3567 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3568 } else {
3569 /* Perform a FW reload */
3570 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3571 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3572 }
3573 }
3574 } else {
3575 /* This should NEVER happen */
3576 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3577 }
3578
3579 /* No more processing.
3580 * TM call will generate an interrupt for SCSI TM Management.
3581 * The FW will reply to all outstanding commands, callback will finish cleanup.
3582 * Hard reset clean-up will free all resources.
3583 */
3584 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3585
3586 return;
3587}
3588
3589#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3590/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3591/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3592 * @hd: Pointer to scsi host structure
3593 * @action: What do be done.
3594 * @id: Logical target id.
3595 * @bus: Target locations bus.
3596 *
3597 * Returns: < 0 on a fatal error
3598 * 0 on success
3599 *
3600 * Remark: Wait to return until reply processed by the ISR.
3601 */
3602static int
3603mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3604{
3605 MpiRaidActionRequest_t *pReq;
3606 MPT_FRAME_HDR *mf;
3607 int in_isr;
3608
3609 in_isr = in_interrupt();
3610 if (in_isr) {
3611 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3612 hd->ioc->name));
3613 return -EPERM;
3614 }
3615
3616 /* Get and Populate a free Frame
3617 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003618 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3620 hd->ioc->name));
3621 return -EAGAIN;
3622 }
3623 pReq = (MpiRaidActionRequest_t *)mf;
3624 pReq->Action = action;
3625 pReq->Reserved1 = 0;
3626 pReq->ChainOffset = 0;
3627 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3628 pReq->VolumeID = io->id;
3629 pReq->VolumeBus = io->bus;
3630 pReq->PhysDiskNum = io->physDiskNum;
3631 pReq->MsgFlags = 0;
3632 pReq->Reserved2 = 0;
3633 pReq->ActionDataWord = 0; /* Reserved for this action */
3634 //pReq->ActionDataSGE = 0;
3635
3636 mpt_add_sge((char *)&pReq->ActionDataSGE,
3637 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3638
3639 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3640 hd->ioc->name, action, io->id));
3641
3642 hd->pLocal = NULL;
3643 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003644 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645
3646 /* Save cmd pointer, for resource free if timeout or
3647 * FW reload occurs
3648 */
3649 hd->cmdPtr = mf;
3650
3651 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003652 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3653 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654
3655 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3656 return -1;
3657
3658 return 0;
3659}
3660#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3661
3662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3663/**
3664 * mptscsih_do_cmd - Do internal command.
3665 * @hd: MPT_SCSI_HOST pointer
3666 * @io: INTERNAL_CMD pointer.
3667 *
3668 * Issue the specified internally generated command and do command
3669 * specific cleanup. For bus scan / DV only.
3670 * NOTES: If command is Inquiry and status is good,
3671 * initialize a target structure, save the data
3672 *
3673 * Remark: Single threaded access only.
3674 *
3675 * Return:
3676 * < 0 if an illegal command or no resources
3677 *
3678 * 0 if good
3679 *
3680 * > 0 if command complete but some type of completion error.
3681 */
3682static int
3683mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3684{
3685 MPT_FRAME_HDR *mf;
3686 SCSIIORequest_t *pScsiReq;
3687 SCSIIORequest_t ReqCopy;
3688 int my_idx, ii, dir;
3689 int rc, cmdTimeout;
3690 int in_isr;
3691 char cmdLen;
3692 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3693 char cmd = io->cmd;
3694
3695 in_isr = in_interrupt();
3696 if (in_isr) {
3697 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3698 hd->ioc->name));
3699 return -EPERM;
3700 }
3701
3702
3703 /* Set command specific information
3704 */
3705 switch (cmd) {
3706 case INQUIRY:
3707 cmdLen = 6;
3708 dir = MPI_SCSIIO_CONTROL_READ;
3709 CDB[0] = cmd;
3710 CDB[4] = io->size;
3711 cmdTimeout = 10;
3712 break;
3713
3714 case TEST_UNIT_READY:
3715 cmdLen = 6;
3716 dir = MPI_SCSIIO_CONTROL_READ;
3717 cmdTimeout = 10;
3718 break;
3719
3720 case START_STOP:
3721 cmdLen = 6;
3722 dir = MPI_SCSIIO_CONTROL_READ;
3723 CDB[0] = cmd;
3724 CDB[4] = 1; /*Spin up the disk */
3725 cmdTimeout = 15;
3726 break;
3727
3728 case REQUEST_SENSE:
3729 cmdLen = 6;
3730 CDB[0] = cmd;
3731 CDB[4] = io->size;
3732 dir = MPI_SCSIIO_CONTROL_READ;
3733 cmdTimeout = 10;
3734 break;
3735
3736 case READ_BUFFER:
3737 cmdLen = 10;
3738 dir = MPI_SCSIIO_CONTROL_READ;
3739 CDB[0] = cmd;
3740 if (io->flags & MPT_ICFLAG_ECHO) {
3741 CDB[1] = 0x0A;
3742 } else {
3743 CDB[1] = 0x02;
3744 }
3745
3746 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3747 CDB[1] |= 0x01;
3748 }
3749 CDB[6] = (io->size >> 16) & 0xFF;
3750 CDB[7] = (io->size >> 8) & 0xFF;
3751 CDB[8] = io->size & 0xFF;
3752 cmdTimeout = 10;
3753 break;
3754
3755 case WRITE_BUFFER:
3756 cmdLen = 10;
3757 dir = MPI_SCSIIO_CONTROL_WRITE;
3758 CDB[0] = cmd;
3759 if (io->flags & MPT_ICFLAG_ECHO) {
3760 CDB[1] = 0x0A;
3761 } else {
3762 CDB[1] = 0x02;
3763 }
3764 CDB[6] = (io->size >> 16) & 0xFF;
3765 CDB[7] = (io->size >> 8) & 0xFF;
3766 CDB[8] = io->size & 0xFF;
3767 cmdTimeout = 10;
3768 break;
3769
3770 case RESERVE:
3771 cmdLen = 6;
3772 dir = MPI_SCSIIO_CONTROL_READ;
3773 CDB[0] = cmd;
3774 cmdTimeout = 10;
3775 break;
3776
3777 case RELEASE:
3778 cmdLen = 6;
3779 dir = MPI_SCSIIO_CONTROL_READ;
3780 CDB[0] = cmd;
3781 cmdTimeout = 10;
3782 break;
3783
3784 case SYNCHRONIZE_CACHE:
3785 cmdLen = 10;
3786 dir = MPI_SCSIIO_CONTROL_READ;
3787 CDB[0] = cmd;
3788// CDB[1] = 0x02; /* set immediate bit */
3789 cmdTimeout = 10;
3790 break;
3791
3792 default:
3793 /* Error Case */
3794 return -EFAULT;
3795 }
3796
3797 /* Get and Populate a free Frame
3798 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003799 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3801 hd->ioc->name));
3802 return -EBUSY;
3803 }
3804
3805 pScsiReq = (SCSIIORequest_t *) mf;
3806
3807 /* Get the request index */
3808 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3809 ADD_INDEX_LOG(my_idx); /* for debug */
3810
3811 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3812 pScsiReq->TargetID = io->physDiskNum;
3813 pScsiReq->Bus = 0;
3814 pScsiReq->ChainOffset = 0;
3815 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3816 } else {
3817 pScsiReq->TargetID = io->id;
3818 pScsiReq->Bus = io->bus;
3819 pScsiReq->ChainOffset = 0;
3820 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3821 }
3822
3823 pScsiReq->CDBLength = cmdLen;
3824 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3825
3826 pScsiReq->Reserved = 0;
3827
3828 pScsiReq->MsgFlags = mpt_msg_flags();
3829 /* MsgContext set in mpt_get_msg_fram call */
3830
3831 for (ii=0; ii < 8; ii++)
3832 pScsiReq->LUN[ii] = 0;
3833 pScsiReq->LUN[1] = io->lun;
3834
3835 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3836 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3837 else
3838 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3839
3840 if (cmd == REQUEST_SENSE) {
3841 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3842 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3843 hd->ioc->name, cmd));
3844 }
3845
3846 for (ii=0; ii < 16; ii++)
3847 pScsiReq->CDB[ii] = CDB[ii];
3848
3849 pScsiReq->DataLength = cpu_to_le32(io->size);
3850 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3851 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3852
3853 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3854 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3855
3856 if (dir == MPI_SCSIIO_CONTROL_READ) {
3857 mpt_add_sge((char *) &pScsiReq->SGL,
3858 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3859 io->data_dma);
3860 } else {
3861 mpt_add_sge((char *) &pScsiReq->SGL,
3862 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3863 io->data_dma);
3864 }
3865
3866 /* The ISR will free the request frame, but we need
3867 * the information to initialize the target. Duplicate.
3868 */
3869 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3870
3871 /* Issue this command after:
3872 * finish init
3873 * add timer
3874 * Wait until the reply has been received
3875 * ScsiScanDvCtx callback function will
3876 * set hd->pLocal;
3877 * set scandv_wait_done and call wake_up
3878 */
3879 hd->pLocal = NULL;
3880 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003881 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
3883 /* Save cmd pointer, for resource free if timeout or
3884 * FW reload occurs
3885 */
3886 hd->cmdPtr = mf;
3887
3888 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003889 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3890 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891
3892 if (hd->pLocal) {
3893 rc = hd->pLocal->completion;
3894 hd->pLocal->skip = 0;
3895
3896 /* Always set fatal error codes in some cases.
3897 */
3898 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3899 rc = -ENXIO;
3900 else if (rc == MPT_SCANDV_SOME_ERROR)
3901 rc = -rc;
3902 } else {
3903 rc = -EFAULT;
3904 /* This should never happen. */
3905 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3906 hd->ioc->name));
3907 }
3908
3909 return rc;
3910}
3911
3912/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3913/**
3914 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3915 * @hd: Pointer to MPT_SCSI_HOST structure
3916 * @portnum: IOC port number
3917 *
3918 * Uses the ISR, but with special processing.
3919 * MUST be single-threaded.
3920 *
3921 * Return: 0 on completion
3922 */
3923static int
3924mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
3925{
3926 MPT_ADAPTER *ioc= hd->ioc;
3927 VirtDevice *pTarget;
3928 SCSIDevicePage1_t *pcfg1Data = NULL;
3929 INTERNAL_CMD iocmd;
3930 CONFIGPARMS cfg;
3931 dma_addr_t cfg1_dma_addr = -1;
3932 ConfigPageHeader_t header1;
3933 int bus = 0;
3934 int id = 0;
3935 int lun;
3936 int indexed_lun, lun_index;
3937 int hostId = ioc->pfacts[portnum].PortSCSIID;
3938 int max_id;
3939 int requested, configuration, data;
3940 int doConfig = 0;
3941 u8 flags, factor;
3942
3943 max_id = ioc->sh->max_id - 1;
3944
3945 /* Following parameters will not change
3946 * in this routine.
3947 */
3948 iocmd.cmd = SYNCHRONIZE_CACHE;
3949 iocmd.flags = 0;
3950 iocmd.physDiskNum = -1;
3951 iocmd.data = NULL;
3952 iocmd.data_dma = -1;
3953 iocmd.size = 0;
3954 iocmd.rsvd = iocmd.rsvd2 = 0;
3955
3956 /* No SCSI hosts
3957 */
3958 if (hd->Targets == NULL)
3959 return 0;
3960
3961 /* Skip the host
3962 */
3963 if (id == hostId)
3964 id++;
3965
3966 /* Write SDP1 for all SCSI devices
3967 * Alloc memory and set up config buffer
3968 */
3969 if (ioc->bus_type == SCSI) {
3970 if (ioc->spi_data.sdp1length > 0) {
3971 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3972 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3973
3974 if (pcfg1Data != NULL) {
3975 doConfig = 1;
3976 header1.PageVersion = ioc->spi_data.sdp1version;
3977 header1.PageLength = ioc->spi_data.sdp1length;
3978 header1.PageNumber = 1;
3979 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3980 cfg.hdr = &header1;
3981 cfg.physAddr = cfg1_dma_addr;
3982 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3983 cfg.dir = 1;
3984 cfg.timeout = 0;
3985 }
3986 }
3987 }
3988
3989 /* loop through all devices on this port
3990 */
3991 while (bus < MPT_MAX_BUS) {
3992 iocmd.bus = bus;
3993 iocmd.id = id;
3994 pTarget = hd->Targets[(int)id];
3995
3996 if (doConfig) {
3997
3998 /* Set the negotiation flags */
3999 if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
4000 flags = pTarget->negoFlags;
4001 } else {
4002 flags = hd->ioc->spi_data.noQas;
4003 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4004 data = hd->ioc->spi_data.nvram[id];
4005
4006 if (data & MPT_NVRAM_WIDE_DISABLE)
4007 flags |= MPT_TARGET_NO_NEGO_WIDE;
4008
4009 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
4010 if ((factor == 0) || (factor == MPT_ASYNC))
4011 flags |= MPT_TARGET_NO_NEGO_SYNC;
4012 }
4013 }
4014
4015 /* Force to async, narrow */
4016 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
4017 &configuration, flags);
4018 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
4019 "offset=0 negoFlags=%x request=%x config=%x\n",
4020 id, flags, requested, configuration));
4021 pcfg1Data->RequestedParameters = le32_to_cpu(requested);
4022 pcfg1Data->Reserved = 0;
4023 pcfg1Data->Configuration = le32_to_cpu(configuration);
4024 cfg.pageAddr = (bus<<8) | id;
4025 mpt_config(hd->ioc, &cfg);
4026 }
4027
4028 /* If target Ptr NULL or if this target is NOT a disk, skip.
4029 */
4030 if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
4031 for (lun=0; lun <= MPT_LAST_LUN; lun++) {
4032 /* If LUN present, issue the command
4033 */
4034 lun_index = (lun >> 5); /* 32 luns per lun_index */
4035 indexed_lun = (lun % 32);
4036 if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
4037 iocmd.lun = lun;
4038 (void) mptscsih_do_cmd(hd, &iocmd);
4039 }
4040 }
4041 }
4042
4043 /* get next relevant device */
4044 id++;
4045
4046 if (id == hostId)
4047 id++;
4048
4049 if (id > max_id) {
4050 id = 0;
4051 bus++;
4052 }
4053 }
4054
4055 if (pcfg1Data) {
4056 pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
4057 }
4058
4059 return 0;
4060}
4061
4062#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
4063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4064/**
4065 * mptscsih_domainValidation - Top level handler for domain validation.
4066 * @hd: Pointer to MPT_SCSI_HOST structure.
4067 *
4068 * Uses the ISR, but with special processing.
4069 * Called from schedule, should not be in interrupt mode.
4070 * While thread alive, do dv for all devices needing dv
4071 *
4072 * Return: None.
4073 */
4074static void
4075mptscsih_domainValidation(void *arg)
4076{
4077 MPT_SCSI_HOST *hd;
4078 MPT_ADAPTER *ioc;
4079 unsigned long flags;
4080 int id, maxid, dvStatus, did;
4081 int ii, isPhysDisk;
4082
4083 spin_lock_irqsave(&dvtaskQ_lock, flags);
4084 dvtaskQ_active = 1;
4085 if (dvtaskQ_release) {
4086 dvtaskQ_active = 0;
4087 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4088 return;
4089 }
4090 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4091
4092 /* For this ioc, loop through all devices and do dv to each device.
4093 * When complete with this ioc, search through the ioc list, and
4094 * for each scsi ioc found, do dv for all devices. Exit when no
4095 * device needs dv.
4096 */
4097 did = 1;
4098 while (did) {
4099 did = 0;
4100 list_for_each_entry(ioc, &ioc_list, list) {
4101 spin_lock_irqsave(&dvtaskQ_lock, flags);
4102 if (dvtaskQ_release) {
4103 dvtaskQ_active = 0;
4104 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4105 return;
4106 }
4107 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4108
4109 msleep(250);
4110
4111 /* DV only to SCSI adapters */
4112 if (ioc->bus_type != SCSI)
4113 continue;
4114
4115 /* Make sure everything looks ok */
4116 if (ioc->sh == NULL)
4117 continue;
4118
4119 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4120 if (hd == NULL)
4121 continue;
4122
4123 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4124 mpt_read_ioc_pg_3(ioc);
4125 if (ioc->spi_data.pIocPg3) {
4126 Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
4127 int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
4128
4129 while (numPDisk) {
4130 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4131 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4132
4133 pPDisk++;
4134 numPDisk--;
4135 }
4136 }
4137 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4138 }
4139
4140 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4141
4142 for (id = 0; id < maxid; id++) {
4143 spin_lock_irqsave(&dvtaskQ_lock, flags);
4144 if (dvtaskQ_release) {
4145 dvtaskQ_active = 0;
4146 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4147 return;
4148 }
4149 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4150 dvStatus = hd->ioc->spi_data.dvStatus[id];
4151
4152 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4153 did++;
4154 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4155 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4156
4157 msleep(250);
4158
4159 /* If hidden phys disk, block IO's to all
4160 * raid volumes
4161 * else, process normally
4162 */
4163 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4164 if (isPhysDisk) {
4165 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4166 if (hd->ioc->spi_data.isRaid & (1 << ii)) {
4167 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4168 }
4169 }
4170 }
4171
4172 if (mptscsih_doDv(hd, 0, id) == 1) {
4173 /* Untagged device was busy, try again
4174 */
4175 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4176 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4177 } else {
4178 /* DV is complete. Clear flags.
4179 */
4180 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4181 }
4182
4183 if (isPhysDisk) {
4184 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4185 if (hd->ioc->spi_data.isRaid & (1 << ii)) {
4186 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4187 }
4188 }
4189 }
4190
4191 if (hd->ioc->spi_data.noQas)
4192 mptscsih_qas_check(hd, id);
4193 }
4194 }
4195 }
4196 }
4197
4198 spin_lock_irqsave(&dvtaskQ_lock, flags);
4199 dvtaskQ_active = 0;
4200 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4201
4202 return;
4203}
4204
4205/* Search IOC page 3 to determine if this is hidden physical disk
4206 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004207static int
4208mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209{
4210 if (ioc->spi_data.pIocPg3) {
4211 Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
4212 int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
4213
4214 while (numPDisk) {
4215 if (pPDisk->PhysDiskID == id) {
4216 return 1;
4217 }
4218 pPDisk++;
4219 numPDisk--;
4220 }
4221 }
4222 return 0;
4223}
4224
4225/* Write SDP1 if no QAS has been enabled
4226 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004227static void
4228mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229{
4230 VirtDevice *pTarget;
4231 int ii;
4232
4233 if (hd->Targets == NULL)
4234 return;
4235
4236 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4237 if (ii == id)
4238 continue;
4239
4240 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4241 continue;
4242
4243 pTarget = hd->Targets[ii];
4244
4245 if ((pTarget != NULL) && (!pTarget->raidVolume)) {
4246 if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4247 pTarget->negoFlags |= hd->ioc->spi_data.noQas;
4248 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4249 mptscsih_writeSDP1(hd, 0, ii, 0);
4250 }
4251 } else {
4252 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4253 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4254 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4255 }
4256 }
4257 }
4258 return;
4259}
4260
4261
4262
4263#define MPT_GET_NVRAM_VALS 0x01
4264#define MPT_UPDATE_MAX 0x02
4265#define MPT_SET_MAX 0x04
4266#define MPT_SET_MIN 0x08
4267#define MPT_FALLBACK 0x10
4268#define MPT_SAVE 0x20
4269
4270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4271/**
4272 * mptscsih_doDv - Perform domain validation to a target.
4273 * @hd: Pointer to MPT_SCSI_HOST structure.
4274 * @portnum: IOC port number.
4275 * @target: Physical ID of this target
4276 *
4277 * Uses the ISR, but with special processing.
4278 * MUST be single-threaded.
4279 * Test will exit if target is at async & narrow.
4280 *
4281 * Return: None.
4282 */
4283static int
4284mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4285{
4286 MPT_ADAPTER *ioc = hd->ioc;
4287 VirtDevice *pTarget;
4288 SCSIDevicePage1_t *pcfg1Data;
4289 SCSIDevicePage0_t *pcfg0Data;
4290 u8 *pbuf1;
4291 u8 *pbuf2;
4292 u8 *pDvBuf;
4293 dma_addr_t dvbuf_dma = -1;
4294 dma_addr_t buf1_dma = -1;
4295 dma_addr_t buf2_dma = -1;
4296 dma_addr_t cfg1_dma_addr = -1;
4297 dma_addr_t cfg0_dma_addr = -1;
4298 ConfigPageHeader_t header1;
4299 ConfigPageHeader_t header0;
4300 DVPARAMETERS dv;
4301 INTERNAL_CMD iocmd;
4302 CONFIGPARMS cfg;
4303 int dv_alloc = 0;
4304 int rc, sz = 0;
4305 int bufsize = 0;
4306 int dataBufSize = 0;
4307 int echoBufSize = 0;
4308 int notDone;
4309 int patt;
4310 int repeat;
4311 int retcode = 0;
4312 int nfactor = MPT_ULTRA320;
4313 char firstPass = 1;
4314 char doFallback = 0;
4315 char readPage0;
4316 char bus, lun;
4317 char inq0 = 0;
4318
4319 if (ioc->spi_data.sdp1length == 0)
4320 return 0;
4321
4322 if (ioc->spi_data.sdp0length == 0)
4323 return 0;
4324
4325 /* If multiple buses are used, require that the initiator
4326 * id be the same on all buses.
4327 */
4328 if (id == ioc->pfacts[0].PortSCSIID)
4329 return 0;
4330
4331 lun = 0;
4332 bus = (u8) bus_number;
4333 ddvtprintk((MYIOC_s_NOTE_FMT
4334 "DV started: bus=%d, id=%d dv @ %p\n",
4335 ioc->name, bus, id, &dv));
4336
4337 /* Prep DV structure
4338 */
4339 memset (&dv, 0, sizeof(DVPARAMETERS));
4340 dv.id = id;
4341
4342 /* Populate tmax with the current maximum
4343 * transfer parameters for this target.
4344 * Exit if narrow and async.
4345 */
4346 dv.cmd = MPT_GET_NVRAM_VALS;
4347 mptscsih_dv_parms(hd, &dv, NULL);
4348
4349 /* Prep SCSI IO structure
4350 */
4351 iocmd.id = id;
4352 iocmd.bus = bus;
4353 iocmd.lun = lun;
4354 iocmd.flags = 0;
4355 iocmd.physDiskNum = -1;
4356 iocmd.rsvd = iocmd.rsvd2 = 0;
4357
4358 pTarget = hd->Targets[id];
4359
4360 /* Use tagged commands if possible.
4361 */
4362 if (pTarget) {
4363 if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
4364 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4365 else {
4366 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4367 return 0;
4368
4369 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4370 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4371 return 0;
4372 }
4373 }
4374
4375 /* Prep cfg structure
4376 */
4377 cfg.pageAddr = (bus<<8) | id;
4378 cfg.hdr = NULL;
4379
4380 /* Prep SDP0 header
4381 */
4382 header0.PageVersion = ioc->spi_data.sdp0version;
4383 header0.PageLength = ioc->spi_data.sdp0length;
4384 header0.PageNumber = 0;
4385 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4386
4387 /* Prep SDP1 header
4388 */
4389 header1.PageVersion = ioc->spi_data.sdp1version;
4390 header1.PageLength = ioc->spi_data.sdp1length;
4391 header1.PageNumber = 1;
4392 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4393
4394 if (header0.PageLength & 1)
4395 dv_alloc = (header0.PageLength * 4) + 4;
4396
4397 dv_alloc += (2048 + (header1.PageLength * 4));
4398
4399 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4400 if (pDvBuf == NULL)
4401 return 0;
4402
4403 sz = 0;
4404 pbuf1 = (u8 *)pDvBuf;
4405 buf1_dma = dvbuf_dma;
4406 sz +=1024;
4407
4408 pbuf2 = (u8 *) (pDvBuf + sz);
4409 buf2_dma = dvbuf_dma + sz;
4410 sz +=1024;
4411
4412 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4413 cfg0_dma_addr = dvbuf_dma + sz;
4414 sz += header0.PageLength * 4;
4415
4416 /* 8-byte alignment
4417 */
4418 if (header0.PageLength & 1)
4419 sz += 4;
4420
4421 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4422 cfg1_dma_addr = dvbuf_dma + sz;
4423
4424 /* Skip this ID? Set cfg.hdr to force config page write
4425 */
4426 {
4427 ScsiCfgData *pspi_data = &hd->ioc->spi_data;
4428 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4429 /* Set the factor from nvram */
4430 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4431 if (nfactor < pspi_data->minSyncFactor )
4432 nfactor = pspi_data->minSyncFactor;
4433
4434 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4435 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4436
4437 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4438 ioc->name, bus, id, lun));
4439
4440 dv.cmd = MPT_SET_MAX;
4441 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4442 cfg.hdr = &header1;
4443
4444 /* Save the final negotiated settings to
4445 * SCSI device page 1.
4446 */
4447 cfg.physAddr = cfg1_dma_addr;
4448 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4449 cfg.dir = 1;
4450 mpt_config(hd->ioc, &cfg);
4451 goto target_done;
4452 }
4453 }
4454 }
4455
4456 /* Finish iocmd inititialization - hidden or visible disk? */
4457 if (ioc->spi_data.pIocPg3) {
4458 /* Search IOC page 3 for matching id
4459 */
4460 Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
4461 int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
4462
4463 while (numPDisk) {
4464 if (pPDisk->PhysDiskID == id) {
4465 /* match */
4466 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4467 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4468
4469 /* Quiesce the IM
4470 */
4471 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4472 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4473 goto target_done;
4474 }
4475 break;
4476 }
4477 pPDisk++;
4478 numPDisk--;
4479 }
4480 }
4481
4482 /* RAID Volume ID's may double for a physical device. If RAID but
4483 * not a physical ID as well, skip DV.
4484 */
4485 if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
4486 goto target_done;
4487
4488
4489 /* Basic Test.
4490 * Async & Narrow - Inquiry
4491 * Async & Narrow - Inquiry
4492 * Maximum transfer rate - Inquiry
4493 * Compare buffers:
4494 * If compare, test complete.
4495 * If miscompare and first pass, repeat
4496 * If miscompare and not first pass, fall back and repeat
4497 */
4498 hd->pLocal = NULL;
4499 readPage0 = 0;
4500 sz = SCSI_MAX_INQUIRY_BYTES;
4501 rc = MPT_SCANDV_GOOD;
4502 while (1) {
4503 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4504 retcode = 0;
4505 dv.cmd = MPT_SET_MIN;
4506 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4507
4508 cfg.hdr = &header1;
4509 cfg.physAddr = cfg1_dma_addr;
4510 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4511 cfg.dir = 1;
4512 if (mpt_config(hd->ioc, &cfg) != 0)
4513 goto target_done;
4514
4515 /* Wide - narrow - wide workaround case
4516 */
4517 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4518 /* Send an untagged command to reset disk Qs corrupted
4519 * when a parity error occurs on a Request Sense.
4520 */
4521 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4522 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4523 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4524
4525 iocmd.cmd = REQUEST_SENSE;
4526 iocmd.data_dma = buf1_dma;
4527 iocmd.data = pbuf1;
4528 iocmd.size = 0x12;
4529 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4530 goto target_done;
4531 else {
4532 if (hd->pLocal == NULL)
4533 goto target_done;
4534 rc = hd->pLocal->completion;
4535 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4536 dv.max.width = 0;
4537 doFallback = 0;
4538 } else
4539 goto target_done;
4540 }
4541 } else
4542 goto target_done;
4543 }
4544
4545 iocmd.cmd = INQUIRY;
4546 iocmd.data_dma = buf1_dma;
4547 iocmd.data = pbuf1;
4548 iocmd.size = sz;
4549 memset(pbuf1, 0x00, sz);
4550 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4551 goto target_done;
4552 else {
4553 if (hd->pLocal == NULL)
4554 goto target_done;
4555 rc = hd->pLocal->completion;
4556 if (rc == MPT_SCANDV_GOOD) {
4557 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4558 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4559 retcode = 1;
4560 else
4561 retcode = 0;
4562
4563 goto target_done;
4564 }
4565 } else if (rc == MPT_SCANDV_SENSE) {
4566 ;
4567 } else {
4568 /* If first command doesn't complete
4569 * with a good status or with a check condition,
4570 * exit.
4571 */
4572 goto target_done;
4573 }
4574 }
4575
4576 /* Reset the size for disks
4577 */
4578 inq0 = (*pbuf1) & 0x1F;
4579 if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
4580 sz = 0x40;
4581 iocmd.size = sz;
4582 }
4583
4584 /* Another GEM workaround. Check peripheral device type,
4585 * if PROCESSOR, quit DV.
4586 */
4587 if (inq0 == TYPE_PROCESSOR) {
4588 mptscsih_initTarget(hd,
4589 bus,
4590 id,
4591 lun,
4592 pbuf1,
4593 sz);
4594 goto target_done;
4595 }
4596
4597 if (inq0 > 0x08)
4598 goto target_done;
4599
4600 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4601 goto target_done;
4602
4603 if (sz == 0x40) {
4604 if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
4605 && (pTarget->minSyncFactor > 0x09)) {
4606 if ((pbuf1[56] & 0x04) == 0)
4607 ;
4608 else if ((pbuf1[56] & 0x01) == 1) {
4609 pTarget->minSyncFactor =
4610 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4611 } else {
4612 pTarget->minSyncFactor =
4613 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4614 }
4615
4616 dv.max.factor = pTarget->minSyncFactor;
4617
4618 if ((pbuf1[56] & 0x02) == 0) {
4619 pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
4620 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
4621 ddvprintk((MYIOC_s_NOTE_FMT
4622 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
4623 ioc->name, id, pbuf1[56]));
4624 }
4625 }
4626 }
4627
4628 if (doFallback)
4629 dv.cmd = MPT_FALLBACK;
4630 else
4631 dv.cmd = MPT_SET_MAX;
4632
4633 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4634 if (mpt_config(hd->ioc, &cfg) != 0)
4635 goto target_done;
4636
4637 if ((!dv.now.width) && (!dv.now.offset))
4638 goto target_done;
4639
4640 iocmd.cmd = INQUIRY;
4641 iocmd.data_dma = buf2_dma;
4642 iocmd.data = pbuf2;
4643 iocmd.size = sz;
4644 memset(pbuf2, 0x00, sz);
4645 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4646 goto target_done;
4647 else if (hd->pLocal == NULL)
4648 goto target_done;
4649 else {
4650 /* Save the return code.
4651 * If this is the first pass,
4652 * read SCSI Device Page 0
4653 * and update the target max parameters.
4654 */
4655 rc = hd->pLocal->completion;
4656 doFallback = 0;
4657 if (rc == MPT_SCANDV_GOOD) {
4658 if (!readPage0) {
4659 u32 sdp0_info;
4660 u32 sdp0_nego;
4661
4662 cfg.hdr = &header0;
4663 cfg.physAddr = cfg0_dma_addr;
4664 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4665 cfg.dir = 0;
4666
4667 if (mpt_config(hd->ioc, &cfg) != 0)
4668 goto target_done;
4669
4670 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4671 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4672
4673 /* Quantum and Fujitsu workarounds.
4674 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4675 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4676 * Resetart with a request for U160.
4677 */
4678 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4679 doFallback = 1;
4680 } else {
4681 dv.cmd = MPT_UPDATE_MAX;
4682 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4683 /* Update the SCSI device page 1 area
4684 */
4685 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4686 readPage0 = 1;
4687 }
4688 }
4689
4690 /* Quantum workaround. Restart this test will the fallback
4691 * flag set.
4692 */
4693 if (doFallback == 0) {
4694 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4695 if (!firstPass)
4696 doFallback = 1;
4697 } else {
4698 ddvprintk((MYIOC_s_NOTE_FMT
4699 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4700 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4701 mptscsih_initTarget(hd,
4702 bus,
4703 id,
4704 lun,
4705 pbuf1,
4706 sz);
4707 break; /* test complete */
4708 }
4709 }
4710
4711
4712 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4713 doFallback = 1; /* set fallback flag */
4714 else if ((rc == MPT_SCANDV_DID_RESET) ||
4715 (rc == MPT_SCANDV_SENSE) ||
4716 (rc == MPT_SCANDV_FALLBACK))
4717 doFallback = 1; /* set fallback flag */
4718 else
4719 goto target_done;
4720
4721 firstPass = 0;
4722 }
4723 }
4724 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4725
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004726 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 goto target_done;
4728
4729 inq0 = (*pbuf1) & 0x1F;
4730
4731 /* Continue only for disks
4732 */
4733 if (inq0 != 0)
4734 goto target_done;
4735
4736 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4737 goto target_done;
4738
4739 /* Start the Enhanced Test.
4740 * 0) issue TUR to clear out check conditions
4741 * 1) read capacity of echo (regular) buffer
4742 * 2) reserve device
4743 * 3) do write-read-compare data pattern test
4744 * 4) release
4745 * 5) update nego parms to target struct
4746 */
4747 cfg.hdr = &header1;
4748 cfg.physAddr = cfg1_dma_addr;
4749 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4750 cfg.dir = 1;
4751
4752 iocmd.cmd = TEST_UNIT_READY;
4753 iocmd.data_dma = -1;
4754 iocmd.data = NULL;
4755 iocmd.size = 0;
4756 notDone = 1;
4757 while (notDone) {
4758 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4759 goto target_done;
4760
4761 if (hd->pLocal == NULL)
4762 goto target_done;
4763
4764 rc = hd->pLocal->completion;
4765 if (rc == MPT_SCANDV_GOOD)
4766 notDone = 0;
4767 else if (rc == MPT_SCANDV_SENSE) {
4768 u8 skey = hd->pLocal->sense[2] & 0x0F;
4769 u8 asc = hd->pLocal->sense[12];
4770 u8 ascq = hd->pLocal->sense[13];
4771 ddvprintk((MYIOC_s_INFO_FMT
4772 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4773 ioc->name, skey, asc, ascq));
4774
4775 if (skey == UNIT_ATTENTION)
4776 notDone++; /* repeat */
4777 else if ((skey == NOT_READY) &&
4778 (asc == 0x04)&&(ascq == 0x01)) {
4779 /* wait then repeat */
4780 mdelay (2000);
4781 notDone++;
4782 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4783 /* no medium, try read test anyway */
4784 notDone = 0;
4785 } else {
4786 /* All other errors are fatal.
4787 */
4788 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4789 ioc->name));
4790 goto target_done;
4791 }
4792 } else
4793 goto target_done;
4794 }
4795
4796 iocmd.cmd = READ_BUFFER;
4797 iocmd.data_dma = buf1_dma;
4798 iocmd.data = pbuf1;
4799 iocmd.size = 4;
4800 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4801
4802 dataBufSize = 0;
4803 echoBufSize = 0;
4804 for (patt = 0; patt < 2; patt++) {
4805 if (patt == 0)
4806 iocmd.flags |= MPT_ICFLAG_ECHO;
4807 else
4808 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4809
4810 notDone = 1;
4811 while (notDone) {
4812 bufsize = 0;
4813
4814 /* If not ready after 8 trials,
4815 * give up on this device.
4816 */
4817 if (notDone > 8)
4818 goto target_done;
4819
4820 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4821 goto target_done;
4822 else if (hd->pLocal == NULL)
4823 goto target_done;
4824 else {
4825 rc = hd->pLocal->completion;
4826 ddvprintk(("ReadBuffer Comp Code %d", rc));
4827 ddvprintk((" buff: %0x %0x %0x %0x\n",
4828 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4829
4830 if (rc == MPT_SCANDV_GOOD) {
4831 notDone = 0;
4832 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4833 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
4834 } else {
4835 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4836 }
4837 } else if (rc == MPT_SCANDV_SENSE) {
4838 u8 skey = hd->pLocal->sense[2] & 0x0F;
4839 u8 asc = hd->pLocal->sense[12];
4840 u8 ascq = hd->pLocal->sense[13];
4841 ddvprintk((MYIOC_s_INFO_FMT
4842 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4843 ioc->name, skey, asc, ascq));
4844 if (skey == ILLEGAL_REQUEST) {
4845 notDone = 0;
4846 } else if (skey == UNIT_ATTENTION) {
4847 notDone++; /* repeat */
4848 } else if ((skey == NOT_READY) &&
4849 (asc == 0x04)&&(ascq == 0x01)) {
4850 /* wait then repeat */
4851 mdelay (2000);
4852 notDone++;
4853 } else {
4854 /* All other errors are fatal.
4855 */
4856 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4857 ioc->name));
4858 goto target_done;
4859 }
4860 } else {
4861 /* All other errors are fatal
4862 */
4863 goto target_done;
4864 }
4865 }
4866 }
4867
4868 if (iocmd.flags & MPT_ICFLAG_ECHO)
4869 echoBufSize = bufsize;
4870 else
4871 dataBufSize = bufsize;
4872 }
4873 sz = 0;
4874 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4875
4876 /* Use echo buffers if possible,
4877 * Exit if both buffers are 0.
4878 */
4879 if (echoBufSize > 0) {
4880 iocmd.flags |= MPT_ICFLAG_ECHO;
4881 if (dataBufSize > 0)
4882 bufsize = min(echoBufSize, dataBufSize);
4883 else
4884 bufsize = echoBufSize;
4885 } else if (dataBufSize == 0)
4886 goto target_done;
4887
4888 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4889 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4890
4891 /* Data buffers for write-read-compare test max 1K.
4892 */
4893 sz = min(bufsize, 1024);
4894
4895 /* --- loop ----
4896 * On first pass, always issue a reserve.
4897 * On additional loops, only if a reset has occurred.
4898 * iocmd.flags indicates if echo or regular buffer
4899 */
4900 for (patt = 0; patt < 4; patt++) {
4901 ddvprintk(("Pattern %d\n", patt));
4902 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4903 iocmd.cmd = TEST_UNIT_READY;
4904 iocmd.data_dma = -1;
4905 iocmd.data = NULL;
4906 iocmd.size = 0;
4907 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4908 goto target_done;
4909
4910 iocmd.cmd = RELEASE;
4911 iocmd.data_dma = -1;
4912 iocmd.data = NULL;
4913 iocmd.size = 0;
4914 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4915 goto target_done;
4916 else if (hd->pLocal == NULL)
4917 goto target_done;
4918 else {
4919 rc = hd->pLocal->completion;
4920 ddvprintk(("Release rc %d\n", rc));
4921 if (rc == MPT_SCANDV_GOOD)
4922 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4923 else
4924 goto target_done;
4925 }
4926 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4927 }
4928 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4929
4930 repeat = 5;
4931 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4932 iocmd.cmd = RESERVE;
4933 iocmd.data_dma = -1;
4934 iocmd.data = NULL;
4935 iocmd.size = 0;
4936 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4937 goto target_done;
4938 else if (hd->pLocal == NULL)
4939 goto target_done;
4940 else {
4941 rc = hd->pLocal->completion;
4942 if (rc == MPT_SCANDV_GOOD) {
4943 iocmd.flags |= MPT_ICFLAG_RESERVED;
4944 } else if (rc == MPT_SCANDV_SENSE) {
4945 /* Wait if coming ready
4946 */
4947 u8 skey = hd->pLocal->sense[2] & 0x0F;
4948 u8 asc = hd->pLocal->sense[12];
4949 u8 ascq = hd->pLocal->sense[13];
4950 ddvprintk((MYIOC_s_INFO_FMT
4951 "DV: Reserve Failed: ", ioc->name));
4952 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4953 skey, asc, ascq));
4954
4955 if ((skey == NOT_READY) && (asc == 0x04)&&
4956 (ascq == 0x01)) {
4957 /* wait then repeat */
4958 mdelay (2000);
4959 notDone++;
4960 } else {
4961 ddvprintk((MYIOC_s_INFO_FMT
4962 "DV: Reserved Failed.", ioc->name));
4963 goto target_done;
4964 }
4965 } else {
4966 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4967 ioc->name));
4968 goto target_done;
4969 }
4970 }
4971 }
4972
4973 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4974 iocmd.cmd = WRITE_BUFFER;
4975 iocmd.data_dma = buf1_dma;
4976 iocmd.data = pbuf1;
4977 iocmd.size = sz;
4978 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4979 goto target_done;
4980 else if (hd->pLocal == NULL)
4981 goto target_done;
4982 else {
4983 rc = hd->pLocal->completion;
4984 if (rc == MPT_SCANDV_GOOD)
4985 ; /* Issue read buffer */
4986 else if (rc == MPT_SCANDV_DID_RESET) {
4987 /* If using echo buffers, reset to data buffers.
4988 * Else do Fallback and restart
4989 * this test (re-issue reserve
4990 * because of bus reset).
4991 */
4992 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4993 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4994 } else {
4995 dv.cmd = MPT_FALLBACK;
4996 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4997
4998 if (mpt_config(hd->ioc, &cfg) != 0)
4999 goto target_done;
5000
5001 if ((!dv.now.width) && (!dv.now.offset))
5002 goto target_done;
5003 }
5004
5005 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5006 patt = -1;
5007 continue;
5008 } else if (rc == MPT_SCANDV_SENSE) {
5009 /* Restart data test if UA, else quit.
5010 */
5011 u8 skey = hd->pLocal->sense[2] & 0x0F;
5012 ddvprintk((MYIOC_s_INFO_FMT
5013 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5014 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5015 if (skey == UNIT_ATTENTION) {
5016 patt = -1;
5017 continue;
5018 } else if (skey == ILLEGAL_REQUEST) {
5019 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5020 if (dataBufSize >= bufsize) {
5021 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5022 patt = -1;
5023 continue;
5024 }
5025 }
5026 goto target_done;
5027 }
5028 else
5029 goto target_done;
5030 } else {
5031 /* fatal error */
5032 goto target_done;
5033 }
5034 }
5035
5036 iocmd.cmd = READ_BUFFER;
5037 iocmd.data_dma = buf2_dma;
5038 iocmd.data = pbuf2;
5039 iocmd.size = sz;
5040 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5041 goto target_done;
5042 else if (hd->pLocal == NULL)
5043 goto target_done;
5044 else {
5045 rc = hd->pLocal->completion;
5046 if (rc == MPT_SCANDV_GOOD) {
5047 /* If buffers compare,
5048 * go to next pattern,
5049 * else, do a fallback and restart
5050 * data transfer test.
5051 */
5052 if (memcmp (pbuf1, pbuf2, sz) == 0) {
5053 ; /* goto next pattern */
5054 } else {
5055 /* Miscompare with Echo buffer, go to data buffer,
5056 * if that buffer exists.
5057 * Miscompare with Data buffer, check first 4 bytes,
5058 * some devices return capacity. Exit in this case.
5059 */
5060 if (iocmd.flags & MPT_ICFLAG_ECHO) {
5061 if (dataBufSize >= bufsize)
5062 iocmd.flags &= ~MPT_ICFLAG_ECHO;
5063 else
5064 goto target_done;
5065 } else {
5066 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
5067 /* Argh. Device returning wrong data.
5068 * Quit DV for this device.
5069 */
5070 goto target_done;
5071 }
5072
5073 /* Had an actual miscompare. Slow down.*/
5074 dv.cmd = MPT_FALLBACK;
5075 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5076
5077 if (mpt_config(hd->ioc, &cfg) != 0)
5078 goto target_done;
5079
5080 if ((!dv.now.width) && (!dv.now.offset))
5081 goto target_done;
5082 }
5083
5084 patt = -1;
5085 continue;
5086 }
5087 } else if (rc == MPT_SCANDV_DID_RESET) {
5088 /* Do Fallback and restart
5089 * this test (re-issue reserve
5090 * because of bus reset).
5091 */
5092 dv.cmd = MPT_FALLBACK;
5093 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5094
5095 if (mpt_config(hd->ioc, &cfg) != 0)
5096 goto target_done;
5097
5098 if ((!dv.now.width) && (!dv.now.offset))
5099 goto target_done;
5100
5101 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5102 patt = -1;
5103 continue;
5104 } else if (rc == MPT_SCANDV_SENSE) {
5105 /* Restart data test if UA, else quit.
5106 */
5107 u8 skey = hd->pLocal->sense[2] & 0x0F;
5108 ddvprintk((MYIOC_s_INFO_FMT
5109 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5110 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5111 if (skey == UNIT_ATTENTION) {
5112 patt = -1;
5113 continue;
5114 }
5115 else
5116 goto target_done;
5117 } else {
5118 /* fatal error */
5119 goto target_done;
5120 }
5121 }
5122
5123 } /* --- end of patt loop ---- */
5124
5125target_done:
5126 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5127 iocmd.cmd = RELEASE;
5128 iocmd.data_dma = -1;
5129 iocmd.data = NULL;
5130 iocmd.size = 0;
5131 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5132 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5133 ioc->name, id);
5134 else if (hd->pLocal) {
5135 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5136 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5137 } else {
5138 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5139 ioc->name, id);
5140 }
5141 }
5142
5143
5144 /* Set if cfg1_dma_addr contents is valid
5145 */
5146 if ((cfg.hdr != NULL) && (retcode == 0)){
5147 /* If disk, not U320, disable QAS
5148 */
5149 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5150 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
5151 ddvprintk((MYIOC_s_NOTE_FMT
5152 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5153 }
5154
5155 dv.cmd = MPT_SAVE;
5156 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5157
5158 /* Double writes to SDP1 can cause problems,
5159 * skip save of the final negotiated settings to
5160 * SCSI device page 1.
5161 *
5162 cfg.hdr = &header1;
5163 cfg.physAddr = cfg1_dma_addr;
5164 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5165 cfg.dir = 1;
5166 mpt_config(hd->ioc, &cfg);
5167 */
5168 }
5169
5170 /* If this is a RAID Passthrough, enable internal IOs
5171 */
5172 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5173 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5174 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5175 }
5176
5177 /* Done with the DV scan of the current target
5178 */
5179 if (pDvBuf)
5180 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5181
5182 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5183 ioc->name, id));
5184
5185 return retcode;
5186}
5187
5188/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5189/* mptscsih_dv_parms - perform a variety of operations on the
5190 * parameters used for negotiation.
5191 * @hd: Pointer to a SCSI host.
5192 * @dv: Pointer to a structure that contains the maximum and current
5193 * negotiated parameters.
5194 */
5195static void
5196mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5197{
5198 VirtDevice *pTarget;
5199 SCSIDevicePage0_t *pPage0;
5200 SCSIDevicePage1_t *pPage1;
5201 int val = 0, data, configuration;
5202 u8 width = 0;
5203 u8 offset = 0;
5204 u8 factor = 0;
5205 u8 negoFlags = 0;
5206 u8 cmd = dv->cmd;
5207 u8 id = dv->id;
5208
5209 switch (cmd) {
5210 case MPT_GET_NVRAM_VALS:
5211 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5212 hd->ioc->name));
5213 /* Get the NVRAM values and save in tmax
5214 * If not an LVD bus, the adapter minSyncFactor has been
5215 * already throttled back.
5216 */
5217 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
5218 width = pTarget->maxWidth;
5219 offset = pTarget->maxOffset;
5220 factor = pTarget->minSyncFactor;
5221 negoFlags = pTarget->negoFlags;
5222 } else {
5223 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5224 data = hd->ioc->spi_data.nvram[id];
5225 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5226 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5227 factor = MPT_ASYNC;
5228 else {
5229 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5230 if ((factor == 0) || (factor == MPT_ASYNC)){
5231 factor = MPT_ASYNC;
5232 offset = 0;
5233 }
5234 }
5235 } else {
5236 width = MPT_NARROW;
5237 offset = 0;
5238 factor = MPT_ASYNC;
5239 }
5240
5241 /* Set the negotiation flags */
5242 negoFlags = hd->ioc->spi_data.noQas;
5243 if (!width)
5244 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5245
5246 if (!offset)
5247 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5248 }
5249
5250 /* limit by adapter capabilities */
5251 width = min(width, hd->ioc->spi_data.maxBusWidth);
5252 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5253 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5254
5255 /* Check Consistency */
5256 if (offset && (factor < MPT_ULTRA2) && !width)
5257 factor = MPT_ULTRA2;
5258
5259 dv->max.width = width;
5260 dv->max.offset = offset;
5261 dv->max.factor = factor;
5262 dv->max.flags = negoFlags;
5263 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5264 id, width, factor, offset, negoFlags));
5265 break;
5266
5267 case MPT_UPDATE_MAX:
5268 ddvprintk((MYIOC_s_NOTE_FMT
5269 "Updating with SDP0 Data: ", hd->ioc->name));
5270 /* Update tmax values with those from Device Page 0.*/
5271 pPage0 = (SCSIDevicePage0_t *) pPage;
5272 if (pPage0) {
5273 val = cpu_to_le32(pPage0->NegotiatedParameters);
5274 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5275 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5276 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5277 }
5278
5279 dv->now.width = dv->max.width;
5280 dv->now.offset = dv->max.offset;
5281 dv->now.factor = dv->max.factor;
5282 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5283 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5284 break;
5285
5286 case MPT_SET_MAX:
5287 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5288 hd->ioc->name));
5289 /* Set current to the max values. Update the config page.*/
5290 dv->now.width = dv->max.width;
5291 dv->now.offset = dv->max.offset;
5292 dv->now.factor = dv->max.factor;
5293 dv->now.flags = dv->max.flags;
5294
5295 pPage1 = (SCSIDevicePage1_t *)pPage;
5296 if (pPage1) {
5297 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5298 dv->now.offset, &val, &configuration, dv->now.flags);
5299 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5300 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5301 pPage1->RequestedParameters = le32_to_cpu(val);
5302 pPage1->Reserved = 0;
5303 pPage1->Configuration = le32_to_cpu(configuration);
5304 }
5305
5306 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x request=%x configuration=%x\n",
5307 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5308 break;
5309
5310 case MPT_SET_MIN:
5311 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5312 hd->ioc->name));
5313 /* Set page to asynchronous and narrow
5314 * Do not update now, breaks fallback routine. */
5315 width = MPT_NARROW;
5316 offset = 0;
5317 factor = MPT_ASYNC;
5318 negoFlags = dv->max.flags;
5319
5320 pPage1 = (SCSIDevicePage1_t *)pPage;
5321 if (pPage1) {
5322 mptscsih_setDevicePage1Flags (width, factor,
5323 offset, &val, &configuration, negoFlags);
5324 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5325 id, width, factor, offset, negoFlags, val, configuration));
5326 pPage1->RequestedParameters = le32_to_cpu(val);
5327 pPage1->Reserved = 0;
5328 pPage1->Configuration = le32_to_cpu(configuration);
5329 }
5330 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5331 id, width, factor, offset, val, configuration, negoFlags));
5332 break;
5333
5334 case MPT_FALLBACK:
5335 ddvprintk((MYIOC_s_NOTE_FMT
5336 "Fallback: Start: offset %d, factor %x, width %d \n",
5337 hd->ioc->name, dv->now.offset,
5338 dv->now.factor, dv->now.width));
5339 width = dv->now.width;
5340 offset = dv->now.offset;
5341 factor = dv->now.factor;
5342 if ((offset) && (dv->max.width)) {
5343 if (factor < MPT_ULTRA160)
5344 factor = MPT_ULTRA160;
5345 else if (factor < MPT_ULTRA2) {
5346 factor = MPT_ULTRA2;
5347 width = MPT_WIDE;
5348 } else if ((factor == MPT_ULTRA2) && width) {
5349 factor = MPT_ULTRA2;
5350 width = MPT_NARROW;
5351 } else if (factor < MPT_ULTRA) {
5352 factor = MPT_ULTRA;
5353 width = MPT_WIDE;
5354 } else if ((factor == MPT_ULTRA) && width) {
5355 width = MPT_NARROW;
5356 } else if (factor < MPT_FAST) {
5357 factor = MPT_FAST;
5358 width = MPT_WIDE;
5359 } else if ((factor == MPT_FAST) && width) {
5360 factor = MPT_FAST;
5361 width = MPT_NARROW;
5362 } else if (factor < MPT_SCSI) {
5363 factor = MPT_SCSI;
5364 width = MPT_WIDE;
5365 } else if ((factor == MPT_SCSI) && width) {
5366 factor = MPT_SCSI;
5367 width = MPT_NARROW;
5368 } else {
5369 factor = MPT_ASYNC;
5370 offset = 0;
5371 }
5372
5373 } else if (offset) {
5374 width = MPT_NARROW;
5375 if (factor < MPT_ULTRA)
5376 factor = MPT_ULTRA;
5377 else if (factor < MPT_FAST)
5378 factor = MPT_FAST;
5379 else if (factor < MPT_SCSI)
5380 factor = MPT_SCSI;
5381 else {
5382 factor = MPT_ASYNC;
5383 offset = 0;
5384 }
5385
5386 } else {
5387 width = MPT_NARROW;
5388 factor = MPT_ASYNC;
5389 }
5390 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5391 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5392
5393 dv->now.width = width;
5394 dv->now.offset = offset;
5395 dv->now.factor = factor;
5396 dv->now.flags = dv->max.flags;
5397
5398 pPage1 = (SCSIDevicePage1_t *)pPage;
5399 if (pPage1) {
5400 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5401 &configuration, dv->now.flags);
5402 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x flags=%x request=%x config=%x\n",
5403 id, width, offset, factor, dv->now.flags, val, configuration));
5404
5405 pPage1->RequestedParameters = le32_to_cpu(val);
5406 pPage1->Reserved = 0;
5407 pPage1->Configuration = le32_to_cpu(configuration);
5408 }
5409
5410 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5411 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5412 break;
5413
5414 case MPT_SAVE:
5415 ddvprintk((MYIOC_s_NOTE_FMT
5416 "Saving to Target structure: ", hd->ioc->name));
5417 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5418 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5419
5420 /* Save these values to target structures
5421 * or overwrite nvram (phys disks only).
5422 */
5423
5424 if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
5425 pTarget->maxWidth = dv->now.width;
5426 pTarget->maxOffset = dv->now.offset;
5427 pTarget->minSyncFactor = dv->now.factor;
5428 pTarget->negoFlags = dv->now.flags;
5429 } else {
5430 /* Preserv all flags, use
5431 * read-modify-write algorithm
5432 */
5433 if (hd->ioc->spi_data.nvram) {
5434 data = hd->ioc->spi_data.nvram[id];
5435
5436 if (dv->now.width)
5437 data &= ~MPT_NVRAM_WIDE_DISABLE;
5438 else
5439 data |= MPT_NVRAM_WIDE_DISABLE;
5440
5441 if (!dv->now.offset)
5442 factor = MPT_ASYNC;
5443
5444 data &= ~MPT_NVRAM_SYNC_MASK;
5445 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5446
5447 hd->ioc->spi_data.nvram[id] = data;
5448 }
5449 }
5450 break;
5451 }
5452}
5453
5454/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5455/* mptscsih_fillbuf - fill a buffer with a special data pattern
5456 * cleanup. For bus scan only.
5457 *
5458 * @buffer: Pointer to data buffer to be filled.
5459 * @size: Number of bytes to fill
5460 * @index: Pattern index
5461 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5462 */
5463static void
5464mptscsih_fillbuf(char *buffer, int size, int index, int width)
5465{
5466 char *ptr = buffer;
5467 int ii;
5468 char byte;
5469 short val;
5470
5471 switch (index) {
5472 case 0:
5473
5474 if (width) {
5475 /* Pattern: 0000 FFFF 0000 FFFF
5476 */
5477 for (ii=0; ii < size; ii++, ptr++) {
5478 if (ii & 0x02)
5479 *ptr = 0xFF;
5480 else
5481 *ptr = 0x00;
5482 }
5483 } else {
5484 /* Pattern: 00 FF 00 FF
5485 */
5486 for (ii=0; ii < size; ii++, ptr++) {
5487 if (ii & 0x01)
5488 *ptr = 0xFF;
5489 else
5490 *ptr = 0x00;
5491 }
5492 }
5493 break;
5494
5495 case 1:
5496 if (width) {
5497 /* Pattern: 5555 AAAA 5555 AAAA 5555
5498 */
5499 for (ii=0; ii < size; ii++, ptr++) {
5500 if (ii & 0x02)
5501 *ptr = 0xAA;
5502 else
5503 *ptr = 0x55;
5504 }
5505 } else {
5506 /* Pattern: 55 AA 55 AA 55
5507 */
5508 for (ii=0; ii < size; ii++, ptr++) {
5509 if (ii & 0x01)
5510 *ptr = 0xAA;
5511 else
5512 *ptr = 0x55;
5513 }
5514 }
5515 break;
5516
5517 case 2:
5518 /* Pattern: 00 01 02 03 04 05
5519 * ... FE FF 00 01..
5520 */
5521 for (ii=0; ii < size; ii++, ptr++)
5522 *ptr = (char) ii;
5523 break;
5524
5525 case 3:
5526 if (width) {
5527 /* Wide Pattern: FFFE 0001 FFFD 0002
5528 * ... 4000 DFFF 8000 EFFF
5529 */
5530 byte = 0;
5531 for (ii=0; ii < size/2; ii++) {
5532 /* Create the base pattern
5533 */
5534 val = (1 << byte);
5535 /* every 64 (0x40) bytes flip the pattern
5536 * since we fill 2 bytes / iteration,
5537 * test for ii = 0x20
5538 */
5539 if (ii & 0x20)
5540 val = ~(val);
5541
5542 if (ii & 0x01) {
5543 *ptr = (char)( (val & 0xFF00) >> 8);
5544 ptr++;
5545 *ptr = (char)(val & 0xFF);
5546 byte++;
5547 byte &= 0x0F;
5548 } else {
5549 val = ~val;
5550 *ptr = (char)( (val & 0xFF00) >> 8);
5551 ptr++;
5552 *ptr = (char)(val & 0xFF);
5553 }
5554
5555 ptr++;
5556 }
5557 } else {
5558 /* Narrow Pattern: FE 01 FD 02 FB 04
5559 * .. 7F 80 01 FE 02 FD ... 80 7F
5560 */
5561 byte = 0;
5562 for (ii=0; ii < size; ii++, ptr++) {
5563 /* Base pattern - first 32 bytes
5564 */
5565 if (ii & 0x01) {
5566 *ptr = (1 << byte);
5567 byte++;
5568 byte &= 0x07;
5569 } else {
5570 *ptr = (char) (~(1 << byte));
5571 }
5572
5573 /* Flip the pattern every 32 bytes
5574 */
5575 if (ii & 0x20)
5576 *ptr = ~(*ptr);
5577 }
5578 }
5579 break;
5580 }
5581}
5582#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5583
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005584EXPORT_SYMBOL(mptscsih_remove);
5585EXPORT_SYMBOL(mptscsih_shutdown);
5586#ifdef CONFIG_PM
5587EXPORT_SYMBOL(mptscsih_suspend);
5588EXPORT_SYMBOL(mptscsih_resume);
5589#endif
5590EXPORT_SYMBOL(mptscsih_proc_info);
5591EXPORT_SYMBOL(mptscsih_info);
5592EXPORT_SYMBOL(mptscsih_qcmd);
5593EXPORT_SYMBOL(mptscsih_slave_alloc);
5594EXPORT_SYMBOL(mptscsih_slave_destroy);
5595EXPORT_SYMBOL(mptscsih_slave_configure);
5596EXPORT_SYMBOL(mptscsih_abort);
5597EXPORT_SYMBOL(mptscsih_dev_reset);
5598EXPORT_SYMBOL(mptscsih_bus_reset);
5599EXPORT_SYMBOL(mptscsih_host_reset);
5600EXPORT_SYMBOL(mptscsih_bios_param);
5601EXPORT_SYMBOL(mptscsih_io_done);
5602EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5603EXPORT_SYMBOL(mptscsih_scandv_complete);
5604EXPORT_SYMBOL(mptscsih_event_process);
5605EXPORT_SYMBOL(mptscsih_ioc_reset);
5606EXPORT_SYMBOL(mptscsih_store_queue_depth);
5607EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/