blob: cdac5578fdf220caefb48a3356710393558372ff [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04006 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * (mailto:mpt_linux_developer@lsil.com)
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include "linux_compat.h" /* linux-2.6 tweaks */
48#include <linux/module.h>
49#include <linux/kernel.h>
50#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
57#include <linux/sched.h>
58#include <linux/workqueue.h>
59
60#include <scsi/scsi.h>
61#include <scsi/scsi_cmnd.h>
62#include <scsi/scsi_device.h>
63#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060065#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68#include "mptscsih.h"
69
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT SCSI Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptscsih"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
80
81typedef struct _BIG_SENSE_BUF {
82 u8 data[MPT_SENSE_BUFFER_ALLOC];
83} BIG_SENSE_BUF;
84
85#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
86#define MPT_SCANDV_DID_RESET (0x00000001)
87#define MPT_SCANDV_SENSE (0x00000002)
88#define MPT_SCANDV_SOME_ERROR (0x00000004)
89#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
90#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
91#define MPT_SCANDV_FALLBACK (0x00000020)
92
93#define MPT_SCANDV_MAX_RETRIES (10)
94
95#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
96#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
Moore, Eric Dean466544d2005-09-14 18:09:10 -060097#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
98#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
99#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
101#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
102
103typedef struct _internal_cmd {
104 char *data; /* data pointer */
105 dma_addr_t data_dma; /* data dma address */
106 int size; /* transfer size */
107 u8 cmd; /* SCSI Op Code */
108 u8 bus; /* bus number */
109 u8 id; /* SCSI ID (virtual) */
110 u8 lun;
111 u8 flags; /* Bit Field - See above */
112 u8 physDiskNum; /* Phys disk number, -1 else */
113 u8 rsvd2;
114 u8 rsvd;
115} INTERNAL_CMD;
116
117typedef struct _negoparms {
118 u8 width;
119 u8 offset;
120 u8 factor;
121 u8 flags;
122} NEGOPARMS;
123
124typedef struct _dv_parameters {
125 NEGOPARMS max;
126 NEGOPARMS now;
127 u8 cmd;
128 u8 id;
129 u16 pad1;
130} DVPARAMETERS;
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/*
133 * Other private/forward protos...
134 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400135int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400137int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
140 SCSIIORequest_t *pReq, int req_idx);
141static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400142static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
144static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
145static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
146
147static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
148static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
149
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400150int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
151int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700153static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen);
154static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, char byte56);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700156static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
158static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400159int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700161static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
162static void mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget);
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700163static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600165static struct work_struct mptscsih_persistTask;
166
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
168static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
169static void mptscsih_domainValidation(void *hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
171static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
172static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
173static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600174static void mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700175static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400178void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700179void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400181int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
182int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#endif
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
186
187#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
188/*
189 * Domain Validation task structure
190 */
191static DEFINE_SPINLOCK(dvtaskQ_lock);
192static int dvtaskQ_active = 0;
193static int dvtaskQ_release = 0;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400194static struct work_struct dvTaskQ_task;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195#endif
196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
198/**
199 * mptscsih_add_sge - Place a simple SGE at address pAddr.
200 * @pAddr: virtual address for SGE
201 * @flagslength: SGE flags and data transfer length
202 * @dma_addr: Physical address
203 *
204 * This routine places a MPT request frame back on the MPT adapter's
205 * FreeQ.
206 */
207static inline void
208mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
209{
210 if (sizeof(dma_addr_t) == sizeof(u64)) {
211 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
212 u32 tmp = dma_addr & 0xFFFFFFFF;
213
214 pSge->FlagsLength = cpu_to_le32(flagslength);
215 pSge->Address.Low = cpu_to_le32(tmp);
216 tmp = (u32) ((u64)dma_addr >> 32);
217 pSge->Address.High = cpu_to_le32(tmp);
218
219 } else {
220 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
221 pSge->FlagsLength = cpu_to_le32(flagslength);
222 pSge->Address = cpu_to_le32(dma_addr);
223 }
224} /* mptscsih_add_sge() */
225
226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
227/**
228 * mptscsih_add_chain - Place a chain SGE at address pAddr.
229 * @pAddr: virtual address for SGE
230 * @next: nextChainOffset value (u32's)
231 * @length: length of next SGL segment
232 * @dma_addr: Physical address
233 *
234 * This routine places a MPT request frame back on the MPT adapter's
235 * FreeQ.
236 */
237static inline void
238mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
239{
240 if (sizeof(dma_addr_t) == sizeof(u64)) {
241 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
242 u32 tmp = dma_addr & 0xFFFFFFFF;
243
244 pChain->Length = cpu_to_le16(length);
245 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
246
247 pChain->NextChainOffset = next;
248
249 pChain->Address.Low = cpu_to_le32(tmp);
250 tmp = (u32) ((u64)dma_addr >> 32);
251 pChain->Address.High = cpu_to_le32(tmp);
252 } else {
253 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
254 pChain->Length = cpu_to_le16(length);
255 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
256 pChain->NextChainOffset = next;
257 pChain->Address = cpu_to_le32(dma_addr);
258 }
259} /* mptscsih_add_chain() */
260
261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
262/*
263 * mptscsih_getFreeChainBuffer - Function to get a free chain
264 * from the MPT_SCSI_HOST FreeChainQ.
265 * @ioc: Pointer to MPT_ADAPTER structure
266 * @req_idx: Index of the SCSI IO request frame. (output)
267 *
268 * return SUCCESS or FAILED
269 */
270static inline int
271mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
272{
273 MPT_FRAME_HDR *chainBuf;
274 unsigned long flags;
275 int rc;
276 int chain_idx;
277
278 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
279 ioc->name));
280 spin_lock_irqsave(&ioc->FreeQlock, flags);
281 if (!list_empty(&ioc->FreeChainQ)) {
282 int offset;
283
284 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
285 u.frame.linkage.list);
286 list_del(&chainBuf->u.frame.linkage.list);
287 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
288 chain_idx = offset / ioc->req_sz;
289 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200290 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
291 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 } else {
293 rc = FAILED;
294 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200295 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 ioc->name));
297 }
298 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
299
300 *retIndex = chain_idx;
301 return rc;
302} /* mptscsih_getFreeChainBuffer() */
303
304/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
305/*
306 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
307 * SCSIIORequest_t Message Frame.
308 * @ioc: Pointer to MPT_ADAPTER structure
309 * @SCpnt: Pointer to scsi_cmnd structure
310 * @pReq: Pointer to SCSIIORequest_t structure
311 *
312 * Returns ...
313 */
314static int
315mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
316 SCSIIORequest_t *pReq, int req_idx)
317{
318 char *psge;
319 char *chainSge;
320 struct scatterlist *sg;
321 int frm_sz;
322 int sges_left, sg_done;
323 int chain_idx = MPT_HOST_NO_CHAIN;
324 int sgeOffset;
325 int numSgeSlots, numSgeThisFrame;
326 u32 sgflags, sgdir, thisxfer = 0;
327 int chain_dma_off = 0;
328 int newIndex;
329 int ii;
330 dma_addr_t v2;
331 u32 RequestNB;
332
333 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
334 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
335 sgdir = MPT_TRANSFER_HOST_TO_IOC;
336 } else {
337 sgdir = MPT_TRANSFER_IOC_TO_HOST;
338 }
339
340 psge = (char *) &pReq->SGL;
341 frm_sz = ioc->req_sz;
342
343 /* Map the data portion, if any.
344 * sges_left = 0 if no data transfer.
345 */
346 if ( (sges_left = SCpnt->use_sg) ) {
347 sges_left = pci_map_sg(ioc->pcidev,
348 (struct scatterlist *) SCpnt->request_buffer,
349 SCpnt->use_sg,
350 SCpnt->sc_data_direction);
351 if (sges_left == 0)
352 return FAILED;
353 } else if (SCpnt->request_bufflen) {
354 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
355 SCpnt->request_buffer,
356 SCpnt->request_bufflen,
357 SCpnt->sc_data_direction);
358 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
359 ioc->name, SCpnt, SCpnt->request_bufflen));
360 mptscsih_add_sge((char *) &pReq->SGL,
361 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
362 SCpnt->SCp.dma_handle);
363
364 return SUCCESS;
365 }
366
367 /* Handle the SG case.
368 */
369 sg = (struct scatterlist *) SCpnt->request_buffer;
370 sg_done = 0;
371 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
372 chainSge = NULL;
373
374 /* Prior to entering this loop - the following must be set
375 * current MF: sgeOffset (bytes)
376 * chainSge (Null if original MF is not a chain buffer)
377 * sg_done (num SGE done for this MF)
378 */
379
380nextSGEset:
381 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
382 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
383
384 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
385
386 /* Get first (num - 1) SG elements
387 * Skip any SG entries with a length of 0
388 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
389 */
390 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
391 thisxfer = sg_dma_len(sg);
392 if (thisxfer == 0) {
393 sg ++; /* Get next SG element from the OS */
394 sg_done++;
395 continue;
396 }
397
398 v2 = sg_dma_address(sg);
399 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
400
401 sg++; /* Get next SG element from the OS */
402 psge += (sizeof(u32) + sizeof(dma_addr_t));
403 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
404 sg_done++;
405 }
406
407 if (numSgeThisFrame == sges_left) {
408 /* Add last element, end of buffer and end of list flags.
409 */
410 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
411 MPT_SGE_FLAGS_END_OF_BUFFER |
412 MPT_SGE_FLAGS_END_OF_LIST;
413
414 /* Add last SGE and set termination flags.
415 * Note: Last SGE may have a length of 0 - which should be ok.
416 */
417 thisxfer = sg_dma_len(sg);
418
419 v2 = sg_dma_address(sg);
420 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
421 /*
422 sg++;
423 psge += (sizeof(u32) + sizeof(dma_addr_t));
424 */
425 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
426 sg_done++;
427
428 if (chainSge) {
429 /* The current buffer is a chain buffer,
430 * but there is not another one.
431 * Update the chain element
432 * Offset and Length fields.
433 */
434 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
435 } else {
436 /* The current buffer is the original MF
437 * and there is no Chain buffer.
438 */
439 pReq->ChainOffset = 0;
440 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
443 ioc->RequestNB[req_idx] = RequestNB;
444 }
445 } else {
446 /* At least one chain buffer is needed.
447 * Complete the first MF
448 * - last SGE element, set the LastElement bit
449 * - set ChainOffset (words) for orig MF
450 * (OR finish previous MF chain buffer)
451 * - update MFStructPtr ChainIndex
452 * - Populate chain element
453 * Also
454 * Loop until done.
455 */
456
457 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
458 ioc->name, sg_done));
459
460 /* Set LAST_ELEMENT flag for last non-chain element
461 * in the buffer. Since psge points at the NEXT
462 * SGE element, go back one SGE element, update the flags
463 * and reset the pointer. (Note: sgflags & thisxfer are already
464 * set properly).
465 */
466 if (sg_done) {
467 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
468 sgflags = le32_to_cpu(*ptmp);
469 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
470 *ptmp = cpu_to_le32(sgflags);
471 }
472
473 if (chainSge) {
474 /* The current buffer is a chain buffer.
475 * chainSge points to the previous Chain Element.
476 * Update its chain element Offset and Length (must
477 * include chain element size) fields.
478 * Old chain element is now complete.
479 */
480 u8 nextChain = (u8) (sgeOffset >> 2);
481 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
482 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
483 } else {
484 /* The original MF buffer requires a chain buffer -
485 * set the offset.
486 * Last element in this MF is a chain element.
487 */
488 pReq->ChainOffset = (u8) (sgeOffset >> 2);
489 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
490 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
491 ioc->RequestNB[req_idx] = RequestNB;
492 }
493
494 sges_left -= sg_done;
495
496
497 /* NOTE: psge points to the beginning of the chain element
498 * in current buffer. Get a chain buffer.
499 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200500 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
501 dfailprintk((MYIOC_s_INFO_FMT
502 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
503 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 /* Update the tracking arrays.
508 * If chainSge == NULL, update ReqToChain, else ChainToChain
509 */
510 if (chainSge) {
511 ioc->ChainToChain[chain_idx] = newIndex;
512 } else {
513 ioc->ReqToChain[req_idx] = newIndex;
514 }
515 chain_idx = newIndex;
516 chain_dma_off = ioc->req_sz * chain_idx;
517
518 /* Populate the chainSGE for the current buffer.
519 * - Set chain buffer pointer to psge and fill
520 * out the Address and Flags fields.
521 */
522 chainSge = (char *) psge;
523 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
524 psge, req_idx));
525
526 /* Start the SGE for the next buffer
527 */
528 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
529 sgeOffset = 0;
530 sg_done = 0;
531
532 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
533 psge, chain_idx));
534
535 /* Start the SGE for the next buffer
536 */
537
538 goto nextSGEset;
539 }
540
541 return SUCCESS;
542} /* mptscsih_AddSGE() */
543
544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
545/*
546 * mptscsih_io_done - Main SCSI IO callback routine registered to
547 * Fusion MPT (base) driver
548 * @ioc: Pointer to MPT_ADAPTER structure
549 * @mf: Pointer to original MPT request frame
550 * @r: Pointer to MPT reply frame (NULL if TurboReply)
551 *
552 * This routine is called from mpt.c::mpt_interrupt() at the completion
553 * of any SCSI IO request.
554 * This routine is registered with the Fusion MPT (base) driver at driver
555 * load/init time via the mpt_register() API call.
556 *
557 * Returns 1 indicating alloc'd request frame ptr should be freed.
558 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400559int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
561{
562 struct scsi_cmnd *sc;
563 MPT_SCSI_HOST *hd;
564 SCSIIORequest_t *pScsiReq;
565 SCSIIOReply_t *pScsiReply;
566 u16 req_idx;
567
568 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
569
570 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
571 sc = hd->ScsiLookup[req_idx];
572 if (sc == NULL) {
573 MPIHeader_t *hdr = (MPIHeader_t *)mf;
574
575 /* Remark: writeSDP1 will use the ScsiDoneCtx
576 * If a SCSI I/O cmd, device disabled by OS and
577 * completion done. Cannot touch sc struct. Just free mem.
578 */
579 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
580 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
581 ioc->name);
582
583 mptscsih_freeChainBuffers(ioc, req_idx);
584 return 1;
585 }
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 sc->result = DID_OK << 16; /* Set default reply as OK */
588 pScsiReq = (SCSIIORequest_t *) mf;
589 pScsiReply = (SCSIIOReply_t *) mr;
590
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200591 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
592 dmfprintk((MYIOC_s_INFO_FMT
593 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
594 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
595 }else{
596 dmfprintk((MYIOC_s_INFO_FMT
597 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
598 ioc->name, mf, mr, sc, req_idx));
599 }
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 if (pScsiReply == NULL) {
602 /* special context reply handling */
603 ;
604 } else {
605 u32 xfer_cnt;
606 u16 status;
607 u8 scsi_state, scsi_status;
608
609 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
610 scsi_state = pScsiReply->SCSIState;
611 scsi_status = pScsiReply->SCSIStatus;
612 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
613 sc->resid = sc->request_bufflen - xfer_cnt;
614
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600615 /*
616 * if we get a data underrun indication, yet no data was
617 * transferred and the SCSI status indicates that the
618 * command was never started, change the data underrun
619 * to success
620 */
621 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
622 (scsi_status == MPI_SCSI_STATUS_BUSY ||
623 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
624 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
625 status = MPI_IOCSTATUS_SUCCESS;
626 }
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
629 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
630 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700631 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600632 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 sc->request_bufflen, xfer_cnt));
634
635 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400636 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /*
639 * Look for + dump FCP ResponseInfo[]!
640 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600641 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
642 pScsiReply->ResponseInfo) {
643 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
644 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700645 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 le32_to_cpu(pScsiReply->ResponseInfo));
647 }
648
649 switch(status) {
650 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
651 /* CHECKME!
652 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
653 * But not: DID_BUS_BUSY lest one risk
654 * killing interrupt handler:-(
655 */
656 sc->result = SAM_STAT_BUSY;
657 break;
658
659 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
660 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
661 sc->result = DID_BAD_TARGET << 16;
662 break;
663
664 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
665 /* Spoof to SCSI Selection Timeout! */
666 sc->result = DID_NO_CONNECT << 16;
667
668 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
669 hd->sel_timeout[pScsiReq->TargetID]++;
670 break;
671
672 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
673 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
674 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
675 /* Linux handles an unsolicited DID_RESET better
676 * than an unsolicited DID_ABORT.
677 */
678 sc->result = DID_RESET << 16;
679
680 /* GEM Workaround. */
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700681 if (ioc->bus_type == SPI)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700682 mptscsih_no_negotiate(hd, sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 break;
684
685 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600686 sc->resid = sc->request_bufflen - xfer_cnt;
687 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
688 sc->result=DID_SOFT_ERROR << 16;
689 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 sc->result = (DID_OK << 16) | scsi_status;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600691 dreplyprintk((KERN_NOTICE
692 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400694
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
696 /*
697 * Do upfront check for valid SenseData and give it
698 * precedence!
699 */
700 sc->result = (DID_OK << 16) | scsi_status;
701 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
702 /* Have already saved the status and sense data
703 */
704 ;
705 } else {
706 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600707 if (scsi_status == SAM_STAT_BUSY)
708 sc->result = SAM_STAT_BUSY;
709 else
710 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 }
712 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
713 /* What to do?
714 */
715 sc->result = DID_SOFT_ERROR << 16;
716 }
717 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
718 /* Not real sure here either... */
719 sc->result = DID_RESET << 16;
720 }
721 }
722
723 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
724 sc->underflow));
725 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
726 /* Report Queue Full
727 */
728 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
729 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 break;
732
733 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
734 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600735 if (scsi_status == MPI_SCSI_STATUS_BUSY)
736 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
737 else
738 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if (scsi_state == 0) {
740 ;
741 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
742 /*
743 * If running against circa 200003dd 909 MPT f/w,
744 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
745 * (QUEUE_FULL) returned from device! --> get 0x0000?128
746 * and with SenseBytes set to 0.
747 */
748 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
749 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
750
751 }
752 else if (scsi_state &
753 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
754 ) {
755 /*
756 * What to do?
757 */
758 sc->result = DID_SOFT_ERROR << 16;
759 }
760 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
761 /* Not real sure here either... */
762 sc->result = DID_RESET << 16;
763 }
764 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
765 /* Device Inq. data indicates that it supports
766 * QTags, but rejects QTag messages.
767 * This command completed OK.
768 *
769 * Not real sure here either so do nothing... */
770 }
771
772 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
773 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
774
775 /* Add handling of:
776 * Reservation Conflict, Busy,
777 * Command Terminated, CHECK
778 */
779 break;
780
781 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
782 sc->result = DID_SOFT_ERROR << 16;
783 break;
784
785 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
786 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
787 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
788 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
789 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
790 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
791 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
792 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
793 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
794 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
795 default:
796 /*
797 * What to do?
798 */
799 sc->result = DID_SOFT_ERROR << 16;
800 break;
801
802 } /* switch(status) */
803
804 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
805 } /* end of address reply case */
806
807 /* Unmap the DMA buffers, if any. */
808 if (sc->use_sg) {
809 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
810 sc->use_sg, sc->sc_data_direction);
811 } else if (sc->request_bufflen) {
812 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
813 sc->request_bufflen, sc->sc_data_direction);
814 }
815
816 hd->ScsiLookup[req_idx] = NULL;
817
818 sc->scsi_done(sc); /* Issue the command callback */
819
820 /* Free Chain buffers */
821 mptscsih_freeChainBuffers(ioc, req_idx);
822 return 1;
823}
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825/*
826 * mptscsih_flush_running_cmds - For each command found, search
827 * Scsi_Host instance taskQ and reply to OS.
828 * Called only if recovering from a FW reload.
829 * @hd: Pointer to a SCSI HOST structure
830 *
831 * Returns: None.
832 *
833 * Must be called while new I/Os are being queued.
834 */
835static void
836mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
837{
838 MPT_ADAPTER *ioc = hd->ioc;
839 struct scsi_cmnd *SCpnt;
840 MPT_FRAME_HDR *mf;
841 int ii;
842 int max = ioc->req_depth;
843
844 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
845 for (ii= 0; ii < max; ii++) {
846 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
847
848 /* Command found.
849 */
850
851 /* Null ScsiLookup index
852 */
853 hd->ScsiLookup[ii] = NULL;
854
855 mf = MPT_INDEX_2_MFPTR(ioc, ii);
856 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
857 mf, SCpnt));
858
859 /* Set status, free OS resources (SG DMA buffers)
860 * Do OS callback
861 * Free driver resources (chain, msg buffers)
862 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400863 if (SCpnt->use_sg) {
864 pci_unmap_sg(ioc->pcidev,
865 (struct scatterlist *) SCpnt->request_buffer,
866 SCpnt->use_sg,
867 SCpnt->sc_data_direction);
868 } else if (SCpnt->request_bufflen) {
869 pci_unmap_single(ioc->pcidev,
870 SCpnt->SCp.dma_handle,
871 SCpnt->request_bufflen,
872 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
874 SCpnt->result = DID_RESET << 16;
875 SCpnt->host_scribble = NULL;
876
877 /* Free Chain buffers */
878 mptscsih_freeChainBuffers(ioc, ii);
879
880 /* Free Message frames */
881 mpt_free_msg_frame(ioc, mf);
882
883 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
884 }
885 }
886
887 return;
888}
889
890/*
891 * mptscsih_search_running_cmds - Delete any commands associated
892 * with the specified target and lun. Function called only
893 * when a lun is disable by mid-layer.
894 * Do NOT access the referenced scsi_cmnd structure or
895 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600896 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700897 * @hd: Pointer to a SCSI HOST structure
898 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 *
900 * Returns: None.
901 *
902 * Called from slave_destroy.
903 */
904static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700905mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 SCSIIORequest_t *mf = NULL;
908 int ii;
909 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600910 struct scsi_cmnd *sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700913 vdevice->target_id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600916 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
919
920 dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
921 hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
922
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700923 if ((mf->TargetID != ((u8)vdevice->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 continue;
925
926 /* Cleanup
927 */
928 hd->ScsiLookup[ii] = NULL;
929 mptscsih_freeChainBuffers(hd->ioc, ii);
930 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600931 if (sc->use_sg) {
932 pci_unmap_sg(hd->ioc->pcidev,
933 (struct scatterlist *) sc->request_buffer,
934 sc->use_sg,
935 sc->sc_data_direction);
936 } else if (sc->request_bufflen) {
937 pci_unmap_single(hd->ioc->pcidev,
938 sc->SCp.dma_handle,
939 sc->request_bufflen,
940 sc->sc_data_direction);
941 }
942 sc->host_scribble = NULL;
943 sc->result = DID_NO_CONNECT << 16;
944 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 return;
948}
949
950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
953/*
954 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
955 * from a SCSI target device.
956 * @sc: Pointer to scsi_cmnd structure
957 * @pScsiReply: Pointer to SCSIIOReply_t
958 * @pScsiReq: Pointer to original SCSI request
959 *
960 * This routine periodically reports QUEUE_FULL status returned from a
961 * SCSI target device. It reports this to the console via kernel
962 * printk() API call, not more than once every 10 seconds.
963 */
964static void
965mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
966{
967 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400970 if (sc->device == NULL)
971 return;
972 if (sc->device->host == NULL)
973 return;
974 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
975 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400977 if (time - hd->last_queue_full > 10 * HZ) {
978 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
979 hd->ioc->name, 0, sc->device->id, sc->device->lun));
980 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982}
983
984/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
985/*
986 * mptscsih_remove - Removed scsi devices
987 * @pdev: Pointer to pci_dev structure
988 *
989 *
990 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400991void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992mptscsih_remove(struct pci_dev *pdev)
993{
994 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
995 struct Scsi_Host *host = ioc->sh;
996 MPT_SCSI_HOST *hd;
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -0700997#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 int count;
999 unsigned long flags;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001000#endif
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001001 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001003 if(!host) {
1004 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 scsi_remove_host(host);
1009
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001010 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1011 return;
1012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1014 /* Check DV thread active */
1015 count = 10 * HZ;
1016 spin_lock_irqsave(&dvtaskQ_lock, flags);
1017 if (dvtaskQ_active) {
1018 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
Nishanth Aravamudan65210182005-11-07 01:01:19 -08001019 while(dvtaskQ_active && --count)
1020 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 } else {
1022 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
1023 }
1024 if (!count)
1025 printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
1026#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
1027 else
1028 printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
1029#endif
1030#endif
1031
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001032 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001036 if (hd->ScsiLookup != NULL) {
1037 sz1 = hd->ioc->req_depth * sizeof(void *);
1038 kfree(hd->ScsiLookup);
1039 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 }
1041
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001042 /*
1043 * Free pointer array.
1044 */
1045 kfree(hd->Targets);
1046 hd->Targets = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001048 dprintk((MYIOC_s_INFO_FMT
1049 "Free'd ScsiLookup (%d) memory\n",
1050 hd->ioc->name, sz1));
1051
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001052 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001053
1054 /* NULL the Scsi_Host pointer
1055 */
1056 hd->ioc->sh = NULL;
1057
1058 scsi_host_put(host);
1059
1060 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/*
1066 * mptscsih_shutdown - reboot notifier
1067 *
1068 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001069void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001070mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001072 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 struct Scsi_Host *host = ioc->sh;
1074 MPT_SCSI_HOST *hd;
1075
1076 if(!host)
1077 return;
1078
1079 hd = (MPT_SCSI_HOST *)host->hostdata;
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081}
1082
1083#ifdef CONFIG_PM
1084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1085/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001086 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 *
1088 *
1089 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001090int
Pavel Machek8d189f72005-04-16 15:25:28 -07001091mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001093 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001094 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
1097/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1098/*
1099 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1100 *
1101 *
1102 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001103int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104mptscsih_resume(struct pci_dev *pdev)
1105{
1106 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1107 struct Scsi_Host *host = ioc->sh;
1108 MPT_SCSI_HOST *hd;
1109
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001110 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if(!host)
1113 return 0;
1114
1115 hd = (MPT_SCSI_HOST *)host->hostdata;
1116 if(!hd)
1117 return 0;
1118
1119#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
1120 {
1121 unsigned long lflags;
1122 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1123 if (!dvtaskQ_active) {
1124 dvtaskQ_active = 1;
1125 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001126 INIT_WORK(&dvTaskQ_task,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 mptscsih_domainValidation, (void *) hd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 } else {
1130 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1131 }
1132 }
1133#endif
1134 return 0;
1135}
1136
1137#endif
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1140/**
1141 * mptscsih_info - Return information about MPT adapter
1142 * @SChost: Pointer to Scsi_Host structure
1143 *
1144 * (linux scsi_host_template.info routine)
1145 *
1146 * Returns pointer to buffer where information was written.
1147 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001148const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149mptscsih_info(struct Scsi_Host *SChost)
1150{
1151 MPT_SCSI_HOST *h;
1152 int size = 0;
1153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001157 if (h->info_kbuf == NULL)
1158 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1159 return h->info_kbuf;
1160 h->info_kbuf[0] = '\0';
1161
1162 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1163 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
1165
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001166 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167}
1168
1169struct info_str {
1170 char *buffer;
1171 int length;
1172 int offset;
1173 int pos;
1174};
1175
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001176static void
1177mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178{
1179 if (info->pos + len > info->length)
1180 len = info->length - info->pos;
1181
1182 if (info->pos + len < info->offset) {
1183 info->pos += len;
1184 return;
1185 }
1186
1187 if (info->pos < info->offset) {
1188 data += (info->offset - info->pos);
1189 len -= (info->offset - info->pos);
1190 }
1191
1192 if (len > 0) {
1193 memcpy(info->buffer + info->pos, data, len);
1194 info->pos += len;
1195 }
1196}
1197
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001198static int
1199mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
1201 va_list args;
1202 char buf[81];
1203 int len;
1204
1205 va_start(args, fmt);
1206 len = vsprintf(buf, fmt, args);
1207 va_end(args);
1208
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001209 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 return len;
1211}
1212
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001213static int
1214mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
1216 struct info_str info;
1217
1218 info.buffer = pbuf;
1219 info.length = len;
1220 info.offset = offset;
1221 info.pos = 0;
1222
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001223 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1224 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1225 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1226 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1229}
1230
1231/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1232/**
1233 * mptscsih_proc_info - Return information about MPT adapter
1234 *
1235 * (linux scsi_host_template.info routine)
1236 *
1237 * buffer: if write, user data; if read, buffer for user
1238 * length: if write, return length;
1239 * offset: if write, 0; if read, the current offset into the buffer from
1240 * the previous read.
1241 * hostno: scsi host number
1242 * func: if write = 1; if read = 0
1243 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001244int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1246 int length, int func)
1247{
1248 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1249 MPT_ADAPTER *ioc = hd->ioc;
1250 int size = 0;
1251
1252 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001253 /*
1254 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 */
1256 } else {
1257 if (start)
1258 *start = buffer;
1259
1260 size = mptscsih_host_info(ioc, buffer, offset, length);
1261 }
1262
1263 return size;
1264}
1265
1266/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1267#define ADD_INDEX_LOG(req_ent) do { } while(0)
1268
1269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1270/**
1271 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1272 * @SCpnt: Pointer to scsi_cmnd structure
1273 * @done: Pointer SCSI mid-layer IO completion function
1274 *
1275 * (linux scsi_host_template.queuecommand routine)
1276 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1277 * from a linux scsi_cmnd request and send it to the IOC.
1278 *
1279 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1280 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001281int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1283{
1284 MPT_SCSI_HOST *hd;
1285 MPT_FRAME_HDR *mf;
1286 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001287 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 int lun;
1289 u32 datalen;
1290 u32 scsictl;
1291 u32 scsidir;
1292 u32 cmd_len;
1293 int my_idx;
1294 int ii;
1295
1296 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 lun = SCpnt->device->lun;
1298 SCpnt->scsi_done = done;
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1301 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1302
1303 if (hd->resetPending) {
1304 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1305 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1306 return SCSI_MLQUEUE_HOST_BUSY;
1307 }
1308
1309 /*
1310 * Put together a MPT SCSI request...
1311 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001312 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1314 hd->ioc->name));
1315 return SCSI_MLQUEUE_HOST_BUSY;
1316 }
1317
1318 pScsiReq = (SCSIIORequest_t *) mf;
1319
1320 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1321
1322 ADD_INDEX_LOG(my_idx);
1323
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001324 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 * Seems we may receive a buffer (datalen>0) even when there
1326 * will be no data transfer! GRRRRR...
1327 */
1328 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1329 datalen = SCpnt->request_bufflen;
1330 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1331 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1332 datalen = SCpnt->request_bufflen;
1333 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1334 } else {
1335 datalen = 0;
1336 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1337 }
1338
1339 /* Default to untagged. Once a target structure has been allocated,
1340 * use the Inquiry data to determine if device supports tagged.
1341 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001342 if (vdev
1343 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 && (SCpnt->device->tagged_supported)) {
1345 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1346 } else {
1347 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1348 }
1349
1350 /* Use the above information to set up the message frame
1351 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001352 pScsiReq->TargetID = (u8) vdev->target_id;
1353 pScsiReq->Bus = vdev->bus_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pScsiReq->ChainOffset = 0;
1355 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1356 pScsiReq->CDBLength = SCpnt->cmd_len;
1357 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1358 pScsiReq->Reserved = 0;
1359 pScsiReq->MsgFlags = mpt_msg_flags();
1360 pScsiReq->LUN[0] = 0;
1361 pScsiReq->LUN[1] = lun;
1362 pScsiReq->LUN[2] = 0;
1363 pScsiReq->LUN[3] = 0;
1364 pScsiReq->LUN[4] = 0;
1365 pScsiReq->LUN[5] = 0;
1366 pScsiReq->LUN[6] = 0;
1367 pScsiReq->LUN[7] = 0;
1368 pScsiReq->Control = cpu_to_le32(scsictl);
1369
1370 /*
1371 * Write SCSI CDB into the message
1372 */
1373 cmd_len = SCpnt->cmd_len;
1374 for (ii=0; ii < cmd_len; ii++)
1375 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1376
1377 for (ii=cmd_len; ii < 16; ii++)
1378 pScsiReq->CDB[ii] = 0;
1379
1380 /* DataLength */
1381 pScsiReq->DataLength = cpu_to_le32(datalen);
1382
1383 /* SenseBuffer low address */
1384 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1385 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1386
1387 /* Now add the SG list
1388 * Always have a SGE even if null length.
1389 */
1390 if (datalen == 0) {
1391 /* Add a NULL SGE */
1392 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1393 (dma_addr_t) -1);
1394 } else {
1395 /* Add a 32 or 64 bit SGE */
1396 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1397 goto fail;
1398 }
1399
1400 hd->ScsiLookup[my_idx] = SCpnt;
1401 SCpnt->host_scribble = NULL;
1402
1403#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001404 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001405 int dvStatus = hd->ioc->spi_data.dvStatus[vdev->target_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 int issueCmd = 1;
1407
1408 if (dvStatus || hd->ioc->spi_data.forceDv) {
1409
1410 if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
1411 (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
1412 unsigned long lflags;
1413 /* Schedule DV if necessary */
1414 spin_lock_irqsave(&dvtaskQ_lock, lflags);
1415 if (!dvtaskQ_active) {
1416 dvtaskQ_active = 1;
1417 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001418 INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001420 schedule_work(&dvTaskQ_task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 } else {
1422 spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
1423 }
1424 hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
1425 }
1426
1427 /* Trying to do DV to this target, extend timeout.
1428 * Wait to issue until flag is clear
1429 */
1430 if (dvStatus & MPT_SCSICFG_DV_PENDING) {
1431 mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
1432 issueCmd = 0;
1433 }
1434
1435 /* Set the DV flags.
1436 */
1437 if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001438 mptscsih_set_dvflags(hd, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440 if (!issueCmd)
1441 goto fail;
1442 }
1443 }
1444#endif
1445
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001446 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1448 hd->ioc->name, SCpnt, mf, my_idx));
1449 DBG_DUMP_REQUEST_FRAME(mf)
1450 return 0;
1451
1452 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001453 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1455 mpt_free_msg_frame(hd->ioc, mf);
1456 return SCSI_MLQUEUE_HOST_BUSY;
1457}
1458
1459/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1460/*
1461 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1462 * with a SCSI IO request
1463 * @hd: Pointer to the MPT_SCSI_HOST instance
1464 * @req_idx: Index of the SCSI IO request frame.
1465 *
1466 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1467 * No return.
1468 */
1469static void
1470mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1471{
1472 MPT_FRAME_HDR *chain;
1473 unsigned long flags;
1474 int chain_idx;
1475 int next;
1476
1477 /* Get the first chain index and reset
1478 * tracker state.
1479 */
1480 chain_idx = ioc->ReqToChain[req_idx];
1481 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1482
1483 while (chain_idx != MPT_HOST_NO_CHAIN) {
1484
1485 /* Save the next chain buffer index */
1486 next = ioc->ChainToChain[chain_idx];
1487
1488 /* Free this chain buffer and reset
1489 * tracker
1490 */
1491 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1492
1493 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1494 + (chain_idx * ioc->req_sz));
1495
1496 spin_lock_irqsave(&ioc->FreeQlock, flags);
1497 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1498 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1499
1500 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1501 ioc->name, chain_idx));
1502
1503 /* handle next */
1504 chain_idx = next;
1505 }
1506 return;
1507}
1508
1509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1510/*
1511 * Reset Handling
1512 */
1513
1514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1515/*
1516 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1517 * Fall through to mpt_HardResetHandler if: not operational, too many
1518 * failed TM requests or handshake failure.
1519 *
1520 * @ioc: Pointer to MPT_ADAPTER structure
1521 * @type: Task Management type
1522 * @target: Logical Target ID for reset (if appropriate)
1523 * @lun: Logical Unit for reset (if appropriate)
1524 * @ctx2abort: Context for the task to be aborted (if appropriate)
1525 *
1526 * Remark: Currently invoked from a non-interrupt thread (_bh).
1527 *
1528 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1529 * will be active.
1530 *
1531 * Returns 0 for SUCCESS or -1 if FAILED.
1532 */
1533static int
1534mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1535{
1536 MPT_ADAPTER *ioc;
1537 int rc = -1;
1538 int doTask = 1;
1539 u32 ioc_raw_state;
1540 unsigned long flags;
1541
1542 /* If FW is being reloaded currently, return success to
1543 * the calling function.
1544 */
1545 if (hd == NULL)
1546 return 0;
1547
1548 ioc = hd->ioc;
1549 if (ioc == NULL) {
1550 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1551 return FAILED;
1552 }
1553 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1554
1555 // SJR - CHECKME - Can we avoid this here?
1556 // (mpt_HardResetHandler has this check...)
1557 spin_lock_irqsave(&ioc->diagLock, flags);
1558 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1559 spin_unlock_irqrestore(&ioc->diagLock, flags);
1560 return FAILED;
1561 }
1562 spin_unlock_irqrestore(&ioc->diagLock, flags);
1563
1564 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1565 * If we time out and not bus reset, then we return a FAILED status to the caller.
1566 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1567 * successful. Otherwise, reload the FW.
1568 */
1569 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1570 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001571 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 "Timed out waiting for last TM (%d) to complete! \n",
1573 hd->ioc->name, hd->tmPending));
1574 return FAILED;
1575 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001576 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 "Timed out waiting for last TM (%d) to complete! \n",
1578 hd->ioc->name, hd->tmPending));
1579 return FAILED;
1580 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001581 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 "Timed out waiting for last TM (%d) to complete! \n",
1583 hd->ioc->name, hd->tmPending));
1584 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1585 return FAILED;
1586
1587 doTask = 0;
1588 }
1589 } else {
1590 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1591 hd->tmPending |= (1 << type);
1592 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1593 }
1594
1595 /* Is operational?
1596 */
1597 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1598
1599#ifdef MPT_DEBUG_RESET
1600 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1601 printk(MYIOC_s_WARN_FMT
1602 "TM Handler: IOC Not operational(0x%x)!\n",
1603 hd->ioc->name, ioc_raw_state);
1604 }
1605#endif
1606
1607 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1608 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1609
1610 /* Isse the Task Mgmt request.
1611 */
1612 if (hd->hard_resets < -1)
1613 hd->hard_resets++;
1614 rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
1615 if (rc) {
1616 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1617 } else {
1618 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1619 }
1620 }
1621
1622 /* Only fall through to the HRH if this is a bus reset
1623 */
1624 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1625 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1626 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1627 hd->ioc->name));
1628 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1629 }
1630
1631 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1632
1633 return rc;
1634}
1635
1636
1637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1638/*
1639 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1640 * @hd: Pointer to MPT_SCSI_HOST structure
1641 * @type: Task Management type
1642 * @target: Logical Target ID for reset (if appropriate)
1643 * @lun: Logical Unit for reset (if appropriate)
1644 * @ctx2abort: Context for the task to be aborted (if appropriate)
1645 *
1646 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1647 * or a non-interrupt thread. In the former, must not call schedule().
1648 *
1649 * Not all fields are meaningfull for all task types.
1650 *
1651 * Returns 0 for SUCCESS, -999 for "no msg frames",
1652 * else other non-zero value returned.
1653 */
1654static int
1655mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
1656{
1657 MPT_FRAME_HDR *mf;
1658 SCSITaskMgmt_t *pScsiTm;
1659 int ii;
1660 int retval;
1661
1662 /* Return Fail to calling function if no message frames available.
1663 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001664 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1666 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001667 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 }
1669 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1670 hd->ioc->name, mf));
1671
1672 /* Format the Request
1673 */
1674 pScsiTm = (SCSITaskMgmt_t *) mf;
1675 pScsiTm->TargetID = target;
1676 pScsiTm->Bus = channel;
1677 pScsiTm->ChainOffset = 0;
1678 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1679
1680 pScsiTm->Reserved = 0;
1681 pScsiTm->TaskType = type;
1682 pScsiTm->Reserved1 = 0;
1683 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1684 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1685
1686 for (ii= 0; ii < 8; ii++) {
1687 pScsiTm->LUN[ii] = 0;
1688 }
1689 pScsiTm->LUN[1] = lun;
1690
1691 for (ii=0; ii < 7; ii++)
1692 pScsiTm->Reserved2[ii] = 0;
1693
1694 pScsiTm->TaskMsgContext = ctx2abort;
1695
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001696 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1697 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1700
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001701 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1703 CAN_SLEEP)) != 0) {
1704 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1705 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1706 hd->ioc, mf));
1707 mpt_free_msg_frame(hd->ioc, mf);
1708 return retval;
1709 }
1710
1711 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1712 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1713 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1714 hd->ioc, mf));
1715 mpt_free_msg_frame(hd->ioc, mf);
1716 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1717 hd->ioc->name));
1718 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1719 }
1720
1721 return retval;
1722}
1723
1724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1725/**
1726 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1727 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1728 *
1729 * (linux scsi_host_template.eh_abort_handler routine)
1730 *
1731 * Returns SUCCESS or FAILED.
1732 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001733int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734mptscsih_abort(struct scsi_cmnd * SCpnt)
1735{
1736 MPT_SCSI_HOST *hd;
1737 MPT_ADAPTER *ioc;
1738 MPT_FRAME_HDR *mf;
1739 u32 ctx2abort;
1740 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001741 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001742 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
1744 /* If we can't locate our host adapter structure, return FAILED status.
1745 */
1746 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1747 SCpnt->result = DID_RESET << 16;
1748 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001749 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 "Can't locate host! (sc=%p)\n",
1751 SCpnt));
1752 return FAILED;
1753 }
1754
1755 ioc = hd->ioc;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001756 if (hd->resetPending) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return FAILED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 if (hd->timeouts < -1)
1761 hd->timeouts++;
1762
1763 /* Find this command
1764 */
1765 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001766 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 * Do OS callback.
1768 */
1769 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001770 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 "Command not in the active list! (sc=%p)\n",
1772 hd->ioc->name, SCpnt));
1773 return SUCCESS;
1774 }
1775
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001776 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1777 hd->ioc->name, SCpnt);
1778 scsi_print_command(SCpnt);
1779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1781 * (the IO to be ABORT'd)
1782 *
1783 * NOTE: Since we do not byteswap MsgContext, we do not
1784 * swap it here either. It is an opaque cookie to
1785 * the controller, so it does not matter. -DaveM
1786 */
1787 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1788 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1789
1790 hd->abortSCpnt = SCpnt;
1791
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001792 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001793 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001794 vdev->bus_id, vdev->target_id, vdev->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001795 ctx2abort, 2 /* 2 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001797 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1798 hd->ioc->name,
1799 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001801 if (retval == 0)
1802 return SUCCESS;
1803
1804 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 hd->tmPending = 0;
1806 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001808 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809}
1810
1811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1812/**
1813 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1814 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1815 *
1816 * (linux scsi_host_template.eh_dev_reset_handler routine)
1817 *
1818 * Returns SUCCESS or FAILED.
1819 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001820int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1822{
1823 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001824 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001825 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
1827 /* If we can't locate our host adapter structure, return FAILED status.
1828 */
1829 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001830 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 "Can't locate host! (sc=%p)\n",
1832 SCpnt));
1833 return FAILED;
1834 }
1835
1836 if (hd->resetPending)
1837 return FAILED;
1838
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001839 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001841 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001843 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001844 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001845 vdev->bus_id, vdev->target_id,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001846 0, 0, 5 /* 5 second timeout */);
1847
1848 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1849 hd->ioc->name,
1850 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1851
1852 if (retval == 0)
1853 return SUCCESS;
1854
1855 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 hd->tmPending = 0;
1857 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001859 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860}
1861
1862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1863/**
1864 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1865 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1866 *
1867 * (linux scsi_host_template.eh_bus_reset_handler routine)
1868 *
1869 * Returns SUCCESS or FAILED.
1870 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001871int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1873{
1874 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001875 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001876 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
1878 /* If we can't locate our host adapter structure, return FAILED status.
1879 */
1880 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001881 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 "Can't locate host! (sc=%p)\n",
1883 SCpnt ) );
1884 return FAILED;
1885 }
1886
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001887 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001889 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 if (hd->timeouts < -1)
1892 hd->timeouts++;
1893
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001894 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001895 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001896 vdev->bus_id, 0, 0, 0, 5 /* 5 second timeout */);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001898 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1899 hd->ioc->name,
1900 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1901
1902 if (retval == 0)
1903 return SUCCESS;
1904
1905 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 hd->tmPending = 0;
1907 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001909 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910}
1911
1912/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1913/**
1914 * mptscsih_host_reset - Perform a SCSI host adapter RESET!
1915 * new_eh variant
1916 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1917 *
1918 * (linux scsi_host_template.eh_host_reset_handler routine)
1919 *
1920 * Returns SUCCESS or FAILED.
1921 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001922int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1924{
1925 MPT_SCSI_HOST * hd;
1926 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
1928 /* If we can't locate the host to reset, then we failed. */
1929 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001930 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 "Can't locate host! (sc=%p)\n",
1932 SCpnt ) );
1933 return FAILED;
1934 }
1935
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001936 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 hd->ioc->name, SCpnt);
1938
1939 /* If our attempts to reset the host failed, then return a failed
1940 * status. The host will be taken off line by the SCSI mid-layer.
1941 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1943 status = FAILED;
1944 } else {
1945 /* Make sure TM pending is cleared and TM state is set to
1946 * NONE.
1947 */
1948 hd->tmPending = 0;
1949 hd->tmState = TM_STATE_NONE;
1950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001952 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 "Status = %s\n",
1954 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1955
1956 return status;
1957}
1958
1959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1960/**
1961 * mptscsih_tm_pending_wait - wait for pending task management request to
1962 * complete.
1963 * @hd: Pointer to MPT host structure.
1964 *
1965 * Returns {SUCCESS,FAILED}.
1966 */
1967static int
1968mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1969{
1970 unsigned long flags;
1971 int loop_count = 4 * 10; /* Wait 10 seconds */
1972 int status = FAILED;
1973
1974 do {
1975 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1976 if (hd->tmState == TM_STATE_NONE) {
1977 hd->tmState = TM_STATE_IN_PROGRESS;
1978 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001980 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 break;
1982 }
1983 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1984 msleep(250);
1985 } while (--loop_count);
1986
1987 return status;
1988}
1989
1990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1991/**
1992 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1993 * @hd: Pointer to MPT host structure.
1994 *
1995 * Returns {SUCCESS,FAILED}.
1996 */
1997static int
1998mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1999{
2000 unsigned long flags;
2001 int loop_count = 4 * timeout;
2002 int status = FAILED;
2003
2004 do {
2005 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2006 if(hd->tmPending == 0) {
2007 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002008 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 break;
2010 }
2011 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2012 msleep_interruptible(250);
2013 } while (--loop_count);
2014
2015 return status;
2016}
2017
2018/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2019/**
2020 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2021 * @ioc: Pointer to MPT_ADAPTER structure
2022 * @mf: Pointer to SCSI task mgmt request frame
2023 * @mr: Pointer to SCSI task mgmt reply frame
2024 *
2025 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2026 * of any SCSI task management request.
2027 * This routine is registered with the MPT (base) driver at driver
2028 * load/init time via the mpt_register() API call.
2029 *
2030 * Returns 1 indicating alloc'd request frame ptr should be freed.
2031 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002032int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2034{
2035 SCSITaskMgmtReply_t *pScsiTmReply;
2036 SCSITaskMgmt_t *pScsiTmReq;
2037 MPT_SCSI_HOST *hd;
2038 unsigned long flags;
2039 u16 iocstatus;
2040 u8 tmType;
2041
2042 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2043 ioc->name, mf, mr));
2044 if (ioc->sh) {
2045 /* Depending on the thread, a timer is activated for
2046 * the TM request. Delete this timer on completion of TM.
2047 * Decrement count of outstanding TM requests.
2048 */
2049 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2050 } else {
2051 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2052 ioc->name));
2053 return 1;
2054 }
2055
2056 if (mr == NULL) {
2057 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2058 ioc->name, mf));
2059 return 1;
2060 } else {
2061 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2062 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2063
2064 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2065 tmType = pScsiTmReq->TaskType;
2066
2067 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2068 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2069 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2070
2071 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2072 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2073 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2074 /* Error? (anything non-zero?) */
2075 if (iocstatus) {
2076
2077 /* clear flags and continue.
2078 */
2079 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2080 hd->abortSCpnt = NULL;
2081
2082 /* If an internal command is present
2083 * or the TM failed - reload the FW.
2084 * FC FW may respond FAILED to an ABORT
2085 */
2086 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2087 if ((hd->cmdPtr) ||
2088 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2089 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2090 printk((KERN_WARNING
2091 " Firmware Reload FAILED!!\n"));
2092 }
2093 }
2094 }
2095 } else {
2096 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2097
2098 hd->abortSCpnt = NULL;
2099
2100 }
2101 }
2102
2103 spin_lock_irqsave(&ioc->FreeQlock, flags);
2104 hd->tmPending = 0;
2105 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2106 hd->tmState = TM_STATE_NONE;
2107
2108 return 1;
2109}
2110
2111/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2112/*
2113 * This is anyones guess quite frankly.
2114 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002115int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2117 sector_t capacity, int geom[])
2118{
2119 int heads;
2120 int sectors;
2121 sector_t cylinders;
2122 ulong dummy;
2123
2124 heads = 64;
2125 sectors = 32;
2126
2127 dummy = heads * sectors;
2128 cylinders = capacity;
2129 sector_div(cylinders,dummy);
2130
2131 /*
2132 * Handle extended translation size for logical drives
2133 * > 1Gb
2134 */
2135 if ((ulong)capacity >= 0x200000) {
2136 heads = 255;
2137 sectors = 63;
2138 dummy = heads * sectors;
2139 cylinders = capacity;
2140 sector_div(cylinders,dummy);
2141 }
2142
2143 /* return result */
2144 geom[0] = heads;
2145 geom[1] = sectors;
2146 geom[2] = cylinders;
2147
2148 dprintk((KERN_NOTICE
2149 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
2150 sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
2151
2152 return 0;
2153}
2154
2155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2156/*
2157 * OS entry point to allow host driver to alloc memory
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002158 * for each scsi target. Called once per device the bus scan.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 * Return non-zero if allocation fails.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002161int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002162mptscsih_target_alloc(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002164 VirtTarget *vtarget;
2165
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002166 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002167 if (!vtarget)
2168 return -ENOMEM;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002169 starget->hostdata = vtarget;
2170 return 0;
2171}
2172
2173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2174/*
2175 * OS entry point to allow host driver to alloc memory
2176 * for each scsi device. Called once per device the bus scan.
2177 * Return non-zero if allocation fails.
2178 */
2179int
2180mptscsih_slave_alloc(struct scsi_device *sdev)
2181{
2182 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002184 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002186 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002188 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 if (!vdev) {
2190 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
2191 hd->ioc->name, sizeof(VirtDevice));
2192 return -ENOMEM;
2193 }
2194
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 vdev->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002196 vdev->target_id = sdev->id;
2197 vdev->bus_id = sdev->channel;
2198 vdev->lun = sdev->lun;
2199 sdev->hostdata = vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002201 starget = scsi_target(sdev);
2202 vtarget = starget->hostdata;
2203 vdev->vtarget = vtarget;
2204
2205 if (vtarget->num_luns == 0) {
2206 hd->Targets[sdev->id] = vtarget;
2207 vtarget->ioc_id = hd->ioc->id;
2208 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
2209 vtarget->target_id = sdev->id;
2210 vtarget->bus_id = sdev->channel;
2211 if (hd->ioc->bus_type == SPI) {
2212 if (hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
2213 vtarget->raidVolume = 1;
2214 ddvtprintk((KERN_INFO
2215 "RAID Volume @ id %d\n", sdev->id));
2216 }
2217 } else {
2218 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2219 }
2220 }
2221 vtarget->num_luns++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 return 0;
2223}
2224
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225/*
2226 * OS entry point to allow for host driver to free allocated memory
2227 * Called if no device present or device being unloaded
2228 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002229void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002230mptscsih_target_destroy(struct scsi_target *starget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002232 if (starget->hostdata)
2233 kfree(starget->hostdata);
2234 starget->hostdata = NULL;
2235}
2236
2237/*
2238 * OS entry point to allow for host driver to free allocated memory
2239 * Called if no device present or device being unloaded
2240 */
2241void
2242mptscsih_slave_destroy(struct scsi_device *sdev)
2243{
2244 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002246 VirtTarget *vtarget;
2247 VirtDevice *vdevice;
2248 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002250 starget = scsi_target(sdev);
2251 vtarget = starget->hostdata;
2252 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002254 mptscsih_search_running_cmds(hd, vdevice);
2255 vtarget->luns[0] &= ~(1 << vdevice->lun);
2256 vtarget->num_luns--;
2257 if (vtarget->num_luns == 0) {
2258 mptscsih_negotiate_to_asyn_narrow(hd, vtarget);
2259 if (hd->ioc->bus_type == SPI) {
2260 if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
2261 hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
2262 } else {
2263 hd->ioc->spi_data.dvStatus[vtarget->target_id] =
2264 MPT_SCSICFG_NEGOTIATE;
2265 if (!hd->negoNvram) {
2266 hd->ioc->spi_data.dvStatus[vtarget->target_id] |=
2267 MPT_SCSICFG_DV_NOT_DONE;
2268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
2270 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002271 hd->Targets[sdev->id] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002273 mptscsih_synchronize_cache(hd, vdevice);
2274 kfree(vdevice);
2275 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276}
2277
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002278/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2279/*
2280 * mptscsih_change_queue_depth - This function will set a devices queue depth
2281 * @sdev: per scsi_device pointer
2282 * @qdepth: requested queue depth
2283 *
2284 * Adding support for new 'change_queue_depth' api.
2285*/
2286int
2287mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002289 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2290 VirtTarget *vtarget;
2291 struct scsi_target *starget;
2292 int max_depth;
2293 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002295 starget = scsi_target(sdev);
2296 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002297
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002298 if (hd->ioc->bus_type == SPI) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002299 if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
2300 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 max_depth = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002302 else if (((vtarget->inq_data[0] & 0x1f) == 0x00) &&
2303 (vtarget->minSyncFactor <= MPT_ULTRA160 ))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2305 else
2306 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
2307 } else {
2308 /* error case - No Inq. Data */
2309 max_depth = 1;
2310 }
2311 } else
2312 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2313
2314 if (qdepth > max_depth)
2315 qdepth = max_depth;
2316 if (qdepth == 1)
2317 tagged = 0;
2318 else
2319 tagged = MSG_SIMPLE_TAG;
2320
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002321 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2322 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323}
2324
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325/*
2326 * OS entry point to adjust the queue_depths on a per-device basis.
2327 * Called once per device the bus scan. Use it to force the queue_depth
2328 * member to 1 if a device does not support Q tags.
2329 * Return non-zero if fails.
2330 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002331int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002332mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002334 struct Scsi_Host *sh = sdev->host;
2335 VirtTarget *vtarget;
2336 VirtDevice *vdevice;
2337 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002339 int indexed_lun, lun_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002341 starget = scsi_target(sdev);
2342 vtarget = starget->hostdata;
2343 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345 dsprintk((MYIOC_s_INFO_FMT
2346 "device @ %p, id=%d, LUN=%d, channel=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002347 hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
2348 if (hd->ioc->bus_type == SPI)
2349 dsprintk((MYIOC_s_INFO_FMT
2350 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2351 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2352 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002354 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002356 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 goto slave_configure_exit;
2358 }
2359
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002360 vdevice->configured_lun=1;
2361 lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
2362 indexed_lun = (vdevice->lun % 32);
2363 vtarget->luns[lun_index] |= (1 << indexed_lun);
2364 mptscsih_initTarget(hd, vtarget, sdev->lun, sdev->inquiry,
2365 sdev->inquiry_len );
2366 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
2368 dsprintk((MYIOC_s_INFO_FMT
2369 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002370 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002372 if (hd->ioc->bus_type == SPI)
2373 dsprintk((MYIOC_s_INFO_FMT
2374 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2375 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2376 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
2378slave_configure_exit:
2379
2380 dsprintk((MYIOC_s_INFO_FMT
2381 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002382 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2383 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
2385 return 0;
2386}
2387
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2389/*
2390 * Private routines...
2391 */
2392
2393/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2394/* Utility function to copy sense data from the scsi_cmnd buffer
2395 * to the FC and SCSI target structures.
2396 *
2397 */
2398static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002399mptscsih_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 -07002400{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002401 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 SCSIIORequest_t *pReq;
2403 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
2405 /* Get target structure
2406 */
2407 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002408 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410 if (sense_count) {
2411 u8 *sense_data;
2412 int req_index;
2413
2414 /* Copy the sense received into the scsi command block. */
2415 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2416 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2417 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2418
2419 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2420 */
2421 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002422 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 int idx;
2424 MPT_ADAPTER *ioc = hd->ioc;
2425
2426 idx = ioc->eventContext % ioc->eventLogSize;
2427 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2428 ioc->events[idx].eventContext = ioc->eventContext;
2429
2430 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2431 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002432 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2435
2436 ioc->eventContext++;
2437 }
2438 }
2439 } else {
2440 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2441 hd->ioc->name));
2442 }
2443}
2444
2445static u32
2446SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2447{
2448 MPT_SCSI_HOST *hd;
2449 int i;
2450
2451 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2452
2453 for (i = 0; i < hd->ioc->req_depth; i++) {
2454 if (hd->ScsiLookup[i] == sc) {
2455 return i;
2456 }
2457 }
2458
2459 return -1;
2460}
2461
2462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002463int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2465{
2466 MPT_SCSI_HOST *hd;
2467 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002468 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
2470 dtmprintk((KERN_WARNING MYNAM
2471 ": IOC %s_reset routed to SCSI host driver!\n",
2472 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2473 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2474
2475 /* If a FW reload request arrives after base installed but
2476 * before all scsi hosts have been attached, then an alt_ioc
2477 * may have a NULL sh pointer.
2478 */
2479 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2480 return 0;
2481 else
2482 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2483
2484 if (reset_phase == MPT_IOC_SETUP_RESET) {
2485 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2486
2487 /* Clean Up:
2488 * 1. Set Hard Reset Pending Flag
2489 * All new commands go to doneQ
2490 */
2491 hd->resetPending = 1;
2492
2493 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2494 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2495
2496 /* 2. Flush running commands
2497 * Clean ScsiLookup (and associated memory)
2498 * AND clean mytaskQ
2499 */
2500
2501 /* 2b. Reply to OS all known outstanding I/O commands.
2502 */
2503 mptscsih_flush_running_cmds(hd);
2504
2505 /* 2c. If there was an internal command that
2506 * has not completed, configuration or io request,
2507 * free these resources.
2508 */
2509 if (hd->cmdPtr) {
2510 del_timer(&hd->timer);
2511 mpt_free_msg_frame(ioc, hd->cmdPtr);
2512 }
2513
2514 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2515
2516 } else {
2517 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2518
2519 /* Once a FW reload begins, all new OS commands are
2520 * redirected to the doneQ w/ a reset status.
2521 * Init all control structures.
2522 */
2523
2524 /* ScsiLookup initialization
2525 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002526 for (ii=0; ii < hd->ioc->req_depth; ii++)
2527 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
2529 /* 2. Chain Buffer initialization
2530 */
2531
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002532 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002534 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
2536 mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
2537 }
2538
2539 /* 5. Enable new commands to be posted
2540 */
2541 spin_lock_irqsave(&ioc->FreeQlock, flags);
2542 hd->tmPending = 0;
2543 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2544 hd->resetPending = 0;
2545 hd->tmState = TM_STATE_NONE;
2546
2547 /* 6. If there was an internal command,
2548 * wake this process up.
2549 */
2550 if (hd->cmdPtr) {
2551 /*
2552 * Wake up the original calling thread
2553 */
2554 hd->pLocal = &hd->localReply;
2555 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002556 hd->scandv_wait_done = 1;
2557 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 hd->cmdPtr = NULL;
2559 }
2560
Michael Reed05e8ec12006-01-13 14:31:54 -06002561 /* 7. SPI: Set flag to force DV and re-read IOC Page 3
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002563 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
2565 ddvtprintk(("Set reload IOC Pg3 Flag\n"));
2566 }
2567
Michael Reed05e8ec12006-01-13 14:31:54 -06002568 /* 7. FC: Rescan for blocked rports which might have returned.
2569 */
2570 else if (ioc->bus_type == FC) {
2571 int work_count;
2572 unsigned long flags;
2573
2574 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2575 work_count = ++ioc->fc_rescan_work_count;
2576 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2577 if (work_count == 1)
2578 schedule_work(&ioc->fc_rescan_work);
2579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2581
2582 }
2583
2584 return 1; /* currently means nothing really */
2585}
2586
2587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002588/* work queue thread to clear the persitency table */
2589static void
2590mptscsih_sas_persist_clear_table(void * arg)
2591{
2592 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
2593
2594 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2595}
2596
2597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002598int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2600{
2601 MPT_SCSI_HOST *hd;
2602 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
Michael Reed05e8ec12006-01-13 14:31:54 -06002603 int work_count;
2604 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
2606 devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
2607 ioc->name, event));
2608
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002609 if (ioc->sh == NULL ||
2610 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2611 return 1;
2612
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 switch (event) {
2614 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2615 /* FIXME! */
2616 break;
2617 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2618 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002619 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002620 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 break;
2622 case MPI_EVENT_LOGOUT: /* 09 */
2623 /* FIXME! */
2624 break;
2625
Michael Reed05e8ec12006-01-13 14:31:54 -06002626 case MPI_EVENT_RESCAN: /* 06 */
2627 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
2628 work_count = ++ioc->fc_rescan_work_count;
2629 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
2630 if (work_count == 1)
2631 schedule_work(&ioc->fc_rescan_work);
2632 break;
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 /*
2635 * CHECKME! Don't think we need to do
2636 * anything for these, but...
2637 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2639 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2640 /*
2641 * CHECKME! Falling thru...
2642 */
2643 break;
2644
2645 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002646 {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07002647#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002648 pMpiEventDataRaid_t pRaidEventData =
2649 (pMpiEventDataRaid_t) pEvReply->Data;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002650 /* Domain Validation Needed */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002651 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002652 pRaidEventData->ReasonCode ==
2653 MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
2654 mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002656 break;
2657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002659 /* Persistent table is full. */
2660 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2661 INIT_WORK(&mptscsih_persistTask,
2662 mptscsih_sas_persist_clear_table,(void *)ioc);
2663 schedule_work(&mptscsih_persistTask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 break;
2665
2666 case MPI_EVENT_NONE: /* 00 */
2667 case MPI_EVENT_LOG_DATA: /* 01 */
2668 case MPI_EVENT_STATE_CHANGE: /* 02 */
2669 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2670 default:
2671 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2672 break;
2673 }
2674
2675 return 1; /* currently means nothing really */
2676}
2677
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2679/*
2680 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2681 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002682 * @vtarget: per target private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 * @lun: SCSI LUN id
2684 * @data: Pointer to data
2685 * @dlen: Number of INQUIRY bytes
2686 *
2687 * NOTE: It's only SAFE to call this routine if data points to
2688 * sane & valid STANDARD INQUIRY data!
2689 *
2690 * Allocate and initialize memory for this target.
2691 * Save inquiry data.
2692 *
2693 */
2694static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002695mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002697 SpiCfgData *pSpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 char data_56;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002699 int inq_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002702 hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704 /*
2705 * If the peripheral qualifier filter is enabled then if the target reports a 0x1
2706 * (i.e. The targer is capable of supporting the specified peripheral device type
2707 * on this logical unit; however, the physical device is not currently connected
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002708 * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 * capable of supporting a physical device on this logical unit). This is to work
2710 * around a bug in th emid-layer in some distributions in which the mid-layer will
2711 * continue to try to communicate to the LUN and evntually create a dummy LUN.
2712 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002713 if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 data[0] |= 0x40;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002715
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 /* Is LUN supported? If so, upper 2 bits will be 0
2717 * in first byte of inquiry data.
2718 */
2719 if (data[0] & 0xe0)
2720 return;
2721
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002722 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002725 if (data)
2726 vtarget->type = data[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002728 if (hd->ioc->bus_type != SPI)
2729 return;
2730
2731 if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
2732 /* Treat all Processors as SAF-TE if
2733 * command line option is set */
2734 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2735 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
2736 }else if ((data[0] == TYPE_PROCESSOR) &&
2737 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
2738 if ( dlen > 49 ) {
2739 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
2740 if ( data[44] == 'S' &&
2741 data[45] == 'A' &&
2742 data[46] == 'F' &&
2743 data[47] == '-' &&
2744 data[48] == 'T' &&
2745 data[49] == 'E' ) {
2746 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
2747 mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
2749 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002750 }
2751 if (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
2752 inq_len = dlen < 8 ? dlen : 8;
2753 memcpy (vtarget->inq_data, data, inq_len);
2754 /* If have not done DV, set the DV flag.
2755 */
2756 pSpi = &hd->ioc->spi_data;
2757 if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
2758 if (pSpi->dvStatus[vtarget->target_id] & MPT_SCSICFG_DV_NOT_DONE)
2759 pSpi->dvStatus[vtarget->target_id] |= MPT_SCSICFG_NEED_DV;
2760 }
2761 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002763 data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */
2764 if (dlen > 56) {
2765 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2766 /* Update the target capabilities
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002768 data_56 = data[56];
2769 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002771 }
2772 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
2773 } else {
2774 /* Initial Inquiry may not request enough data bytes to
2775 * obtain byte 57. DV will; if target doesn't return
2776 * at least 57 bytes, data[56] will be zero. */
2777 if (dlen > 56) {
2778 if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
2779 /* Update the target capabilities
2780 */
2781 data_56 = data[56];
2782 vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
2783 mptscsih_setTargetNegoParms(hd, vtarget, data_56);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 }
2785 }
2786 }
2787}
2788
2789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2790/*
2791 * Update the target negotiation parameters based on the
2792 * the Inquiry data, adapter capabilities, and NVRAM settings.
2793 *
2794 */
2795static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002796mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, char byte56)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002798 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 int id = (int) target->target_id;
2800 int nvram;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002801 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 int ii;
2803 u8 width = MPT_NARROW;
2804 u8 factor = MPT_ASYNC;
2805 u8 offset = 0;
2806 u8 version, nfactor;
2807 u8 noQas = 1;
2808
2809 target->negoFlags = pspi_data->noQas;
2810
2811 /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
2812 * support. If available, default QAS to off and allow enabling.
2813 * If not available, default QAS to on, turn off for non-disks.
2814 */
2815
2816 /* Set flags based on Inquiry data
2817 */
2818 version = target->inq_data[2] & 0x07;
2819 if (version < 2) {
2820 width = 0;
2821 factor = MPT_ULTRA2;
2822 offset = pspi_data->maxSyncOffset;
2823 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2824 } else {
2825 if (target->inq_data[7] & 0x20) {
2826 width = 1;
2827 }
2828
2829 if (target->inq_data[7] & 0x10) {
2830 factor = pspi_data->minSyncFactor;
2831 if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
2832 /* bits 2 & 3 show Clocking support */
2833 if ((byte56 & 0x0C) == 0)
2834 factor = MPT_ULTRA2;
2835 else {
2836 if ((byte56 & 0x03) == 0)
2837 factor = MPT_ULTRA160;
2838 else {
2839 factor = MPT_ULTRA320;
2840 if (byte56 & 0x02)
2841 {
2842 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
2843 noQas = 0;
2844 }
2845 if (target->inq_data[0] == TYPE_TAPE) {
2846 if (byte56 & 0x01)
2847 target->negoFlags |= MPT_TAPE_NEGO_IDP;
2848 }
2849 }
2850 }
2851 } else {
2852 ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
2853 noQas = 0;
2854 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002855
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 offset = pspi_data->maxSyncOffset;
2857
2858 /* If RAID, never disable QAS
2859 * else if non RAID, do not disable
2860 * QAS if bit 1 is set
2861 * bit 1 QAS support, non-raid only
2862 * bit 0 IU support
2863 */
2864 if (target->raidVolume == 1) {
2865 noQas = 0;
2866 }
2867 } else {
2868 factor = MPT_ASYNC;
2869 offset = 0;
2870 }
2871 }
2872
2873 if ( (target->inq_data[7] & 0x02) == 0) {
2874 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2875 }
2876
2877 /* Update tflags based on NVRAM settings. (SCSI only)
2878 */
2879 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2880 nvram = pspi_data->nvram[id];
2881 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2882
2883 if (width)
2884 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2885
2886 if (offset > 0) {
2887 /* Ensure factor is set to the
2888 * maximum of: adapter, nvram, inquiry
2889 */
2890 if (nfactor) {
2891 if (nfactor < pspi_data->minSyncFactor )
2892 nfactor = pspi_data->minSyncFactor;
2893
2894 factor = max(factor, nfactor);
2895 if (factor == MPT_ASYNC)
2896 offset = 0;
2897 } else {
2898 offset = 0;
2899 factor = MPT_ASYNC;
2900 }
2901 } else {
2902 factor = MPT_ASYNC;
2903 }
2904 }
2905
2906 /* Make sure data is consistent
2907 */
2908 if ((!width) && (factor < MPT_ULTRA2)) {
2909 factor = MPT_ULTRA2;
2910 }
2911
2912 /* Save the data to the target structure.
2913 */
2914 target->minSyncFactor = factor;
2915 target->maxOffset = offset;
2916 target->maxWidth = width;
2917
2918 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2919
2920 /* Disable unused features.
2921 */
2922 if (!width)
2923 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2924
2925 if (!offset)
2926 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2927
2928 if ( factor > MPT_ULTRA320 )
2929 noQas = 0;
2930
2931 /* GEM, processor WORKAROUND
2932 */
2933 if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
2934 target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
2935 pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
2936 } else {
2937 if (noQas && (pspi_data->noQas == 0)) {
2938 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2939 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2940
2941 /* Disable QAS in a mixed configuration case
2942 */
2943
2944 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
2945 for (ii = 0; ii < id; ii++) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002946 if ( (vtarget = hd->Targets[ii]) ) {
2947 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2948 mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 }
2951 }
2952 }
2953
2954 /* Write SDP1 on this I/O to this target */
2955 if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
2956 ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
2957 mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
2958 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
2959 } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
2960 ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
2961 mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
2962 pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
2963 }
2964}
2965
2966/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967/*
2968 * If no Target, bus reset on 1st I/O. Set the flag to
2969 * prevent any future negotiations to this device.
2970 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002971static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002972mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002974 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002976 if ((vdev = sc->device->hostdata) != NULL)
2977 hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 return;
2979}
2980
2981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2982/*
2983 * SCSI Config Page functionality ...
2984 */
2985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2986/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
2987 * based on width, factor and offset parameters.
2988 * @width: bus width
2989 * @factor: sync factor
2990 * @offset: sync offset
2991 * @requestedPtr: pointer to requested values (updated)
2992 * @configurationPtr: pointer to configuration values (updated)
2993 * @flags: flags to block WDTR or SDTR negotiation
2994 *
2995 * Return: None.
2996 *
2997 * Remark: Called by writeSDP1 and _dv_params
2998 */
2999static void
3000mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
3001{
3002 u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
3003 u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
3004
3005 *configurationPtr = 0;
3006 *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
3007 *requestedPtr |= (offset << 16) | (factor << 8);
3008
3009 if (width && offset && !nowide && !nosync) {
3010 if (factor < MPT_ULTRA160) {
3011 *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
3012 if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
3013 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
3014 if (flags & MPT_TAPE_NEGO_IDP)
3015 *requestedPtr |= 0x08000000;
3016 } else if (factor < MPT_ULTRA2) {
3017 *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
3018 }
3019 }
3020
3021 if (nowide)
3022 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
3023
3024 if (nosync)
3025 *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
3026
3027 return;
3028}
3029
3030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3031/* mptscsih_writeSDP1 - write SCSI Device Page 1
3032 * @hd: Pointer to a SCSI Host Strucutre
3033 * @portnum: IOC port number
3034 * @target_id: writeSDP1 for single ID
3035 * @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
3036 *
3037 * Return: -EFAULT if read of config page header fails
3038 * or 0 if success.
3039 *
3040 * Remark: If a target has been found, the settings from the
3041 * target structure are used, else the device is set
3042 * to async/narrow.
3043 *
3044 * Remark: Called during init and after a FW reload.
3045 * Remark: We do not wait for a return, write pages sequentially.
3046 */
3047static int
3048mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
3049{
3050 MPT_ADAPTER *ioc = hd->ioc;
3051 Config_t *pReq;
3052 SCSIDevicePage1_t *pData;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003053 VirtTarget *vtarget=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 MPT_FRAME_HDR *mf;
3055 dma_addr_t dataDma;
3056 u16 req_idx;
3057 u32 frameOffset;
3058 u32 requested, configuration, flagsLength;
3059 int ii, nvram;
3060 int id = 0, maxid = 0;
3061 u8 width;
3062 u8 factor;
3063 u8 offset;
3064 u8 bus = 0;
3065 u8 negoFlags;
3066 u8 maxwidth, maxoffset, maxfactor;
3067
3068 if (ioc->spi_data.sdp1length == 0)
3069 return 0;
3070
3071 if (flags & MPT_SCSICFG_ALL_IDS) {
3072 id = 0;
3073 maxid = ioc->sh->max_id - 1;
3074 } else if (ioc->sh) {
3075 id = target_id;
3076 maxid = min_t(int, id, ioc->sh->max_id - 1);
3077 }
3078
3079 for (; id <= maxid; id++) {
3080
3081 if (id == ioc->pfacts[portnum].PortSCSIID)
3082 continue;
3083
3084 /* Use NVRAM to get adapter and target maximums
3085 * Data over-riden by target structure information, if present
3086 */
3087 maxwidth = ioc->spi_data.maxBusWidth;
3088 maxoffset = ioc->spi_data.maxSyncOffset;
3089 maxfactor = ioc->spi_data.minSyncFactor;
3090 if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3091 nvram = ioc->spi_data.nvram[id];
3092
3093 if (maxwidth)
3094 maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
3095
3096 if (maxoffset > 0) {
3097 maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
3098 if (maxfactor == 0) {
3099 /* Key for async */
3100 maxfactor = MPT_ASYNC;
3101 maxoffset = 0;
3102 } else if (maxfactor < ioc->spi_data.minSyncFactor) {
3103 maxfactor = ioc->spi_data.minSyncFactor;
3104 }
3105 } else
3106 maxfactor = MPT_ASYNC;
3107 }
3108
3109 /* Set the negotiation flags.
3110 */
3111 negoFlags = ioc->spi_data.noQas;
3112 if (!maxwidth)
3113 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
3114
3115 if (!maxoffset)
3116 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
3117
3118 if (flags & MPT_SCSICFG_USE_NVRAM) {
3119 width = maxwidth;
3120 factor = maxfactor;
3121 offset = maxoffset;
3122 } else {
3123 width = 0;
3124 factor = MPT_ASYNC;
3125 offset = 0;
3126 //negoFlags = 0;
3127 //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
3128 }
3129
3130 /* If id is not a raid volume, get the updated
3131 * transmission settings from the target structure.
3132 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003133 if (hd->Targets && (vtarget = hd->Targets[id]) && !vtarget->raidVolume) {
3134 width = vtarget->maxWidth;
3135 factor = vtarget->minSyncFactor;
3136 offset = vtarget->maxOffset;
3137 negoFlags = vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 }
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003139
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3141 /* Force to async and narrow if DV has not been executed
3142 * for this ID
3143 */
3144 if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
3145 width = 0;
3146 factor = MPT_ASYNC;
3147 offset = 0;
3148 }
3149#endif
3150
3151 if (flags & MPT_SCSICFG_BLK_NEGO)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003152 negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
3154 mptscsih_setDevicePage1Flags(width, factor, offset,
3155 &requested, &configuration, negoFlags);
3156 dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
3157 target_id, width, factor, offset, negoFlags, requested, configuration));
3158
3159 /* Get a MF for this command.
3160 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003161 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003162 dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
3163 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 return -EAGAIN;
3165 }
3166
3167 ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
3168 hd->ioc->name, mf, id, requested, configuration));
3169
3170
3171 /* Set the request and the data pointers.
3172 * Request takes: 36 bytes (32 bit SGE)
3173 * SCSI Device Page 1 requires 16 bytes
3174 * 40 + 16 <= size of SCSI IO Request = 56 bytes
3175 * and MF size >= 64 bytes.
3176 * Place data at end of MF.
3177 */
3178 pReq = (Config_t *)mf;
3179
3180 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3181 frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
3182
3183 pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
3184 dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
3185
3186 /* Complete the request frame (same for all requests).
3187 */
3188 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3189 pReq->Reserved = 0;
3190 pReq->ChainOffset = 0;
3191 pReq->Function = MPI_FUNCTION_CONFIG;
3192 pReq->ExtPageLength = 0;
3193 pReq->ExtPageType = 0;
3194 pReq->MsgFlags = 0;
3195 for (ii=0; ii < 8; ii++) {
3196 pReq->Reserved2[ii] = 0;
3197 }
3198 pReq->Header.PageVersion = ioc->spi_data.sdp1version;
3199 pReq->Header.PageLength = ioc->spi_data.sdp1length;
3200 pReq->Header.PageNumber = 1;
3201 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3202 pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
3203
3204 /* Add a SGE to the config request.
3205 */
3206 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
3207
3208 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3209
3210 /* Set up the common data portion
3211 */
3212 pData->Header.PageVersion = pReq->Header.PageVersion;
3213 pData->Header.PageLength = pReq->Header.PageLength;
3214 pData->Header.PageNumber = pReq->Header.PageNumber;
3215 pData->Header.PageType = pReq->Header.PageType;
3216 pData->RequestedParameters = cpu_to_le32(requested);
3217 pData->Reserved = 0;
3218 pData->Configuration = cpu_to_le32(configuration);
3219
3220 dprintk((MYIOC_s_INFO_FMT
3221 "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
3222 ioc->name, id, (id | (bus<<8)),
3223 requested, configuration));
3224
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003225 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 }
3227
3228 return 0;
3229}
3230
3231/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3232/* mptscsih_writeIOCPage4 - write IOC Page 4
3233 * @hd: Pointer to a SCSI Host Structure
3234 * @target_id: write IOC Page4 for this ID & Bus
3235 *
3236 * Return: -EAGAIN if unable to obtain a Message Frame
3237 * or 0 if success.
3238 *
3239 * Remark: We do not wait for a return, write pages sequentially.
3240 */
3241static int
3242mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
3243{
3244 MPT_ADAPTER *ioc = hd->ioc;
3245 Config_t *pReq;
3246 IOCPage4_t *IOCPage4Ptr;
3247 MPT_FRAME_HDR *mf;
3248 dma_addr_t dataDma;
3249 u16 req_idx;
3250 u32 frameOffset;
3251 u32 flagsLength;
3252 int ii;
3253
3254 /* Get a MF for this command.
3255 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003256 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003257 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 ioc->name));
3259 return -EAGAIN;
3260 }
3261
3262 /* Set the request and the data pointers.
3263 * Place data at end of MF.
3264 */
3265 pReq = (Config_t *)mf;
3266
3267 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3268 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
3269
3270 /* Complete the request frame (same for all requests).
3271 */
3272 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3273 pReq->Reserved = 0;
3274 pReq->ChainOffset = 0;
3275 pReq->Function = MPI_FUNCTION_CONFIG;
3276 pReq->ExtPageLength = 0;
3277 pReq->ExtPageType = 0;
3278 pReq->MsgFlags = 0;
3279 for (ii=0; ii < 8; ii++) {
3280 pReq->Reserved2[ii] = 0;
3281 }
3282
3283 IOCPage4Ptr = ioc->spi_data.pIocPg4;
3284 dataDma = ioc->spi_data.IocPg4_dma;
3285 ii = IOCPage4Ptr->ActiveSEP++;
3286 IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
3287 IOCPage4Ptr->SEP[ii].SEPBus = bus;
3288 pReq->Header = IOCPage4Ptr->Header;
3289 pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
3290
3291 /* Add a SGE to the config request.
3292 */
3293 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3294 (IOCPage4Ptr->Header.PageLength + ii) * 4;
3295
3296 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3297
3298 dinitprintk((MYIOC_s_INFO_FMT
3299 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3300 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
3301
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003302 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
3304 return 0;
3305}
3306
3307/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3308/*
3309 * Bus Scan and Domain Validation functionality ...
3310 */
3311
3312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3313/*
3314 * mptscsih_scandv_complete - Scan and DV callback routine registered
3315 * to Fustion MPT (base) driver.
3316 *
3317 * @ioc: Pointer to MPT_ADAPTER structure
3318 * @mf: Pointer to original MPT request frame
3319 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
3320 *
3321 * This routine is called from mpt.c::mpt_interrupt() at the completion
3322 * of any SCSI IO request.
3323 * This routine is registered with the Fusion MPT (base) driver at driver
3324 * load/init time via the mpt_register() API call.
3325 *
3326 * Returns 1 indicating alloc'd request frame ptr should be freed.
3327 *
3328 * Remark: Sets a completion code and (possibly) saves sense data
3329 * in the IOC member localReply structure.
3330 * Used ONLY for DV and other internal commands.
3331 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003332int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
3334{
3335 MPT_SCSI_HOST *hd;
3336 SCSIIORequest_t *pReq;
3337 int completionCode;
3338 u16 req_idx;
3339
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003340 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
3341
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 if ((mf == NULL) ||
3343 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
3344 printk(MYIOC_s_ERR_FMT
3345 "ScanDvComplete, %s req frame ptr! (=%p)\n",
3346 ioc->name, mf?"BAD":"NULL", (void *) mf);
3347 goto wakeup;
3348 }
3349
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 del_timer(&hd->timer);
3351 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3352 hd->ScsiLookup[req_idx] = NULL;
3353 pReq = (SCSIIORequest_t *) mf;
3354
3355 if (mf != hd->cmdPtr) {
3356 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
3357 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
3358 }
3359 hd->cmdPtr = NULL;
3360
3361 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
3362 hd->ioc->name, mf, mr, req_idx));
3363
3364 hd->pLocal = &hd->localReply;
3365 hd->pLocal->scsiStatus = 0;
3366
3367 /* If target struct exists, clear sense valid flag.
3368 */
3369 if (mr == NULL) {
3370 completionCode = MPT_SCANDV_GOOD;
3371 } else {
3372 SCSIIOReply_t *pReply;
3373 u16 status;
3374 u8 scsi_status;
3375
3376 pReply = (SCSIIOReply_t *) mr;
3377
3378 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
3379 scsi_status = pReply->SCSIStatus;
3380
3381 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
3382 status, pReply->SCSIState, scsi_status,
3383 le32_to_cpu(pReply->IOCLogInfo)));
3384
3385 switch(status) {
3386
3387 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
3388 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
3389 break;
3390
3391 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
3392 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
3393 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
3394 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
3395 completionCode = MPT_SCANDV_DID_RESET;
3396 break;
3397
3398 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
3399 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
3400 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
3401 if (pReply->Function == MPI_FUNCTION_CONFIG) {
3402 ConfigReply_t *pr = (ConfigReply_t *)mr;
3403 completionCode = MPT_SCANDV_GOOD;
3404 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
3405 hd->pLocal->header.PageLength = pr->Header.PageLength;
3406 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
3407 hd->pLocal->header.PageType = pr->Header.PageType;
3408
3409 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
3410 /* If the RAID Volume request is successful,
3411 * return GOOD, else indicate that
3412 * some type of error occurred.
3413 */
3414 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02003415 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 completionCode = MPT_SCANDV_GOOD;
3417 else
3418 completionCode = MPT_SCANDV_SOME_ERROR;
3419
3420 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
3421 u8 *sense_data;
3422 int sz;
3423
3424 /* save sense data in global structure
3425 */
3426 completionCode = MPT_SCANDV_SENSE;
3427 hd->pLocal->scsiStatus = scsi_status;
3428 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
3429 (req_idx * MPT_SENSE_BUFFER_ALLOC));
3430
3431 sz = min_t(int, pReq->SenseBufferLength,
3432 SCSI_STD_SENSE_BYTES);
3433 memcpy(hd->pLocal->sense, sense_data, sz);
3434
3435 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
3436 sense_data));
3437 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
3438 if (pReq->CDB[0] == INQUIRY)
3439 completionCode = MPT_SCANDV_ISSUE_SENSE;
3440 else
3441 completionCode = MPT_SCANDV_DID_RESET;
3442 }
3443 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
3444 completionCode = MPT_SCANDV_DID_RESET;
3445 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3446 completionCode = MPT_SCANDV_DID_RESET;
3447 else {
3448 completionCode = MPT_SCANDV_GOOD;
3449 hd->pLocal->scsiStatus = scsi_status;
3450 }
3451 break;
3452
3453 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
3454 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
3455 completionCode = MPT_SCANDV_DID_RESET;
3456 else
3457 completionCode = MPT_SCANDV_SOME_ERROR;
3458 break;
3459
3460 default:
3461 completionCode = MPT_SCANDV_SOME_ERROR;
3462 break;
3463
3464 } /* switch(status) */
3465
3466 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
3467 completionCode));
3468 } /* end of address reply case */
3469
3470 hd->pLocal->completion = completionCode;
3471
3472 /* MF and RF are freed in mpt_interrupt
3473 */
3474wakeup:
3475 /* Free Chain buffers (will never chain) in scan or dv */
3476 //mptscsih_freeChainBuffers(ioc, req_idx);
3477
3478 /*
3479 * Wake up the original calling thread
3480 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003481 hd->scandv_wait_done = 1;
3482 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
3484 return 1;
3485}
3486
3487/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3488/* mptscsih_timer_expired - Call back for timer process.
3489 * Used only for dv functionality.
3490 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3491 *
3492 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003493void
3494mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495{
3496 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3497
3498 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3499
3500 if (hd->cmdPtr) {
3501 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3502
3503 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3504 /* Desire to issue a task management request here.
3505 * TM requests MUST be single threaded.
3506 * If old eh code and no TM current, issue request.
3507 * If new eh code, do nothing. Wait for OS cmd timeout
3508 * for bus reset.
3509 */
3510 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3511 } else {
3512 /* Perform a FW reload */
3513 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3514 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3515 }
3516 }
3517 } else {
3518 /* This should NEVER happen */
3519 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3520 }
3521
3522 /* No more processing.
3523 * TM call will generate an interrupt for SCSI TM Management.
3524 * The FW will reply to all outstanding commands, callback will finish cleanup.
3525 * Hard reset clean-up will free all resources.
3526 */
3527 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3528
3529 return;
3530}
3531
3532#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3534/* mptscsih_do_raid - Format and Issue a RAID volume request message.
3535 * @hd: Pointer to scsi host structure
3536 * @action: What do be done.
3537 * @id: Logical target id.
3538 * @bus: Target locations bus.
3539 *
3540 * Returns: < 0 on a fatal error
3541 * 0 on success
3542 *
3543 * Remark: Wait to return until reply processed by the ISR.
3544 */
3545static int
3546mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
3547{
3548 MpiRaidActionRequest_t *pReq;
3549 MPT_FRAME_HDR *mf;
3550 int in_isr;
3551
3552 in_isr = in_interrupt();
3553 if (in_isr) {
3554 dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
3555 hd->ioc->name));
3556 return -EPERM;
3557 }
3558
3559 /* Get and Populate a free Frame
3560 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003561 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
3563 hd->ioc->name));
3564 return -EAGAIN;
3565 }
3566 pReq = (MpiRaidActionRequest_t *)mf;
3567 pReq->Action = action;
3568 pReq->Reserved1 = 0;
3569 pReq->ChainOffset = 0;
3570 pReq->Function = MPI_FUNCTION_RAID_ACTION;
3571 pReq->VolumeID = io->id;
3572 pReq->VolumeBus = io->bus;
3573 pReq->PhysDiskNum = io->physDiskNum;
3574 pReq->MsgFlags = 0;
3575 pReq->Reserved2 = 0;
3576 pReq->ActionDataWord = 0; /* Reserved for this action */
3577 //pReq->ActionDataSGE = 0;
3578
3579 mpt_add_sge((char *)&pReq->ActionDataSGE,
3580 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
3581
3582 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
3583 hd->ioc->name, action, io->id));
3584
3585 hd->pLocal = NULL;
3586 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003587 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
3589 /* Save cmd pointer, for resource free if timeout or
3590 * FW reload occurs
3591 */
3592 hd->cmdPtr = mf;
3593
3594 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003595 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3596 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
3598 if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
3599 return -1;
3600
3601 return 0;
3602}
3603#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
3604
3605/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3606/**
3607 * mptscsih_do_cmd - Do internal command.
3608 * @hd: MPT_SCSI_HOST pointer
3609 * @io: INTERNAL_CMD pointer.
3610 *
3611 * Issue the specified internally generated command and do command
3612 * specific cleanup. For bus scan / DV only.
3613 * NOTES: If command is Inquiry and status is good,
3614 * initialize a target structure, save the data
3615 *
3616 * Remark: Single threaded access only.
3617 *
3618 * Return:
3619 * < 0 if an illegal command or no resources
3620 *
3621 * 0 if good
3622 *
3623 * > 0 if command complete but some type of completion error.
3624 */
3625static int
3626mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3627{
3628 MPT_FRAME_HDR *mf;
3629 SCSIIORequest_t *pScsiReq;
3630 SCSIIORequest_t ReqCopy;
3631 int my_idx, ii, dir;
3632 int rc, cmdTimeout;
3633 int in_isr;
3634 char cmdLen;
3635 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3636 char cmd = io->cmd;
3637
3638 in_isr = in_interrupt();
3639 if (in_isr) {
3640 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3641 hd->ioc->name));
3642 return -EPERM;
3643 }
3644
3645
3646 /* Set command specific information
3647 */
3648 switch (cmd) {
3649 case INQUIRY:
3650 cmdLen = 6;
3651 dir = MPI_SCSIIO_CONTROL_READ;
3652 CDB[0] = cmd;
3653 CDB[4] = io->size;
3654 cmdTimeout = 10;
3655 break;
3656
3657 case TEST_UNIT_READY:
3658 cmdLen = 6;
3659 dir = MPI_SCSIIO_CONTROL_READ;
3660 cmdTimeout = 10;
3661 break;
3662
3663 case START_STOP:
3664 cmdLen = 6;
3665 dir = MPI_SCSIIO_CONTROL_READ;
3666 CDB[0] = cmd;
3667 CDB[4] = 1; /*Spin up the disk */
3668 cmdTimeout = 15;
3669 break;
3670
3671 case REQUEST_SENSE:
3672 cmdLen = 6;
3673 CDB[0] = cmd;
3674 CDB[4] = io->size;
3675 dir = MPI_SCSIIO_CONTROL_READ;
3676 cmdTimeout = 10;
3677 break;
3678
3679 case READ_BUFFER:
3680 cmdLen = 10;
3681 dir = MPI_SCSIIO_CONTROL_READ;
3682 CDB[0] = cmd;
3683 if (io->flags & MPT_ICFLAG_ECHO) {
3684 CDB[1] = 0x0A;
3685 } else {
3686 CDB[1] = 0x02;
3687 }
3688
3689 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3690 CDB[1] |= 0x01;
3691 }
3692 CDB[6] = (io->size >> 16) & 0xFF;
3693 CDB[7] = (io->size >> 8) & 0xFF;
3694 CDB[8] = io->size & 0xFF;
3695 cmdTimeout = 10;
3696 break;
3697
3698 case WRITE_BUFFER:
3699 cmdLen = 10;
3700 dir = MPI_SCSIIO_CONTROL_WRITE;
3701 CDB[0] = cmd;
3702 if (io->flags & MPT_ICFLAG_ECHO) {
3703 CDB[1] = 0x0A;
3704 } else {
3705 CDB[1] = 0x02;
3706 }
3707 CDB[6] = (io->size >> 16) & 0xFF;
3708 CDB[7] = (io->size >> 8) & 0xFF;
3709 CDB[8] = io->size & 0xFF;
3710 cmdTimeout = 10;
3711 break;
3712
3713 case RESERVE:
3714 cmdLen = 6;
3715 dir = MPI_SCSIIO_CONTROL_READ;
3716 CDB[0] = cmd;
3717 cmdTimeout = 10;
3718 break;
3719
3720 case RELEASE:
3721 cmdLen = 6;
3722 dir = MPI_SCSIIO_CONTROL_READ;
3723 CDB[0] = cmd;
3724 cmdTimeout = 10;
3725 break;
3726
3727 case SYNCHRONIZE_CACHE:
3728 cmdLen = 10;
3729 dir = MPI_SCSIIO_CONTROL_READ;
3730 CDB[0] = cmd;
3731// CDB[1] = 0x02; /* set immediate bit */
3732 cmdTimeout = 10;
3733 break;
3734
3735 default:
3736 /* Error Case */
3737 return -EFAULT;
3738 }
3739
3740 /* Get and Populate a free Frame
3741 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003742 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3744 hd->ioc->name));
3745 return -EBUSY;
3746 }
3747
3748 pScsiReq = (SCSIIORequest_t *) mf;
3749
3750 /* Get the request index */
3751 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3752 ADD_INDEX_LOG(my_idx); /* for debug */
3753
3754 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3755 pScsiReq->TargetID = io->physDiskNum;
3756 pScsiReq->Bus = 0;
3757 pScsiReq->ChainOffset = 0;
3758 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3759 } else {
3760 pScsiReq->TargetID = io->id;
3761 pScsiReq->Bus = io->bus;
3762 pScsiReq->ChainOffset = 0;
3763 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3764 }
3765
3766 pScsiReq->CDBLength = cmdLen;
3767 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3768
3769 pScsiReq->Reserved = 0;
3770
3771 pScsiReq->MsgFlags = mpt_msg_flags();
3772 /* MsgContext set in mpt_get_msg_fram call */
3773
3774 for (ii=0; ii < 8; ii++)
3775 pScsiReq->LUN[ii] = 0;
3776 pScsiReq->LUN[1] = io->lun;
3777
3778 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3779 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3780 else
3781 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3782
3783 if (cmd == REQUEST_SENSE) {
3784 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3785 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3786 hd->ioc->name, cmd));
3787 }
3788
3789 for (ii=0; ii < 16; ii++)
3790 pScsiReq->CDB[ii] = CDB[ii];
3791
3792 pScsiReq->DataLength = cpu_to_le32(io->size);
3793 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3794 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3795
3796 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3797 hd->ioc->name, cmd, io->bus, io->id, io->lun));
3798
3799 if (dir == MPI_SCSIIO_CONTROL_READ) {
3800 mpt_add_sge((char *) &pScsiReq->SGL,
3801 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3802 io->data_dma);
3803 } else {
3804 mpt_add_sge((char *) &pScsiReq->SGL,
3805 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3806 io->data_dma);
3807 }
3808
3809 /* The ISR will free the request frame, but we need
3810 * the information to initialize the target. Duplicate.
3811 */
3812 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3813
3814 /* Issue this command after:
3815 * finish init
3816 * add timer
3817 * Wait until the reply has been received
3818 * ScsiScanDvCtx callback function will
3819 * set hd->pLocal;
3820 * set scandv_wait_done and call wake_up
3821 */
3822 hd->pLocal = NULL;
3823 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003824 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
3826 /* Save cmd pointer, for resource free if timeout or
3827 * FW reload occurs
3828 */
3829 hd->cmdPtr = mf;
3830
3831 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003832 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3833 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
3835 if (hd->pLocal) {
3836 rc = hd->pLocal->completion;
3837 hd->pLocal->skip = 0;
3838
3839 /* Always set fatal error codes in some cases.
3840 */
3841 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3842 rc = -ENXIO;
3843 else if (rc == MPT_SCANDV_SOME_ERROR)
3844 rc = -rc;
3845 } else {
3846 rc = -EFAULT;
3847 /* This should never happen. */
3848 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3849 hd->ioc->name));
3850 }
3851
3852 return rc;
3853}
3854
3855/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3856/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003857 * mptscsih_negotiate_to_asyn_narrow - Restore devices to default state
3858 * @hd: Pointer to a SCSI HOST structure
3859 * @vtarget: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 *
3861 * Uses the ISR, but with special processing.
3862 * MUST be single-threaded.
3863 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003865static void
3866mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867{
3868 MPT_ADAPTER *ioc= hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003869 SCSIDevicePage1_t *pcfg1Data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 CONFIGPARMS cfg;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003871 dma_addr_t cfg1_dma_addr;
3872 ConfigPageHeader_t header;
3873 int id;
3874 int requested, configuration, data,i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 u8 flags, factor;
3876
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003877 if (ioc->bus_type != SPI)
3878 return;
3879
3880 if (!ioc->spi_data.sdp1length)
3881 return;
3882
3883 pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
3884 ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
3885
3886 if (pcfg1Data == NULL)
3887 return;
3888
3889 header.PageVersion = ioc->spi_data.sdp1version;
3890 header.PageLength = ioc->spi_data.sdp1length;
3891 header.PageNumber = 1;
3892 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
3893 cfg.cfghdr.hdr = &header;
3894 cfg.physAddr = cfg1_dma_addr;
3895 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
3896 cfg.dir = 1;
3897 cfg.timeout = 0;
3898
3899 if (vtarget->raidVolume && ioc->raid_data.pIocPg3) {
3900 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3901 id = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID;
3902 flags = hd->ioc->spi_data.noQas;
3903 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
3904 data = hd->ioc->spi_data.nvram[id];
3905 if (data & MPT_NVRAM_WIDE_DISABLE)
3906 flags |= MPT_TARGET_NO_NEGO_WIDE;
3907 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
3908 if ((factor == 0) || (factor == MPT_ASYNC))
3909 flags |= MPT_TARGET_NO_NEGO_SYNC;
3910 }
3911 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3912 &configuration, flags);
3913 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3914 "offset=0 negoFlags=%x request=%x config=%x\n",
3915 id, flags, requested, configuration));
3916 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3917 pcfg1Data->Reserved = 0;
3918 pcfg1Data->Configuration = cpu_to_le32(configuration);
3919 cfg.pageAddr = (vtarget->bus_id<<8) | id;
3920 mpt_config(hd->ioc, &cfg);
3921 }
3922 } else {
3923 flags = vtarget->negoFlags;
3924 mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
3925 &configuration, flags);
3926 dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
3927 "offset=0 negoFlags=%x request=%x config=%x\n",
3928 vtarget->target_id, flags, requested, configuration));
3929 pcfg1Data->RequestedParameters = cpu_to_le32(requested);
3930 pcfg1Data->Reserved = 0;
3931 pcfg1Data->Configuration = cpu_to_le32(configuration);
3932 cfg.pageAddr = (vtarget->bus_id<<8) | vtarget->target_id;
3933 mpt_config(hd->ioc, &cfg);
3934 }
3935
3936 if (pcfg1Data)
3937 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr);
3938}
3939
3940/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3941/**
3942 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3943 * @hd: Pointer to a SCSI HOST structure
3944 * @vtarget: per device private data
3945 * @lun: lun
3946 *
3947 * Uses the ISR, but with special processing.
3948 * MUST be single-threaded.
3949 *
3950 */
3951static void
3952mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3953{
3954 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955
3956 /* Following parameters will not change
3957 * in this routine.
3958 */
3959 iocmd.cmd = SYNCHRONIZE_CACHE;
3960 iocmd.flags = 0;
3961 iocmd.physDiskNum = -1;
3962 iocmd.data = NULL;
3963 iocmd.data_dma = -1;
3964 iocmd.size = 0;
3965 iocmd.rsvd = iocmd.rsvd2 = 0;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003966 iocmd.bus = vdevice->bus_id;
3967 iocmd.id = vdevice->target_id;
3968 iocmd.lun = (u8)vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003970 if ((vdevice->vtarget->type & TYPE_DISK) &&
3971 (vdevice->configured_lun))
3972 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973}
3974
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07003975/* Search IOC page 3 to determine if this is hidden physical disk
3976 */
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07003977static int
3978mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
3979{
3980 int i;
3981
3982 if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
3983 return 0;
3984
3985 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
3986 if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
3987 return 1;
3988 }
3989
3990 return 0;
3991}
3992
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
3994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3995/**
3996 * mptscsih_domainValidation - Top level handler for domain validation.
3997 * @hd: Pointer to MPT_SCSI_HOST structure.
3998 *
3999 * Uses the ISR, but with special processing.
4000 * Called from schedule, should not be in interrupt mode.
4001 * While thread alive, do dv for all devices needing dv
4002 *
4003 * Return: None.
4004 */
4005static void
4006mptscsih_domainValidation(void *arg)
4007{
4008 MPT_SCSI_HOST *hd;
4009 MPT_ADAPTER *ioc;
4010 unsigned long flags;
4011 int id, maxid, dvStatus, did;
4012 int ii, isPhysDisk;
4013
4014 spin_lock_irqsave(&dvtaskQ_lock, flags);
4015 dvtaskQ_active = 1;
4016 if (dvtaskQ_release) {
4017 dvtaskQ_active = 0;
4018 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4019 return;
4020 }
4021 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4022
4023 /* For this ioc, loop through all devices and do dv to each device.
4024 * When complete with this ioc, search through the ioc list, and
4025 * for each scsi ioc found, do dv for all devices. Exit when no
4026 * device needs dv.
4027 */
4028 did = 1;
4029 while (did) {
4030 did = 0;
4031 list_for_each_entry(ioc, &ioc_list, list) {
4032 spin_lock_irqsave(&dvtaskQ_lock, flags);
4033 if (dvtaskQ_release) {
4034 dvtaskQ_active = 0;
4035 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4036 return;
4037 }
4038 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4039
4040 msleep(250);
4041
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004042 /* DV only to SPI adapters */
4043 if (ioc->bus_type != SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 continue;
4045
4046 /* Make sure everything looks ok */
4047 if (ioc->sh == NULL)
4048 continue;
4049
4050 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
4051 if (hd == NULL)
4052 continue;
4053
4054 if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
4055 mpt_read_ioc_pg_3(ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004056 if (ioc->raid_data.pIocPg3) {
4057 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4058 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059
4060 while (numPDisk) {
4061 if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
4062 ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
4063
4064 pPDisk++;
4065 numPDisk--;
4066 }
4067 }
4068 ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
4069 }
4070
4071 maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
4072
4073 for (id = 0; id < maxid; id++) {
4074 spin_lock_irqsave(&dvtaskQ_lock, flags);
4075 if (dvtaskQ_release) {
4076 dvtaskQ_active = 0;
4077 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4078 return;
4079 }
4080 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4081 dvStatus = hd->ioc->spi_data.dvStatus[id];
4082
4083 if (dvStatus & MPT_SCSICFG_NEED_DV) {
4084 did++;
4085 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
4086 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
4087
4088 msleep(250);
4089
4090 /* If hidden phys disk, block IO's to all
4091 * raid volumes
4092 * else, process normally
4093 */
4094 isPhysDisk = mptscsih_is_phys_disk(ioc, id);
4095 if (isPhysDisk) {
4096 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004097 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
4099 }
4100 }
4101 }
4102
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004103 if(mpt_alt_ioc_wait(hd->ioc)!=0) {
4104 ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
4105 hd->ioc->name));
4106 continue;
4107 }
4108
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 if (mptscsih_doDv(hd, 0, id) == 1) {
4110 /* Untagged device was busy, try again
4111 */
4112 hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
4113 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
4114 } else {
4115 /* DV is complete. Clear flags.
4116 */
4117 hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
4118 }
4119
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07004120 spin_lock(&hd->ioc->initializing_hba_lock);
4121 hd->ioc->initializing_hba_lock_flag=0;
4122 spin_unlock(&hd->ioc->initializing_hba_lock);
4123
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 if (isPhysDisk) {
4125 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004126 if (hd->ioc->raid_data.isRaid & (1 << ii)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
4128 }
4129 }
4130 }
4131
4132 if (hd->ioc->spi_data.noQas)
4133 mptscsih_qas_check(hd, id);
4134 }
4135 }
4136 }
4137 }
4138
4139 spin_lock_irqsave(&dvtaskQ_lock, flags);
4140 dvtaskQ_active = 0;
4141 spin_unlock_irqrestore(&dvtaskQ_lock, flags);
4142
4143 return;
4144}
4145
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146/* Write SDP1 if no QAS has been enabled
4147 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004148static void
4149mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004151 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 int ii;
4153
4154 if (hd->Targets == NULL)
4155 return;
4156
4157 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4158 if (ii == id)
4159 continue;
4160
4161 if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
4162 continue;
4163
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004164 vtarget = hd->Targets[ii];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004166 if ((vtarget != NULL) && (!vtarget->raidVolume)) {
4167 if ((vtarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
4168 vtarget->negoFlags |= hd->ioc->spi_data.noQas;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
4170 mptscsih_writeSDP1(hd, 0, ii, 0);
4171 }
4172 } else {
4173 if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
4174 dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
4175 mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
4176 }
4177 }
4178 }
4179 return;
4180}
4181
4182
4183
4184#define MPT_GET_NVRAM_VALS 0x01
4185#define MPT_UPDATE_MAX 0x02
4186#define MPT_SET_MAX 0x04
4187#define MPT_SET_MIN 0x08
4188#define MPT_FALLBACK 0x10
4189#define MPT_SAVE 0x20
4190
4191/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4192/**
4193 * mptscsih_doDv - Perform domain validation to a target.
4194 * @hd: Pointer to MPT_SCSI_HOST structure.
4195 * @portnum: IOC port number.
4196 * @target: Physical ID of this target
4197 *
4198 * Uses the ISR, but with special processing.
4199 * MUST be single-threaded.
4200 * Test will exit if target is at async & narrow.
4201 *
4202 * Return: None.
4203 */
4204static int
4205mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
4206{
4207 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004208 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 SCSIDevicePage1_t *pcfg1Data;
4210 SCSIDevicePage0_t *pcfg0Data;
4211 u8 *pbuf1;
4212 u8 *pbuf2;
4213 u8 *pDvBuf;
4214 dma_addr_t dvbuf_dma = -1;
4215 dma_addr_t buf1_dma = -1;
4216 dma_addr_t buf2_dma = -1;
4217 dma_addr_t cfg1_dma_addr = -1;
4218 dma_addr_t cfg0_dma_addr = -1;
4219 ConfigPageHeader_t header1;
4220 ConfigPageHeader_t header0;
4221 DVPARAMETERS dv;
4222 INTERNAL_CMD iocmd;
4223 CONFIGPARMS cfg;
4224 int dv_alloc = 0;
4225 int rc, sz = 0;
4226 int bufsize = 0;
4227 int dataBufSize = 0;
4228 int echoBufSize = 0;
4229 int notDone;
4230 int patt;
4231 int repeat;
4232 int retcode = 0;
4233 int nfactor = MPT_ULTRA320;
4234 char firstPass = 1;
4235 char doFallback = 0;
4236 char readPage0;
4237 char bus, lun;
4238 char inq0 = 0;
4239
4240 if (ioc->spi_data.sdp1length == 0)
4241 return 0;
4242
4243 if (ioc->spi_data.sdp0length == 0)
4244 return 0;
4245
4246 /* If multiple buses are used, require that the initiator
4247 * id be the same on all buses.
4248 */
4249 if (id == ioc->pfacts[0].PortSCSIID)
4250 return 0;
4251
4252 lun = 0;
4253 bus = (u8) bus_number;
4254 ddvtprintk((MYIOC_s_NOTE_FMT
4255 "DV started: bus=%d, id=%d dv @ %p\n",
4256 ioc->name, bus, id, &dv));
4257
4258 /* Prep DV structure
4259 */
4260 memset (&dv, 0, sizeof(DVPARAMETERS));
4261 dv.id = id;
4262
4263 /* Populate tmax with the current maximum
4264 * transfer parameters for this target.
4265 * Exit if narrow and async.
4266 */
4267 dv.cmd = MPT_GET_NVRAM_VALS;
4268 mptscsih_dv_parms(hd, &dv, NULL);
4269
4270 /* Prep SCSI IO structure
4271 */
4272 iocmd.id = id;
4273 iocmd.bus = bus;
4274 iocmd.lun = lun;
4275 iocmd.flags = 0;
4276 iocmd.physDiskNum = -1;
4277 iocmd.rsvd = iocmd.rsvd2 = 0;
4278
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004279 vtarget = hd->Targets[id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
4281 /* Use tagged commands if possible.
4282 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004283 if (vtarget) {
4284 if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
4286 else {
4287 if (hd->ioc->facts.FWVersion.Word < 0x01000600)
4288 return 0;
4289
4290 if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4291 (hd->ioc->facts.FWVersion.Word < 0x01010B00))
4292 return 0;
4293 }
4294 }
4295
4296 /* Prep cfg structure
4297 */
4298 cfg.pageAddr = (bus<<8) | id;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004299 cfg.cfghdr.hdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
4301 /* Prep SDP0 header
4302 */
4303 header0.PageVersion = ioc->spi_data.sdp0version;
4304 header0.PageLength = ioc->spi_data.sdp0length;
4305 header0.PageNumber = 0;
4306 header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4307
4308 /* Prep SDP1 header
4309 */
4310 header1.PageVersion = ioc->spi_data.sdp1version;
4311 header1.PageLength = ioc->spi_data.sdp1length;
4312 header1.PageNumber = 1;
4313 header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4314
4315 if (header0.PageLength & 1)
4316 dv_alloc = (header0.PageLength * 4) + 4;
4317
4318 dv_alloc += (2048 + (header1.PageLength * 4));
4319
4320 pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
4321 if (pDvBuf == NULL)
4322 return 0;
4323
4324 sz = 0;
4325 pbuf1 = (u8 *)pDvBuf;
4326 buf1_dma = dvbuf_dma;
4327 sz +=1024;
4328
4329 pbuf2 = (u8 *) (pDvBuf + sz);
4330 buf2_dma = dvbuf_dma + sz;
4331 sz +=1024;
4332
4333 pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
4334 cfg0_dma_addr = dvbuf_dma + sz;
4335 sz += header0.PageLength * 4;
4336
4337 /* 8-byte alignment
4338 */
4339 if (header0.PageLength & 1)
4340 sz += 4;
4341
4342 pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
4343 cfg1_dma_addr = dvbuf_dma + sz;
4344
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004345 /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 */
4347 {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004348 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
4350 /* Set the factor from nvram */
4351 nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
4352 if (nfactor < pspi_data->minSyncFactor )
4353 nfactor = pspi_data->minSyncFactor;
4354
4355 if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
4356 (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
4357
4358 ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
4359 ioc->name, bus, id, lun));
4360
4361 dv.cmd = MPT_SET_MAX;
4362 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004363 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
4365 /* Save the final negotiated settings to
4366 * SCSI device page 1.
4367 */
4368 cfg.physAddr = cfg1_dma_addr;
4369 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4370 cfg.dir = 1;
4371 mpt_config(hd->ioc, &cfg);
4372 goto target_done;
4373 }
4374 }
4375 }
4376
4377 /* Finish iocmd inititialization - hidden or visible disk? */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004378 if (ioc->raid_data.pIocPg3) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 /* Search IOC page 3 for matching id
4380 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004381 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
4382 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383
4384 while (numPDisk) {
4385 if (pPDisk->PhysDiskID == id) {
4386 /* match */
4387 iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
4388 iocmd.physDiskNum = pPDisk->PhysDiskNum;
4389
4390 /* Quiesce the IM
4391 */
4392 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
4393 ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
4394 goto target_done;
4395 }
4396 break;
4397 }
4398 pPDisk++;
4399 numPDisk--;
4400 }
4401 }
4402
4403 /* RAID Volume ID's may double for a physical device. If RAID but
4404 * not a physical ID as well, skip DV.
4405 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004406 if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 goto target_done;
4408
4409
4410 /* Basic Test.
4411 * Async & Narrow - Inquiry
4412 * Async & Narrow - Inquiry
4413 * Maximum transfer rate - Inquiry
4414 * Compare buffers:
4415 * If compare, test complete.
4416 * If miscompare and first pass, repeat
4417 * If miscompare and not first pass, fall back and repeat
4418 */
4419 hd->pLocal = NULL;
4420 readPage0 = 0;
4421 sz = SCSI_MAX_INQUIRY_BYTES;
4422 rc = MPT_SCANDV_GOOD;
4423 while (1) {
4424 ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
4425 retcode = 0;
4426 dv.cmd = MPT_SET_MIN;
4427 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4428
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004429 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 cfg.physAddr = cfg1_dma_addr;
4431 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4432 cfg.dir = 1;
4433 if (mpt_config(hd->ioc, &cfg) != 0)
4434 goto target_done;
4435
4436 /* Wide - narrow - wide workaround case
4437 */
4438 if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
4439 /* Send an untagged command to reset disk Qs corrupted
4440 * when a parity error occurs on a Request Sense.
4441 */
4442 if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
4443 ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
4444 (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
4445
4446 iocmd.cmd = REQUEST_SENSE;
4447 iocmd.data_dma = buf1_dma;
4448 iocmd.data = pbuf1;
4449 iocmd.size = 0x12;
4450 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4451 goto target_done;
4452 else {
4453 if (hd->pLocal == NULL)
4454 goto target_done;
4455 rc = hd->pLocal->completion;
4456 if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
4457 dv.max.width = 0;
4458 doFallback = 0;
4459 } else
4460 goto target_done;
4461 }
4462 } else
4463 goto target_done;
4464 }
4465
4466 iocmd.cmd = INQUIRY;
4467 iocmd.data_dma = buf1_dma;
4468 iocmd.data = pbuf1;
4469 iocmd.size = sz;
4470 memset(pbuf1, 0x00, sz);
4471 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4472 goto target_done;
4473 else {
4474 if (hd->pLocal == NULL)
4475 goto target_done;
4476 rc = hd->pLocal->completion;
4477 if (rc == MPT_SCANDV_GOOD) {
4478 if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
4479 if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
4480 retcode = 1;
4481 else
4482 retcode = 0;
4483
4484 goto target_done;
4485 }
4486 } else if (rc == MPT_SCANDV_SENSE) {
4487 ;
4488 } else {
4489 /* If first command doesn't complete
4490 * with a good status or with a check condition,
4491 * exit.
4492 */
4493 goto target_done;
4494 }
4495 }
4496
4497 /* Reset the size for disks
4498 */
4499 inq0 = (*pbuf1) & 0x1F;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004500 if ((inq0 == 0) && vtarget && !vtarget->raidVolume) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 sz = 0x40;
4502 iocmd.size = sz;
4503 }
4504
4505 /* Another GEM workaround. Check peripheral device type,
4506 * if PROCESSOR, quit DV.
4507 */
4508 if (inq0 == TYPE_PROCESSOR) {
4509 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004510 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 lun,
4512 pbuf1,
4513 sz);
4514 goto target_done;
4515 }
4516
4517 if (inq0 > 0x08)
4518 goto target_done;
4519
4520 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4521 goto target_done;
4522
4523 if (sz == 0x40) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004524 if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A)
4525 && (vtarget->minSyncFactor > 0x09)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 if ((pbuf1[56] & 0x04) == 0)
4527 ;
4528 else if ((pbuf1[56] & 0x01) == 1) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004529 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
4531 } else {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004532 vtarget->minSyncFactor =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
4534 }
4535
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004536 dv.max.factor = vtarget->minSyncFactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537
4538 if ((pbuf1[56] & 0x02) == 0) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004539 vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004541 ddvprintk((MYIOC_s_NOTE_FMT
4542 "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 ioc->name, id, pbuf1[56]));
4544 }
4545 }
4546 }
4547
4548 if (doFallback)
4549 dv.cmd = MPT_FALLBACK;
4550 else
4551 dv.cmd = MPT_SET_MAX;
4552
4553 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4554 if (mpt_config(hd->ioc, &cfg) != 0)
4555 goto target_done;
4556
4557 if ((!dv.now.width) && (!dv.now.offset))
4558 goto target_done;
4559
4560 iocmd.cmd = INQUIRY;
4561 iocmd.data_dma = buf2_dma;
4562 iocmd.data = pbuf2;
4563 iocmd.size = sz;
4564 memset(pbuf2, 0x00, sz);
4565 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4566 goto target_done;
4567 else if (hd->pLocal == NULL)
4568 goto target_done;
4569 else {
4570 /* Save the return code.
4571 * If this is the first pass,
4572 * read SCSI Device Page 0
4573 * and update the target max parameters.
4574 */
4575 rc = hd->pLocal->completion;
4576 doFallback = 0;
4577 if (rc == MPT_SCANDV_GOOD) {
4578 if (!readPage0) {
4579 u32 sdp0_info;
4580 u32 sdp0_nego;
4581
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004582 cfg.cfghdr.hdr = &header0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 cfg.physAddr = cfg0_dma_addr;
4584 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4585 cfg.dir = 0;
4586
4587 if (mpt_config(hd->ioc, &cfg) != 0)
4588 goto target_done;
4589
4590 sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
4591 sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
4592
4593 /* Quantum and Fujitsu workarounds.
4594 * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
4595 * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
4596 * Resetart with a request for U160.
4597 */
4598 if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
4599 doFallback = 1;
4600 } else {
4601 dv.cmd = MPT_UPDATE_MAX;
4602 mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
4603 /* Update the SCSI device page 1 area
4604 */
4605 pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
4606 readPage0 = 1;
4607 }
4608 }
4609
4610 /* Quantum workaround. Restart this test will the fallback
4611 * flag set.
4612 */
4613 if (doFallback == 0) {
4614 if (memcmp(pbuf1, pbuf2, sz) != 0) {
4615 if (!firstPass)
4616 doFallback = 1;
4617 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004618 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
4620 hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
4621 mptscsih_initTarget(hd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07004622 vtarget,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 lun,
4624 pbuf1,
4625 sz);
4626 break; /* test complete */
4627 }
4628 }
4629
4630
4631 } else if (rc == MPT_SCANDV_ISSUE_SENSE)
4632 doFallback = 1; /* set fallback flag */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004633 else if ((rc == MPT_SCANDV_DID_RESET) ||
4634 (rc == MPT_SCANDV_SENSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 (rc == MPT_SCANDV_FALLBACK))
4636 doFallback = 1; /* set fallback flag */
4637 else
4638 goto target_done;
4639
4640 firstPass = 0;
4641 }
4642 }
4643 ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
4644
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04004645 if (ioc->spi_data.mpt_dv == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 goto target_done;
4647
4648 inq0 = (*pbuf1) & 0x1F;
4649
4650 /* Continue only for disks
4651 */
4652 if (inq0 != 0)
4653 goto target_done;
4654
4655 if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
4656 goto target_done;
4657
4658 /* Start the Enhanced Test.
4659 * 0) issue TUR to clear out check conditions
4660 * 1) read capacity of echo (regular) buffer
4661 * 2) reserve device
4662 * 3) do write-read-compare data pattern test
4663 * 4) release
4664 * 5) update nego parms to target struct
4665 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004666 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 cfg.physAddr = cfg1_dma_addr;
4668 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4669 cfg.dir = 1;
4670
4671 iocmd.cmd = TEST_UNIT_READY;
4672 iocmd.data_dma = -1;
4673 iocmd.data = NULL;
4674 iocmd.size = 0;
4675 notDone = 1;
4676 while (notDone) {
4677 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4678 goto target_done;
4679
4680 if (hd->pLocal == NULL)
4681 goto target_done;
4682
4683 rc = hd->pLocal->completion;
4684 if (rc == MPT_SCANDV_GOOD)
4685 notDone = 0;
4686 else if (rc == MPT_SCANDV_SENSE) {
4687 u8 skey = hd->pLocal->sense[2] & 0x0F;
4688 u8 asc = hd->pLocal->sense[12];
4689 u8 ascq = hd->pLocal->sense[13];
4690 ddvprintk((MYIOC_s_INFO_FMT
4691 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4692 ioc->name, skey, asc, ascq));
4693
4694 if (skey == UNIT_ATTENTION)
4695 notDone++; /* repeat */
4696 else if ((skey == NOT_READY) &&
4697 (asc == 0x04)&&(ascq == 0x01)) {
4698 /* wait then repeat */
4699 mdelay (2000);
4700 notDone++;
4701 } else if ((skey == NOT_READY) && (asc == 0x3A)) {
4702 /* no medium, try read test anyway */
4703 notDone = 0;
4704 } else {
4705 /* All other errors are fatal.
4706 */
4707 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4708 ioc->name));
4709 goto target_done;
4710 }
4711 } else
4712 goto target_done;
4713 }
4714
4715 iocmd.cmd = READ_BUFFER;
4716 iocmd.data_dma = buf1_dma;
4717 iocmd.data = pbuf1;
4718 iocmd.size = 4;
4719 iocmd.flags |= MPT_ICFLAG_BUF_CAP;
4720
4721 dataBufSize = 0;
4722 echoBufSize = 0;
4723 for (patt = 0; patt < 2; patt++) {
4724 if (patt == 0)
4725 iocmd.flags |= MPT_ICFLAG_ECHO;
4726 else
4727 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4728
4729 notDone = 1;
4730 while (notDone) {
4731 bufsize = 0;
4732
4733 /* If not ready after 8 trials,
4734 * give up on this device.
4735 */
4736 if (notDone > 8)
4737 goto target_done;
4738
4739 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4740 goto target_done;
4741 else if (hd->pLocal == NULL)
4742 goto target_done;
4743 else {
4744 rc = hd->pLocal->completion;
4745 ddvprintk(("ReadBuffer Comp Code %d", rc));
4746 ddvprintk((" buff: %0x %0x %0x %0x\n",
4747 pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
4748
4749 if (rc == MPT_SCANDV_GOOD) {
4750 notDone = 0;
4751 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4752 bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004753 if (pbuf1[0] & 0x01)
4754 iocmd.flags |= MPT_ICFLAG_EBOS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 } else {
4756 bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
4757 }
4758 } else if (rc == MPT_SCANDV_SENSE) {
4759 u8 skey = hd->pLocal->sense[2] & 0x0F;
4760 u8 asc = hd->pLocal->sense[12];
4761 u8 ascq = hd->pLocal->sense[13];
4762 ddvprintk((MYIOC_s_INFO_FMT
4763 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4764 ioc->name, skey, asc, ascq));
4765 if (skey == ILLEGAL_REQUEST) {
4766 notDone = 0;
4767 } else if (skey == UNIT_ATTENTION) {
4768 notDone++; /* repeat */
4769 } else if ((skey == NOT_READY) &&
4770 (asc == 0x04)&&(ascq == 0x01)) {
4771 /* wait then repeat */
4772 mdelay (2000);
4773 notDone++;
4774 } else {
4775 /* All other errors are fatal.
4776 */
4777 ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
4778 ioc->name));
4779 goto target_done;
4780 }
4781 } else {
4782 /* All other errors are fatal
4783 */
4784 goto target_done;
4785 }
4786 }
4787 }
4788
4789 if (iocmd.flags & MPT_ICFLAG_ECHO)
4790 echoBufSize = bufsize;
4791 else
4792 dataBufSize = bufsize;
4793 }
4794 sz = 0;
4795 iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
4796
4797 /* Use echo buffers if possible,
4798 * Exit if both buffers are 0.
4799 */
4800 if (echoBufSize > 0) {
4801 iocmd.flags |= MPT_ICFLAG_ECHO;
4802 if (dataBufSize > 0)
4803 bufsize = min(echoBufSize, dataBufSize);
4804 else
4805 bufsize = echoBufSize;
4806 } else if (dataBufSize == 0)
4807 goto target_done;
4808
4809 ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
4810 (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
4811
4812 /* Data buffers for write-read-compare test max 1K.
4813 */
4814 sz = min(bufsize, 1024);
4815
4816 /* --- loop ----
4817 * On first pass, always issue a reserve.
4818 * On additional loops, only if a reset has occurred.
4819 * iocmd.flags indicates if echo or regular buffer
4820 */
4821 for (patt = 0; patt < 4; patt++) {
4822 ddvprintk(("Pattern %d\n", patt));
4823 if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
4824 iocmd.cmd = TEST_UNIT_READY;
4825 iocmd.data_dma = -1;
4826 iocmd.data = NULL;
4827 iocmd.size = 0;
4828 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4829 goto target_done;
4830
4831 iocmd.cmd = RELEASE;
4832 iocmd.data_dma = -1;
4833 iocmd.data = NULL;
4834 iocmd.size = 0;
4835 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4836 goto target_done;
4837 else if (hd->pLocal == NULL)
4838 goto target_done;
4839 else {
4840 rc = hd->pLocal->completion;
4841 ddvprintk(("Release rc %d\n", rc));
4842 if (rc == MPT_SCANDV_GOOD)
4843 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4844 else
4845 goto target_done;
4846 }
4847 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
4848 }
4849 iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
4850
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004851 if (iocmd.flags & MPT_ICFLAG_EBOS)
4852 goto skip_Reserve;
4853
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 repeat = 5;
4855 while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
4856 iocmd.cmd = RESERVE;
4857 iocmd.data_dma = -1;
4858 iocmd.data = NULL;
4859 iocmd.size = 0;
4860 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4861 goto target_done;
4862 else if (hd->pLocal == NULL)
4863 goto target_done;
4864 else {
4865 rc = hd->pLocal->completion;
4866 if (rc == MPT_SCANDV_GOOD) {
4867 iocmd.flags |= MPT_ICFLAG_RESERVED;
4868 } else if (rc == MPT_SCANDV_SENSE) {
4869 /* Wait if coming ready
4870 */
4871 u8 skey = hd->pLocal->sense[2] & 0x0F;
4872 u8 asc = hd->pLocal->sense[12];
4873 u8 ascq = hd->pLocal->sense[13];
4874 ddvprintk((MYIOC_s_INFO_FMT
4875 "DV: Reserve Failed: ", ioc->name));
4876 ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
4877 skey, asc, ascq));
4878
4879 if ((skey == NOT_READY) && (asc == 0x04)&&
4880 (ascq == 0x01)) {
4881 /* wait then repeat */
4882 mdelay (2000);
4883 notDone++;
4884 } else {
4885 ddvprintk((MYIOC_s_INFO_FMT
4886 "DV: Reserved Failed.", ioc->name));
4887 goto target_done;
4888 }
4889 } else {
4890 ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
4891 ioc->name));
4892 goto target_done;
4893 }
4894 }
4895 }
4896
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004897skip_Reserve:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 mptscsih_fillbuf(pbuf1, sz, patt, 1);
4899 iocmd.cmd = WRITE_BUFFER;
4900 iocmd.data_dma = buf1_dma;
4901 iocmd.data = pbuf1;
4902 iocmd.size = sz;
4903 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4904 goto target_done;
4905 else if (hd->pLocal == NULL)
4906 goto target_done;
4907 else {
4908 rc = hd->pLocal->completion;
4909 if (rc == MPT_SCANDV_GOOD)
4910 ; /* Issue read buffer */
4911 else if (rc == MPT_SCANDV_DID_RESET) {
4912 /* If using echo buffers, reset to data buffers.
4913 * Else do Fallback and restart
4914 * this test (re-issue reserve
4915 * because of bus reset).
4916 */
4917 if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
4918 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4919 } else {
4920 dv.cmd = MPT_FALLBACK;
4921 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
4922
4923 if (mpt_config(hd->ioc, &cfg) != 0)
4924 goto target_done;
4925
4926 if ((!dv.now.width) && (!dv.now.offset))
4927 goto target_done;
4928 }
4929
4930 iocmd.flags |= MPT_ICFLAG_DID_RESET;
4931 patt = -1;
4932 continue;
4933 } else if (rc == MPT_SCANDV_SENSE) {
4934 /* Restart data test if UA, else quit.
4935 */
4936 u8 skey = hd->pLocal->sense[2] & 0x0F;
4937 ddvprintk((MYIOC_s_INFO_FMT
4938 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
4939 hd->pLocal->sense[12], hd->pLocal->sense[13]));
4940 if (skey == UNIT_ATTENTION) {
4941 patt = -1;
4942 continue;
4943 } else if (skey == ILLEGAL_REQUEST) {
4944 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4945 if (dataBufSize >= bufsize) {
4946 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4947 patt = -1;
4948 continue;
4949 }
4950 }
4951 goto target_done;
4952 }
4953 else
4954 goto target_done;
4955 } else {
4956 /* fatal error */
4957 goto target_done;
4958 }
4959 }
4960
4961 iocmd.cmd = READ_BUFFER;
4962 iocmd.data_dma = buf2_dma;
4963 iocmd.data = pbuf2;
4964 iocmd.size = sz;
4965 if (mptscsih_do_cmd(hd, &iocmd) < 0)
4966 goto target_done;
4967 else if (hd->pLocal == NULL)
4968 goto target_done;
4969 else {
4970 rc = hd->pLocal->completion;
4971 if (rc == MPT_SCANDV_GOOD) {
4972 /* If buffers compare,
4973 * go to next pattern,
4974 * else, do a fallback and restart
4975 * data transfer test.
4976 */
4977 if (memcmp (pbuf1, pbuf2, sz) == 0) {
4978 ; /* goto next pattern */
4979 } else {
4980 /* Miscompare with Echo buffer, go to data buffer,
4981 * if that buffer exists.
4982 * Miscompare with Data buffer, check first 4 bytes,
4983 * some devices return capacity. Exit in this case.
4984 */
4985 if (iocmd.flags & MPT_ICFLAG_ECHO) {
4986 if (dataBufSize >= bufsize)
4987 iocmd.flags &= ~MPT_ICFLAG_ECHO;
4988 else
4989 goto target_done;
4990 } else {
4991 if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
4992 /* Argh. Device returning wrong data.
4993 * Quit DV for this device.
4994 */
4995 goto target_done;
4996 }
4997
4998 /* Had an actual miscompare. Slow down.*/
4999 dv.cmd = MPT_FALLBACK;
5000 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5001
5002 if (mpt_config(hd->ioc, &cfg) != 0)
5003 goto target_done;
5004
5005 if ((!dv.now.width) && (!dv.now.offset))
5006 goto target_done;
5007 }
5008
5009 patt = -1;
5010 continue;
5011 }
5012 } else if (rc == MPT_SCANDV_DID_RESET) {
5013 /* Do Fallback and restart
5014 * this test (re-issue reserve
5015 * because of bus reset).
5016 */
5017 dv.cmd = MPT_FALLBACK;
5018 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5019
5020 if (mpt_config(hd->ioc, &cfg) != 0)
5021 goto target_done;
5022
5023 if ((!dv.now.width) && (!dv.now.offset))
5024 goto target_done;
5025
5026 iocmd.flags |= MPT_ICFLAG_DID_RESET;
5027 patt = -1;
5028 continue;
5029 } else if (rc == MPT_SCANDV_SENSE) {
5030 /* Restart data test if UA, else quit.
5031 */
5032 u8 skey = hd->pLocal->sense[2] & 0x0F;
5033 ddvprintk((MYIOC_s_INFO_FMT
5034 "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
5035 hd->pLocal->sense[12], hd->pLocal->sense[13]));
5036 if (skey == UNIT_ATTENTION) {
5037 patt = -1;
5038 continue;
5039 }
5040 else
5041 goto target_done;
5042 } else {
5043 /* fatal error */
5044 goto target_done;
5045 }
5046 }
5047
5048 } /* --- end of patt loop ---- */
5049
5050target_done:
5051 if (iocmd.flags & MPT_ICFLAG_RESERVED) {
5052 iocmd.cmd = RELEASE;
5053 iocmd.data_dma = -1;
5054 iocmd.data = NULL;
5055 iocmd.size = 0;
5056 if (mptscsih_do_cmd(hd, &iocmd) < 0)
5057 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5058 ioc->name, id);
5059 else if (hd->pLocal) {
5060 if (hd->pLocal->completion == MPT_SCANDV_GOOD)
5061 iocmd.flags &= ~MPT_ICFLAG_RESERVED;
5062 } else {
5063 printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
5064 ioc->name, id);
5065 }
5066 }
5067
5068
5069 /* Set if cfg1_dma_addr contents is valid
5070 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005071 if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 /* If disk, not U320, disable QAS
5073 */
5074 if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
5075 hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005076 ddvprintk((MYIOC_s_NOTE_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
5078 }
5079
5080 dv.cmd = MPT_SAVE;
5081 mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
5082
5083 /* Double writes to SDP1 can cause problems,
5084 * skip save of the final negotiated settings to
5085 * SCSI device page 1.
5086 *
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005087 cfg.cfghdr.hdr = &header1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 cfg.physAddr = cfg1_dma_addr;
5089 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5090 cfg.dir = 1;
5091 mpt_config(hd->ioc, &cfg);
5092 */
5093 }
5094
5095 /* If this is a RAID Passthrough, enable internal IOs
5096 */
5097 if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
5098 if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
5099 ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
5100 }
5101
5102 /* Done with the DV scan of the current target
5103 */
5104 if (pDvBuf)
5105 pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
5106
5107 ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
5108 ioc->name, id));
5109
5110 return retcode;
5111}
5112
5113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5114/* mptscsih_dv_parms - perform a variety of operations on the
5115 * parameters used for negotiation.
5116 * @hd: Pointer to a SCSI host.
5117 * @dv: Pointer to a structure that contains the maximum and current
5118 * negotiated parameters.
5119 */
5120static void
5121mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
5122{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005123 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 SCSIDevicePage0_t *pPage0;
5125 SCSIDevicePage1_t *pPage1;
5126 int val = 0, data, configuration;
5127 u8 width = 0;
5128 u8 offset = 0;
5129 u8 factor = 0;
5130 u8 negoFlags = 0;
5131 u8 cmd = dv->cmd;
5132 u8 id = dv->id;
5133
5134 switch (cmd) {
5135 case MPT_GET_NVRAM_VALS:
5136 ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
5137 hd->ioc->name));
5138 /* Get the NVRAM values and save in tmax
5139 * If not an LVD bus, the adapter minSyncFactor has been
5140 * already throttled back.
5141 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005142 negoFlags = hd->ioc->spi_data.noQas;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005143 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume) {
5144 width = vtarget->maxWidth;
5145 offset = vtarget->maxOffset;
5146 factor = vtarget->minSyncFactor;
5147 negoFlags |= vtarget->negoFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 } else {
5149 if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
5150 data = hd->ioc->spi_data.nvram[id];
5151 width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
5152 if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
5153 factor = MPT_ASYNC;
5154 else {
5155 factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
5156 if ((factor == 0) || (factor == MPT_ASYNC)){
5157 factor = MPT_ASYNC;
5158 offset = 0;
5159 }
5160 }
5161 } else {
5162 width = MPT_NARROW;
5163 offset = 0;
5164 factor = MPT_ASYNC;
5165 }
5166
5167 /* Set the negotiation flags */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 if (!width)
5169 negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
5170
5171 if (!offset)
5172 negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
5173 }
5174
5175 /* limit by adapter capabilities */
5176 width = min(width, hd->ioc->spi_data.maxBusWidth);
5177 offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
5178 factor = max(factor, hd->ioc->spi_data.minSyncFactor);
5179
5180 /* Check Consistency */
5181 if (offset && (factor < MPT_ULTRA2) && !width)
5182 factor = MPT_ULTRA2;
5183
5184 dv->max.width = width;
5185 dv->max.offset = offset;
5186 dv->max.factor = factor;
5187 dv->max.flags = negoFlags;
5188 ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
5189 id, width, factor, offset, negoFlags));
5190 break;
5191
5192 case MPT_UPDATE_MAX:
5193 ddvprintk((MYIOC_s_NOTE_FMT
5194 "Updating with SDP0 Data: ", hd->ioc->name));
5195 /* Update tmax values with those from Device Page 0.*/
5196 pPage0 = (SCSIDevicePage0_t *) pPage;
5197 if (pPage0) {
Christoph Hellwig637fa992005-08-18 16:25:44 +02005198 val = le32_to_cpu(pPage0->NegotiatedParameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
5200 dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
5201 dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
5202 }
5203
5204 dv->now.width = dv->max.width;
5205 dv->now.offset = dv->max.offset;
5206 dv->now.factor = dv->max.factor;
5207 ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
5208 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5209 break;
5210
5211 case MPT_SET_MAX:
5212 ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
5213 hd->ioc->name));
5214 /* Set current to the max values. Update the config page.*/
5215 dv->now.width = dv->max.width;
5216 dv->now.offset = dv->max.offset;
5217 dv->now.factor = dv->max.factor;
5218 dv->now.flags = dv->max.flags;
5219
5220 pPage1 = (SCSIDevicePage1_t *)pPage;
5221 if (pPage1) {
5222 mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
5223 dv->now.offset, &val, &configuration, dv->now.flags);
5224 dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5225 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005226 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005228 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 }
5230
Christoph Hellwig637fa992005-08-18 16:25:44 +02005231 ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
5233 break;
5234
5235 case MPT_SET_MIN:
5236 ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
5237 hd->ioc->name));
5238 /* Set page to asynchronous and narrow
5239 * Do not update now, breaks fallback routine. */
5240 width = MPT_NARROW;
5241 offset = 0;
5242 factor = MPT_ASYNC;
5243 negoFlags = dv->max.flags;
5244
5245 pPage1 = (SCSIDevicePage1_t *)pPage;
5246 if (pPage1) {
5247 mptscsih_setDevicePage1Flags (width, factor,
5248 offset, &val, &configuration, negoFlags);
5249 dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
5250 id, width, factor, offset, negoFlags, val, configuration));
Christoph Hellwig637fa992005-08-18 16:25:44 +02005251 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005253 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 }
5255 ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
5256 id, width, factor, offset, val, configuration, negoFlags));
5257 break;
5258
5259 case MPT_FALLBACK:
5260 ddvprintk((MYIOC_s_NOTE_FMT
5261 "Fallback: Start: offset %d, factor %x, width %d \n",
5262 hd->ioc->name, dv->now.offset,
5263 dv->now.factor, dv->now.width));
5264 width = dv->now.width;
5265 offset = dv->now.offset;
5266 factor = dv->now.factor;
5267 if ((offset) && (dv->max.width)) {
5268 if (factor < MPT_ULTRA160)
5269 factor = MPT_ULTRA160;
5270 else if (factor < MPT_ULTRA2) {
5271 factor = MPT_ULTRA2;
5272 width = MPT_WIDE;
5273 } else if ((factor == MPT_ULTRA2) && width) {
5274 factor = MPT_ULTRA2;
5275 width = MPT_NARROW;
5276 } else if (factor < MPT_ULTRA) {
5277 factor = MPT_ULTRA;
5278 width = MPT_WIDE;
5279 } else if ((factor == MPT_ULTRA) && width) {
5280 width = MPT_NARROW;
5281 } else if (factor < MPT_FAST) {
5282 factor = MPT_FAST;
5283 width = MPT_WIDE;
5284 } else if ((factor == MPT_FAST) && width) {
5285 factor = MPT_FAST;
5286 width = MPT_NARROW;
5287 } else if (factor < MPT_SCSI) {
5288 factor = MPT_SCSI;
5289 width = MPT_WIDE;
5290 } else if ((factor == MPT_SCSI) && width) {
5291 factor = MPT_SCSI;
5292 width = MPT_NARROW;
5293 } else {
5294 factor = MPT_ASYNC;
5295 offset = 0;
5296 }
5297
5298 } else if (offset) {
5299 width = MPT_NARROW;
5300 if (factor < MPT_ULTRA)
5301 factor = MPT_ULTRA;
5302 else if (factor < MPT_FAST)
5303 factor = MPT_FAST;
5304 else if (factor < MPT_SCSI)
5305 factor = MPT_SCSI;
5306 else {
5307 factor = MPT_ASYNC;
5308 offset = 0;
5309 }
5310
5311 } else {
5312 width = MPT_NARROW;
5313 factor = MPT_ASYNC;
5314 }
5315 dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
5316 dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
5317
5318 dv->now.width = width;
5319 dv->now.offset = offset;
5320 dv->now.factor = factor;
5321 dv->now.flags = dv->max.flags;
5322
5323 pPage1 = (SCSIDevicePage1_t *)pPage;
5324 if (pPage1) {
5325 mptscsih_setDevicePage1Flags (width, factor, offset, &val,
5326 &configuration, dv->now.flags);
Christoph Hellwig637fa992005-08-18 16:25:44 +02005327 dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 id, width, offset, factor, dv->now.flags, val, configuration));
5329
Christoph Hellwig637fa992005-08-18 16:25:44 +02005330 pPage1->RequestedParameters = cpu_to_le32(val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 pPage1->Reserved = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005332 pPage1->Configuration = cpu_to_le32(configuration);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 }
5334
5335 ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
5336 id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
5337 break;
5338
5339 case MPT_SAVE:
5340 ddvprintk((MYIOC_s_NOTE_FMT
5341 "Saving to Target structure: ", hd->ioc->name));
5342 ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
5343 id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
5344
5345 /* Save these values to target structures
5346 * or overwrite nvram (phys disks only).
5347 */
5348
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005349 if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume ) {
5350 vtarget->maxWidth = dv->now.width;
5351 vtarget->maxOffset = dv->now.offset;
5352 vtarget->minSyncFactor = dv->now.factor;
5353 vtarget->negoFlags = dv->now.flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 } else {
5355 /* Preserv all flags, use
5356 * read-modify-write algorithm
5357 */
5358 if (hd->ioc->spi_data.nvram) {
5359 data = hd->ioc->spi_data.nvram[id];
5360
5361 if (dv->now.width)
5362 data &= ~MPT_NVRAM_WIDE_DISABLE;
5363 else
5364 data |= MPT_NVRAM_WIDE_DISABLE;
5365
5366 if (!dv->now.offset)
5367 factor = MPT_ASYNC;
5368
5369 data &= ~MPT_NVRAM_SYNC_MASK;
5370 data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
5371
5372 hd->ioc->spi_data.nvram[id] = data;
5373 }
5374 }
5375 break;
5376 }
5377}
5378
5379/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5380/* mptscsih_fillbuf - fill a buffer with a special data pattern
5381 * cleanup. For bus scan only.
5382 *
5383 * @buffer: Pointer to data buffer to be filled.
5384 * @size: Number of bytes to fill
5385 * @index: Pattern index
5386 * @width: bus width, 0 (8 bits) or 1 (16 bits)
5387 */
5388static void
5389mptscsih_fillbuf(char *buffer, int size, int index, int width)
5390{
5391 char *ptr = buffer;
5392 int ii;
5393 char byte;
5394 short val;
5395
5396 switch (index) {
5397 case 0:
5398
5399 if (width) {
5400 /* Pattern: 0000 FFFF 0000 FFFF
5401 */
5402 for (ii=0; ii < size; ii++, ptr++) {
5403 if (ii & 0x02)
5404 *ptr = 0xFF;
5405 else
5406 *ptr = 0x00;
5407 }
5408 } else {
5409 /* Pattern: 00 FF 00 FF
5410 */
5411 for (ii=0; ii < size; ii++, ptr++) {
5412 if (ii & 0x01)
5413 *ptr = 0xFF;
5414 else
5415 *ptr = 0x00;
5416 }
5417 }
5418 break;
5419
5420 case 1:
5421 if (width) {
5422 /* Pattern: 5555 AAAA 5555 AAAA 5555
5423 */
5424 for (ii=0; ii < size; ii++, ptr++) {
5425 if (ii & 0x02)
5426 *ptr = 0xAA;
5427 else
5428 *ptr = 0x55;
5429 }
5430 } else {
5431 /* Pattern: 55 AA 55 AA 55
5432 */
5433 for (ii=0; ii < size; ii++, ptr++) {
5434 if (ii & 0x01)
5435 *ptr = 0xAA;
5436 else
5437 *ptr = 0x55;
5438 }
5439 }
5440 break;
5441
5442 case 2:
5443 /* Pattern: 00 01 02 03 04 05
5444 * ... FE FF 00 01..
5445 */
5446 for (ii=0; ii < size; ii++, ptr++)
5447 *ptr = (char) ii;
5448 break;
5449
5450 case 3:
5451 if (width) {
5452 /* Wide Pattern: FFFE 0001 FFFD 0002
5453 * ... 4000 DFFF 8000 EFFF
5454 */
5455 byte = 0;
5456 for (ii=0; ii < size/2; ii++) {
5457 /* Create the base pattern
5458 */
5459 val = (1 << byte);
5460 /* every 64 (0x40) bytes flip the pattern
5461 * since we fill 2 bytes / iteration,
5462 * test for ii = 0x20
5463 */
5464 if (ii & 0x20)
5465 val = ~(val);
5466
5467 if (ii & 0x01) {
5468 *ptr = (char)( (val & 0xFF00) >> 8);
5469 ptr++;
5470 *ptr = (char)(val & 0xFF);
5471 byte++;
5472 byte &= 0x0F;
5473 } else {
5474 val = ~val;
5475 *ptr = (char)( (val & 0xFF00) >> 8);
5476 ptr++;
5477 *ptr = (char)(val & 0xFF);
5478 }
5479
5480 ptr++;
5481 }
5482 } else {
5483 /* Narrow Pattern: FE 01 FD 02 FB 04
5484 * .. 7F 80 01 FE 02 FD ... 80 7F
5485 */
5486 byte = 0;
5487 for (ii=0; ii < size; ii++, ptr++) {
5488 /* Base pattern - first 32 bytes
5489 */
5490 if (ii & 0x01) {
5491 *ptr = (1 << byte);
5492 byte++;
5493 byte &= 0x07;
5494 } else {
5495 *ptr = (char) (~(1 << byte));
5496 }
5497
5498 /* Flip the pattern every 32 bytes
5499 */
5500 if (ii & 0x20)
5501 *ptr = ~(*ptr);
5502 }
5503 }
5504 break;
5505 }
5506}
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005507
5508/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5509/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
5510 * Else set the NEED_DV flag after Read Capacity Issued (disks)
5511 * or Mode Sense (cdroms).
5512 *
5513 * Tapes, initTarget will set this flag on completion of Inquiry command.
5514 * Called only if DV_NOT_DONE flag is set
5515 */
5516static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005517mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005518{
5519 MPT_ADAPTER *ioc = hd->ioc;
5520 u8 cmd;
5521 SpiCfgData *pSpi;
5522
5523 ddvtprintk((MYIOC_s_NOTE_FMT
5524 " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005525 hd->ioc->name, sc->device->id, sc->device->lun , hd->negoNvram, sc->cmnd[0]));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005526
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005527 if ((sc->device->lun != 0) || (hd->negoNvram != 0))
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005528 return;
5529
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005530 cmd = sc->cmnd[0];
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005531
5532 if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
5533 pSpi = &ioc->spi_data;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005534 if ((ioc->raid_data.isRaid & (1 << sc->device->id)) && ioc->raid_data.pIocPg3) {
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005535 /* Set NEED_DV for all hidden disks
5536 */
5537 Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5538 int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5539
5540 while (numPDisk) {
5541 pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
5542 ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
5543 pPDisk++;
5544 numPDisk--;
5545 }
5546 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005547 pSpi->dvStatus[sc->device->id] |= MPT_SCSICFG_NEED_DV;
5548 ddvtprintk(("NEED_DV set for visible disk id %d\n", sc->device->id));
Moore, Eric Deanf2ea8672005-11-16 18:54:23 -07005549 }
5550}
5551
5552/* mptscsih_raid_set_dv_flags()
5553 *
5554 * New or replaced disk. Set DV flag and schedule DV.
5555 */
5556static void
5557mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
5558{
5559 MPT_ADAPTER *ioc = hd->ioc;
5560 SpiCfgData *pSpi = &ioc->spi_data;
5561 Ioc3PhysDisk_t *pPDisk;
5562 int numPDisk;
5563
5564 if (hd->negoNvram != 0)
5565 return;
5566
5567 ddvtprintk(("DV requested for phys disk id %d\n", id));
5568 if (ioc->raid_data.pIocPg3) {
5569 pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
5570 numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
5571 while (numPDisk) {
5572 if (id == pPDisk->PhysDiskNum) {
5573 pSpi->dvStatus[pPDisk->PhysDiskID] =
5574 (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
5575 pSpi->forceDv = MPT_SCSICFG_NEED_DV;
5576 ddvtprintk(("NEED_DV set for phys disk id %d\n",
5577 pPDisk->PhysDiskID));
5578 break;
5579 }
5580 pPDisk++;
5581 numPDisk--;
5582 }
5583
5584 if (numPDisk == 0) {
5585 /* The physical disk that needs DV was not found
5586 * in the stored IOC Page 3. The driver must reload
5587 * this page. DV routine will set the NEED_DV flag for
5588 * all phys disks that have DV_NOT_DONE set.
5589 */
5590 pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
5591 ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
5592 }
5593 }
5594}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
5596
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005597EXPORT_SYMBOL(mptscsih_remove);
5598EXPORT_SYMBOL(mptscsih_shutdown);
5599#ifdef CONFIG_PM
5600EXPORT_SYMBOL(mptscsih_suspend);
5601EXPORT_SYMBOL(mptscsih_resume);
5602#endif
5603EXPORT_SYMBOL(mptscsih_proc_info);
5604EXPORT_SYMBOL(mptscsih_info);
5605EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005606EXPORT_SYMBOL(mptscsih_target_alloc);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005607EXPORT_SYMBOL(mptscsih_slave_alloc);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07005608EXPORT_SYMBOL(mptscsih_target_destroy);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005609EXPORT_SYMBOL(mptscsih_slave_destroy);
5610EXPORT_SYMBOL(mptscsih_slave_configure);
5611EXPORT_SYMBOL(mptscsih_abort);
5612EXPORT_SYMBOL(mptscsih_dev_reset);
5613EXPORT_SYMBOL(mptscsih_bus_reset);
5614EXPORT_SYMBOL(mptscsih_host_reset);
5615EXPORT_SYMBOL(mptscsih_bios_param);
5616EXPORT_SYMBOL(mptscsih_io_done);
5617EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
5618EXPORT_SYMBOL(mptscsih_scandv_complete);
5619EXPORT_SYMBOL(mptscsih_event_process);
5620EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06005621EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005622EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04005624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/