blob: f00c1003a7657118e5eeea7a6a780e59c918c687 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05306 * Copyright (c) 1999-2007 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/workqueue.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060063#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "mptbase.h"
66#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060067#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*
81 * Other private/forward protos...
82 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040083int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040085int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
88 SCSIIORequest_t *pReq, int req_idx);
89static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040090static 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 -070091static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
92static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -060093static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Eric Moore793955f2007-01-29 09:42:20 -070095static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040097int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
98int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400100int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700102static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400104void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700105void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400107int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
108int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#endif
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
114/**
115 * mptscsih_add_sge - Place a simple SGE at address pAddr.
116 * @pAddr: virtual address for SGE
117 * @flagslength: SGE flags and data transfer length
118 * @dma_addr: Physical address
119 *
120 * This routine places a MPT request frame back on the MPT adapter's
121 * FreeQ.
122 */
123static inline void
124mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
125{
126 if (sizeof(dma_addr_t) == sizeof(u64)) {
127 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
128 u32 tmp = dma_addr & 0xFFFFFFFF;
129
130 pSge->FlagsLength = cpu_to_le32(flagslength);
131 pSge->Address.Low = cpu_to_le32(tmp);
132 tmp = (u32) ((u64)dma_addr >> 32);
133 pSge->Address.High = cpu_to_le32(tmp);
134
135 } else {
136 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
137 pSge->FlagsLength = cpu_to_le32(flagslength);
138 pSge->Address = cpu_to_le32(dma_addr);
139 }
140} /* mptscsih_add_sge() */
141
142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
143/**
144 * mptscsih_add_chain - Place a chain SGE at address pAddr.
145 * @pAddr: virtual address for SGE
146 * @next: nextChainOffset value (u32's)
147 * @length: length of next SGL segment
148 * @dma_addr: Physical address
149 *
150 * This routine places a MPT request frame back on the MPT adapter's
151 * FreeQ.
152 */
153static inline void
154mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
155{
156 if (sizeof(dma_addr_t) == sizeof(u64)) {
157 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
158 u32 tmp = dma_addr & 0xFFFFFFFF;
159
160 pChain->Length = cpu_to_le16(length);
161 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
162
163 pChain->NextChainOffset = next;
164
165 pChain->Address.Low = cpu_to_le32(tmp);
166 tmp = (u32) ((u64)dma_addr >> 32);
167 pChain->Address.High = cpu_to_le32(tmp);
168 } else {
169 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
170 pChain->Length = cpu_to_le16(length);
171 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
172 pChain->NextChainOffset = next;
173 pChain->Address = cpu_to_le32(dma_addr);
174 }
175} /* mptscsih_add_chain() */
176
177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
178/*
179 * mptscsih_getFreeChainBuffer - Function to get a free chain
180 * from the MPT_SCSI_HOST FreeChainQ.
181 * @ioc: Pointer to MPT_ADAPTER structure
182 * @req_idx: Index of the SCSI IO request frame. (output)
183 *
184 * return SUCCESS or FAILED
185 */
186static inline int
187mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
188{
189 MPT_FRAME_HDR *chainBuf;
190 unsigned long flags;
191 int rc;
192 int chain_idx;
193
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530194 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 ioc->name));
196 spin_lock_irqsave(&ioc->FreeQlock, flags);
197 if (!list_empty(&ioc->FreeChainQ)) {
198 int offset;
199
200 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
201 u.frame.linkage.list);
202 list_del(&chainBuf->u.frame.linkage.list);
203 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
204 chain_idx = offset / ioc->req_sz;
205 rc = SUCCESS;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530206 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200207 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 } else {
209 rc = FAILED;
210 chain_idx = MPT_HOST_NO_CHAIN;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530211 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 ioc->name));
213 }
214 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
215
216 *retIndex = chain_idx;
217 return rc;
218} /* mptscsih_getFreeChainBuffer() */
219
220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
221/*
222 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
223 * SCSIIORequest_t Message Frame.
224 * @ioc: Pointer to MPT_ADAPTER structure
225 * @SCpnt: Pointer to scsi_cmnd structure
226 * @pReq: Pointer to SCSIIORequest_t structure
227 *
228 * Returns ...
229 */
230static int
231mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
232 SCSIIORequest_t *pReq, int req_idx)
233{
234 char *psge;
235 char *chainSge;
236 struct scatterlist *sg;
237 int frm_sz;
238 int sges_left, sg_done;
239 int chain_idx = MPT_HOST_NO_CHAIN;
240 int sgeOffset;
241 int numSgeSlots, numSgeThisFrame;
242 u32 sgflags, sgdir, thisxfer = 0;
243 int chain_dma_off = 0;
244 int newIndex;
245 int ii;
246 dma_addr_t v2;
247 u32 RequestNB;
248
249 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
250 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
251 sgdir = MPT_TRANSFER_HOST_TO_IOC;
252 } else {
253 sgdir = MPT_TRANSFER_IOC_TO_HOST;
254 }
255
256 psge = (char *) &pReq->SGL;
257 frm_sz = ioc->req_sz;
258
259 /* Map the data portion, if any.
260 * sges_left = 0 if no data transfer.
261 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900262 sges_left = scsi_dma_map(SCpnt);
263 if (sges_left < 0)
264 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 /* Handle the SG case.
267 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900268 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sg_done = 0;
270 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
271 chainSge = NULL;
272
273 /* Prior to entering this loop - the following must be set
274 * current MF: sgeOffset (bytes)
275 * chainSge (Null if original MF is not a chain buffer)
276 * sg_done (num SGE done for this MF)
277 */
278
279nextSGEset:
280 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
281 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
282
283 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
284
285 /* Get first (num - 1) SG elements
286 * Skip any SG entries with a length of 0
287 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
288 */
289 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
290 thisxfer = sg_dma_len(sg);
291 if (thisxfer == 0) {
292 sg ++; /* Get next SG element from the OS */
293 sg_done++;
294 continue;
295 }
296
297 v2 = sg_dma_address(sg);
298 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
299
300 sg++; /* Get next SG element from the OS */
301 psge += (sizeof(u32) + sizeof(dma_addr_t));
302 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
303 sg_done++;
304 }
305
306 if (numSgeThisFrame == sges_left) {
307 /* Add last element, end of buffer and end of list flags.
308 */
309 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
310 MPT_SGE_FLAGS_END_OF_BUFFER |
311 MPT_SGE_FLAGS_END_OF_LIST;
312
313 /* Add last SGE and set termination flags.
314 * Note: Last SGE may have a length of 0 - which should be ok.
315 */
316 thisxfer = sg_dma_len(sg);
317
318 v2 = sg_dma_address(sg);
319 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
320 /*
321 sg++;
322 psge += (sizeof(u32) + sizeof(dma_addr_t));
323 */
324 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
325 sg_done++;
326
327 if (chainSge) {
328 /* The current buffer is a chain buffer,
329 * but there is not another one.
330 * Update the chain element
331 * Offset and Length fields.
332 */
333 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
334 } else {
335 /* The current buffer is the original MF
336 * and there is no Chain buffer.
337 */
338 pReq->ChainOffset = 0;
339 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530340 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
342 ioc->RequestNB[req_idx] = RequestNB;
343 }
344 } else {
345 /* At least one chain buffer is needed.
346 * Complete the first MF
347 * - last SGE element, set the LastElement bit
348 * - set ChainOffset (words) for orig MF
349 * (OR finish previous MF chain buffer)
350 * - update MFStructPtr ChainIndex
351 * - Populate chain element
352 * Also
353 * Loop until done.
354 */
355
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530356 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 ioc->name, sg_done));
358
359 /* Set LAST_ELEMENT flag for last non-chain element
360 * in the buffer. Since psge points at the NEXT
361 * SGE element, go back one SGE element, update the flags
362 * and reset the pointer. (Note: sgflags & thisxfer are already
363 * set properly).
364 */
365 if (sg_done) {
366 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
367 sgflags = le32_to_cpu(*ptmp);
368 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
369 *ptmp = cpu_to_le32(sgflags);
370 }
371
372 if (chainSge) {
373 /* The current buffer is a chain buffer.
374 * chainSge points to the previous Chain Element.
375 * Update its chain element Offset and Length (must
376 * include chain element size) fields.
377 * Old chain element is now complete.
378 */
379 u8 nextChain = (u8) (sgeOffset >> 2);
380 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
381 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
382 } else {
383 /* The original MF buffer requires a chain buffer -
384 * set the offset.
385 * Last element in this MF is a chain element.
386 */
387 pReq->ChainOffset = (u8) (sgeOffset >> 2);
388 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530389 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 ioc->RequestNB[req_idx] = RequestNB;
391 }
392
393 sges_left -= sg_done;
394
395
396 /* NOTE: psge points to the beginning of the chain element
397 * in current buffer. Get a chain buffer.
398 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200399 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530400 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
402 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* Update the tracking arrays.
407 * If chainSge == NULL, update ReqToChain, else ChainToChain
408 */
409 if (chainSge) {
410 ioc->ChainToChain[chain_idx] = newIndex;
411 } else {
412 ioc->ReqToChain[req_idx] = newIndex;
413 }
414 chain_idx = newIndex;
415 chain_dma_off = ioc->req_sz * chain_idx;
416
417 /* Populate the chainSGE for the current buffer.
418 * - Set chain buffer pointer to psge and fill
419 * out the Address and Flags fields.
420 */
421 chainSge = (char *) psge;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530422 dsgprintk(ioc, printk(KERN_DEBUG " Current buff @ %p (index 0x%x)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 psge, req_idx));
424
425 /* Start the SGE for the next buffer
426 */
427 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
428 sgeOffset = 0;
429 sg_done = 0;
430
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530431 dsgprintk(ioc, printk(KERN_DEBUG " Chain buff @ %p (index 0x%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 psge, chain_idx));
433
434 /* Start the SGE for the next buffer
435 */
436
437 goto nextSGEset;
438 }
439
440 return SUCCESS;
441} /* mptscsih_AddSGE() */
442
Eric Moore786899b2006-07-11 17:22:22 -0600443static void
444mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
445 U32 SlotStatus)
446{
447 MPT_FRAME_HDR *mf;
448 SEPRequest_t *SEPMsg;
449
Eric Moorecc78d302007-06-15 17:27:21 -0600450 if (ioc->bus_type != SAS)
451 return;
452
453 /* Not supported for hidden raid components
454 */
455 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600456 return;
457
458 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530459 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Eric Moore786899b2006-07-11 17:22:22 -0600460 ioc->name,__FUNCTION__));
461 return;
462 }
463
464 SEPMsg = (SEPRequest_t *)mf;
465 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700466 SEPMsg->Bus = vtarget->channel;
467 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600468 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
469 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530470 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700471 "Sending SEP cmd=%x channel=%d id=%d\n",
472 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600473 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
474}
475
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530476#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700477/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530478 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700479 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700480 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530481 * @pScsiReply: Pointer to MPT reply frame
482 *
483 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700484 *
485 * Refer to lsi/mpi.h.
486 **/
487static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530488mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700489{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530490 char *desc = NULL;
491 char *desc1 = NULL;
492 u16 ioc_status;
493 u8 skey, asc, ascq;
494
495 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700496
497 switch (ioc_status) {
498
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530499 case MPI_IOCSTATUS_SUCCESS:
500 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700501 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530502 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
503 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700504 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530505 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
506 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700507 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530508 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
509 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700510 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530511 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
512 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700513 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530514 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
515 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700516 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530517 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
518 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700519 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530520 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
521 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700522 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530523 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
524 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700525 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530526 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
527 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700528 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530529 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
530 desc = "task management failed";
531 break;
532 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
533 desc = "IOC terminated";
534 break;
535 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
536 desc = "ext terminated";
537 break;
538 default:
539 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700540 break;
541 }
542
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530543 switch (pScsiReply->SCSIStatus)
544 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700545
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530546 case MPI_SCSI_STATUS_SUCCESS:
547 desc1 = "success";
548 break;
549 case MPI_SCSI_STATUS_CHECK_CONDITION:
550 desc1 = "check condition";
551 break;
552 case MPI_SCSI_STATUS_CONDITION_MET:
553 desc1 = "condition met";
554 break;
555 case MPI_SCSI_STATUS_BUSY:
556 desc1 = "busy";
557 break;
558 case MPI_SCSI_STATUS_INTERMEDIATE:
559 desc1 = "intermediate";
560 break;
561 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
562 desc1 = "intermediate condmet";
563 break;
564 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
565 desc1 = "reservation conflict";
566 break;
567 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
568 desc1 = "command terminated";
569 break;
570 case MPI_SCSI_STATUS_TASK_SET_FULL:
571 desc1 = "task set full";
572 break;
573 case MPI_SCSI_STATUS_ACA_ACTIVE:
574 desc1 = "aca active";
575 break;
576 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
577 desc1 = "fcpext device logged out";
578 break;
579 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
580 desc1 = "fcpext no link";
581 break;
582 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
583 desc1 = "fcpext unassigned";
584 break;
585 default:
586 desc1 = "";
587 break;
588 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700589
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530590 scsi_print_command(sc);
591 printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n",
592 pScsiReply->Bus, pScsiReply->TargetID);
593 printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n",
594 scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
595 printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
596 le16_to_cpu(pScsiReply->TaskTag),
597 le32_to_cpu(pScsiReply->TransferCount), sc->result);
598
599 printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), "
600 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
601 desc, ioc_status,
602 desc1, pScsiReply->SCSIStatus,
603 pScsiReply->SCSIState);
604
605 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
606 skey = sc->sense_buffer[2] & 0x0F;
607 asc = sc->sense_buffer[12];
608 ascq = sc->sense_buffer[13];
609
610 printk(KERN_DEBUG "\t[sense_key,asc,ascq]: "
611 "[0x%02x,0x%02x,0x%02x]\n",
612 skey, asc, ascq);
613 }
614
615 /*
616 * Look for + dump FCP ResponseInfo[]!
617 */
618 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
619 pScsiReply->ResponseInfo)
620 printk(KERN_DEBUG "response_info = %08xh\n",
621 le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700622}
623#endif
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
626/*
627 * mptscsih_io_done - Main SCSI IO callback routine registered to
628 * Fusion MPT (base) driver
629 * @ioc: Pointer to MPT_ADAPTER structure
630 * @mf: Pointer to original MPT request frame
631 * @r: Pointer to MPT reply frame (NULL if TurboReply)
632 *
633 * This routine is called from mpt.c::mpt_interrupt() at the completion
634 * of any SCSI IO request.
635 * This routine is registered with the Fusion MPT (base) driver at driver
636 * load/init time via the mpt_register() API call.
637 *
638 * Returns 1 indicating alloc'd request frame ptr should be freed.
639 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400640int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
642{
643 struct scsi_cmnd *sc;
644 MPT_SCSI_HOST *hd;
645 SCSIIORequest_t *pScsiReq;
646 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700647 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600648 VirtDevice *vdev;
649 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
652
653 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700654 req_idx_MR = (mr != NULL) ?
655 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
656 if ((req_idx != req_idx_MR) ||
657 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
658 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
659 ioc->name);
660 printk (MYIOC_s_ERR_FMT
661 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
662 ioc->name, req_idx, req_idx_MR, mf, mr,
663 hd->ScsiLookup[req_idx_MR]);
664 return 0;
665 }
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600668 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (sc == NULL) {
670 MPIHeader_t *hdr = (MPIHeader_t *)mf;
671
672 /* Remark: writeSDP1 will use the ScsiDoneCtx
673 * If a SCSI I/O cmd, device disabled by OS and
674 * completion done. Cannot touch sc struct. Just free mem.
675 */
676 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
677 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
678 ioc->name);
679
680 mptscsih_freeChainBuffers(ioc, req_idx);
681 return 1;
682 }
683
Eric Moore3dc0b032006-07-11 17:32:33 -0600684 if ((unsigned char *)mf != sc->host_scribble) {
685 mptscsih_freeChainBuffers(ioc, req_idx);
686 return 1;
687 }
688
689 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 sc->result = DID_OK << 16; /* Set default reply as OK */
691 pScsiReq = (SCSIIORequest_t *) mf;
692 pScsiReply = (SCSIIOReply_t *) mr;
693
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200694 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530695 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200696 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
697 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
698 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530699 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200700 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
701 ioc->name, mf, mr, sc, req_idx));
702 }
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (pScsiReply == NULL) {
705 /* special context reply handling */
706 ;
707 } else {
708 u32 xfer_cnt;
709 u16 status;
710 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700711 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
714 scsi_state = pScsiReply->SCSIState;
715 scsi_status = pScsiReply->SCSIStatus;
716 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900717 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700718 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600720 /*
721 * if we get a data underrun indication, yet no data was
722 * transferred and the SCSI status indicates that the
723 * command was never started, change the data underrun
724 * to success
725 */
726 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
727 (scsi_status == MPI_SCSI_STATUS_BUSY ||
728 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
729 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
730 status = MPI_IOCSTATUS_SUCCESS;
731 }
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400734 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 /*
737 * Look for + dump FCP ResponseInfo[]!
738 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600739 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
740 pScsiReply->ResponseInfo) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700741 printk(KERN_NOTICE "[%d:%d:%d:%d] "
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600742 "FCP_ResponseInfo=%08xh\n",
Eric Moorec6c727a2007-01-29 09:44:54 -0700743 sc->device->host->host_no, sc->device->channel,
744 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 le32_to_cpu(pScsiReply->ResponseInfo));
746 }
747
748 switch(status) {
749 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
750 /* CHECKME!
751 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
752 * But not: DID_BUS_BUSY lest one risk
753 * killing interrupt handler:-(
754 */
755 sc->result = SAM_STAT_BUSY;
756 break;
757
758 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
759 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
760 sc->result = DID_BAD_TARGET << 16;
761 break;
762
763 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
764 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600765 if (ioc->bus_type != FC)
766 sc->result = DID_NO_CONNECT << 16;
767 /* else fibre, just stall until rescan event */
768 else
769 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
772 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600773
774 vdev = sc->device->hostdata;
775 if (!vdev)
776 break;
777 vtarget = vdev->vtarget;
778 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
779 mptscsih_issue_sep_command(ioc, vtarget,
780 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
781 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 break;
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600786 if ( ioc->bus_type == SAS ) {
787 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
788 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700789 if ((log_info & SAS_LOGINFO_MASK)
790 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600791 sc->result = (DID_BUS_BUSY << 16);
792 break;
793 }
794 }
Eric Moore86dd4242007-01-04 20:44:01 -0700795 } else if (ioc->bus_type == FC) {
796 /*
797 * The FC IOC may kill a request for variety of
798 * reasons, some of which may be recovered by a
799 * retry, some which are unlikely to be
800 * recovered. Return DID_ERROR instead of
801 * DID_RESET to permit retry of the command,
802 * just not an infinite number of them
803 */
804 sc->result = DID_ERROR << 16;
805 break;
Eric Moorebf451522006-07-11 17:25:35 -0600806 }
807
808 /*
809 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
810 */
811
812 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
814 /* Linux handles an unsolicited DID_RESET better
815 * than an unsolicited DID_ABORT.
816 */
817 sc->result = DID_RESET << 16;
818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 break;
820
821 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900822 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600823 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
824 sc->result=DID_SOFT_ERROR << 16;
825 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 sc->result = (DID_OK << 16) | scsi_status;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530827 dreplyprintk(ioc, printk(KERN_DEBUG
Eric Moorec6c727a2007-01-29 09:44:54 -0700828 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
829 sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
833 /*
834 * Do upfront check for valid SenseData and give it
835 * precedence!
836 */
837 sc->result = (DID_OK << 16) | scsi_status;
838 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
839 /* Have already saved the status and sense data
840 */
841 ;
842 } else {
843 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600844 if (scsi_status == SAM_STAT_BUSY)
845 sc->result = SAM_STAT_BUSY;
846 else
847 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
850 /* What to do?
851 */
852 sc->result = DID_SOFT_ERROR << 16;
853 }
854 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
855 /* Not real sure here either... */
856 sc->result = DID_RESET << 16;
857 }
858 }
859
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530860
861 dreplyprintk(ioc, printk(KERN_DEBUG " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 sc->underflow));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530863 dreplyprintk(ioc, printk(KERN_DEBUG " ActBytesXferd=%02xh\n", xfer_cnt));
864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 /* Report Queue Full
866 */
867 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
868 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 break;
871
Moore, Eric7e551472006-01-16 18:53:21 -0700872 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900873 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
875 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600876 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (scsi_state == 0) {
878 ;
879 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
880 /*
881 * If running against circa 200003dd 909 MPT f/w,
882 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
883 * (QUEUE_FULL) returned from device! --> get 0x0000?128
884 * and with SenseBytes set to 0.
885 */
886 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
887 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
888
889 }
890 else if (scsi_state &
891 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
892 ) {
893 /*
894 * What to do?
895 */
896 sc->result = DID_SOFT_ERROR << 16;
897 }
898 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
899 /* Not real sure here either... */
900 sc->result = DID_RESET << 16;
901 }
902 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
903 /* Device Inq. data indicates that it supports
904 * QTags, but rejects QTag messages.
905 * This command completed OK.
906 *
907 * Not real sure here either so do nothing... */
908 }
909
910 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
911 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
912
913 /* Add handling of:
914 * Reservation Conflict, Busy,
915 * Command Terminated, CHECK
916 */
917 break;
918
919 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
920 sc->result = DID_SOFT_ERROR << 16;
921 break;
922
923 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
924 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
925 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
926 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
927 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
928 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
929 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
931 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
932 default:
933 /*
934 * What to do?
935 */
936 sc->result = DID_SOFT_ERROR << 16;
937 break;
938
939 } /* switch(status) */
940
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530941#ifdef CONFIG_FUSION_LOGGING
942 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
943 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700944#endif
945
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 } /* end of address reply case */
947
948 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900949 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 sc->scsi_done(sc); /* Issue the command callback */
952
953 /* Free Chain buffers */
954 mptscsih_freeChainBuffers(ioc, req_idx);
955 return 1;
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/*
959 * mptscsih_flush_running_cmds - For each command found, search
960 * Scsi_Host instance taskQ and reply to OS.
961 * Called only if recovering from a FW reload.
962 * @hd: Pointer to a SCSI HOST structure
963 *
964 * Returns: None.
965 *
966 * Must be called while new I/Os are being queued.
967 */
968static void
969mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
970{
971 MPT_ADAPTER *ioc = hd->ioc;
972 struct scsi_cmnd *SCpnt;
973 MPT_FRAME_HDR *mf;
974 int ii;
975 int max = ioc->req_depth;
976
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530977 dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 for (ii= 0; ii < max; ii++) {
979 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
980
981 /* Command found.
982 */
983
984 /* Null ScsiLookup index
985 */
986 hd->ScsiLookup[ii] = NULL;
987
988 mf = MPT_INDEX_2_MFPTR(ioc, ii);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530989 dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 mf, SCpnt));
991
Eric Moore3dc0b032006-07-11 17:32:33 -0600992 /* Free Chain buffers */
993 mptscsih_freeChainBuffers(ioc, ii);
994
995 /* Free Message frames */
996 mpt_free_msg_frame(ioc, mf);
997
998 if ((unsigned char *)mf != SCpnt->host_scribble)
999 continue;
1000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 /* Set status, free OS resources (SG DMA buffers)
1002 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001004 scsi_dma_unmap(SCpnt);
1005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 SCpnt->result = DID_RESET << 16;
1007 SCpnt->host_scribble = NULL;
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
1010 }
1011 }
1012
1013 return;
1014}
1015
1016/*
1017 * mptscsih_search_running_cmds - Delete any commands associated
1018 * with the specified target and lun. Function called only
1019 * when a lun is disable by mid-layer.
1020 * Do NOT access the referenced scsi_cmnd structure or
1021 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001022 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001023 * @hd: Pointer to a SCSI HOST structure
1024 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 *
1026 * Returns: None.
1027 *
1028 * Called from slave_destroy.
1029 */
1030static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001031mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
1033 SCSIIORequest_t *mf = NULL;
1034 int ii;
1035 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001036 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001037 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301039 dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n",
Eric Moore793955f2007-01-29 09:42:20 -07001040 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001043 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001046 if (mf == NULL)
1047 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001048 /* If the device is a hidden raid component, then its
1049 * expected that the mf->function will be RAID_SCSI_IO
1050 */
1051 if (vdevice->vtarget->tflags &
1052 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1053 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1054 continue;
1055
Eric Moore793955f2007-01-29 09:42:20 -07001056 int_to_scsilun(vdevice->lun, &lun);
1057 if ((mf->Bus != vdevice->vtarget->channel) ||
1058 (mf->TargetID != vdevice->vtarget->id) ||
1059 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 continue;
1061
1062 /* Cleanup
1063 */
1064 hd->ScsiLookup[ii] = NULL;
1065 mptscsih_freeChainBuffers(hd->ioc, ii);
1066 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001067 if ((unsigned char *)mf != sc->host_scribble)
1068 continue;
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001069 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001070 sc->host_scribble = NULL;
1071 sc->result = DID_NO_CONNECT << 16;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301072 sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d,"
1073 "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel,
1074 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001075 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return;
1079}
1080
1081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1084/*
1085 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1086 * from a SCSI target device.
1087 * @sc: Pointer to scsi_cmnd structure
1088 * @pScsiReply: Pointer to SCSIIOReply_t
1089 * @pScsiReq: Pointer to original SCSI request
1090 *
1091 * This routine periodically reports QUEUE_FULL status returned from a
1092 * SCSI target device. It reports this to the console via kernel
1093 * printk() API call, not more than once every 10 seconds.
1094 */
1095static void
1096mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1097{
1098 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001101 if (sc->device == NULL)
1102 return;
1103 if (sc->device->host == NULL)
1104 return;
1105 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1106 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001108 if (time - hd->last_queue_full > 10 * HZ) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301109 dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001110 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1111 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113}
1114
1115/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1116/*
1117 * mptscsih_remove - Removed scsi devices
1118 * @pdev: Pointer to pci_dev structure
1119 *
1120 *
1121 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001122void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123mptscsih_remove(struct pci_dev *pdev)
1124{
1125 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1126 struct Scsi_Host *host = ioc->sh;
1127 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001130 if(!host) {
1131 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 scsi_remove_host(host);
1136
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001137 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1138 return;
1139
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001140 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001142 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001144 if (hd->ScsiLookup != NULL) {
1145 sz1 = hd->ioc->req_depth * sizeof(void *);
1146 kfree(hd->ScsiLookup);
1147 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301150 dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001151 "Free'd ScsiLookup (%d) memory\n",
1152 hd->ioc->name, sz1));
1153
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001154 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155
1156 /* NULL the Scsi_Host pointer
1157 */
1158 hd->ioc->sh = NULL;
1159
1160 scsi_host_put(host);
1161
1162 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164}
1165
1166/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1167/*
1168 * mptscsih_shutdown - reboot notifier
1169 *
1170 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001171void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001172mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001174 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 struct Scsi_Host *host = ioc->sh;
1176 MPT_SCSI_HOST *hd;
1177
1178 if(!host)
1179 return;
1180
1181 hd = (MPT_SCSI_HOST *)host->hostdata;
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183}
1184
1185#ifdef CONFIG_PM
1186/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1187/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001188 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 *
1190 *
1191 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001192int
Pavel Machek8d189f72005-04-16 15:25:28 -07001193mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001195 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197}
1198
1199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1200/*
1201 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1202 *
1203 *
1204 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001205int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206mptscsih_resume(struct pci_dev *pdev)
1207{
Hormsb364fd52007-03-19 15:06:44 +09001208 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209}
1210
1211#endif
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1214/**
1215 * mptscsih_info - Return information about MPT adapter
1216 * @SChost: Pointer to Scsi_Host structure
1217 *
1218 * (linux scsi_host_template.info routine)
1219 *
1220 * Returns pointer to buffer where information was written.
1221 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001222const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223mptscsih_info(struct Scsi_Host *SChost)
1224{
1225 MPT_SCSI_HOST *h;
1226 int size = 0;
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001231 if (h->info_kbuf == NULL)
1232 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1233 return h->info_kbuf;
1234 h->info_kbuf[0] = '\0';
1235
1236 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1237 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 }
1239
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001240 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241}
1242
1243struct info_str {
1244 char *buffer;
1245 int length;
1246 int offset;
1247 int pos;
1248};
1249
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001250static void
1251mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252{
1253 if (info->pos + len > info->length)
1254 len = info->length - info->pos;
1255
1256 if (info->pos + len < info->offset) {
1257 info->pos += len;
1258 return;
1259 }
1260
1261 if (info->pos < info->offset) {
1262 data += (info->offset - info->pos);
1263 len -= (info->offset - info->pos);
1264 }
1265
1266 if (len > 0) {
1267 memcpy(info->buffer + info->pos, data, len);
1268 info->pos += len;
1269 }
1270}
1271
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001272static int
1273mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
1275 va_list args;
1276 char buf[81];
1277 int len;
1278
1279 va_start(args, fmt);
1280 len = vsprintf(buf, fmt, args);
1281 va_end(args);
1282
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 return len;
1285}
1286
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001287static int
1288mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
1290 struct info_str info;
1291
1292 info.buffer = pbuf;
1293 info.length = len;
1294 info.offset = offset;
1295 info.pos = 0;
1296
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001297 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1298 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1299 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1300 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1303}
1304
1305/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1306/**
1307 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001308 * @host: scsi host struct
1309 * @buffer: if write, user data; if read, buffer for user
1310 * @start: returns the buffer address
1311 * @offset: if write, 0; if read, the current offset into the buffer from
1312 * the previous read.
1313 * @length: if write, return length;
1314 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 *
1316 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001318int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1320 int length, int func)
1321{
1322 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1323 MPT_ADAPTER *ioc = hd->ioc;
1324 int size = 0;
1325
1326 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001327 /*
1328 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 */
1330 } else {
1331 if (start)
1332 *start = buffer;
1333
1334 size = mptscsih_host_info(ioc, buffer, offset, length);
1335 }
1336
1337 return size;
1338}
1339
1340/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1341#define ADD_INDEX_LOG(req_ent) do { } while(0)
1342
1343/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1344/**
1345 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1346 * @SCpnt: Pointer to scsi_cmnd structure
1347 * @done: Pointer SCSI mid-layer IO completion function
1348 *
1349 * (linux scsi_host_template.queuecommand routine)
1350 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1351 * from a linux scsi_cmnd request and send it to the IOC.
1352 *
1353 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1354 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001355int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1357{
1358 MPT_SCSI_HOST *hd;
1359 MPT_FRAME_HDR *mf;
1360 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001361 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 int lun;
1363 u32 datalen;
1364 u32 scsictl;
1365 u32 scsidir;
1366 u32 cmd_len;
1367 int my_idx;
1368 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301369 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301372 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 lun = SCpnt->device->lun;
1374 SCpnt->scsi_done = done;
1375
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301376 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1377 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 if (hd->resetPending) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301380 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1381 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return SCSI_MLQUEUE_HOST_BUSY;
1383 }
1384
1385 /*
1386 * Put together a MPT SCSI request...
1387 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001388 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301389 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1390 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 return SCSI_MLQUEUE_HOST_BUSY;
1392 }
1393
1394 pScsiReq = (SCSIIORequest_t *) mf;
1395
1396 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1397
1398 ADD_INDEX_LOG(my_idx);
1399
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001400 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 * Seems we may receive a buffer (datalen>0) even when there
1402 * will be no data transfer! GRRRRR...
1403 */
1404 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001405 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1407 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001408 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1410 } else {
1411 datalen = 0;
1412 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1413 }
1414
1415 /* Default to untagged. Once a target structure has been allocated,
1416 * use the Inquiry data to determine if device supports tagged.
1417 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001418 if (vdev
1419 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 && (SCpnt->device->tagged_supported)) {
1421 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1422 } else {
1423 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1424 }
1425
1426 /* Use the above information to set up the message frame
1427 */
Eric Moore793955f2007-01-29 09:42:20 -07001428 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1429 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001431 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1432 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1433 else
1434 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 pScsiReq->CDBLength = SCpnt->cmd_len;
1436 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1437 pScsiReq->Reserved = 0;
1438 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001439 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 pScsiReq->Control = cpu_to_le32(scsictl);
1441
1442 /*
1443 * Write SCSI CDB into the message
1444 */
1445 cmd_len = SCpnt->cmd_len;
1446 for (ii=0; ii < cmd_len; ii++)
1447 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1448
1449 for (ii=cmd_len; ii < 16; ii++)
1450 pScsiReq->CDB[ii] = 0;
1451
1452 /* DataLength */
1453 pScsiReq->DataLength = cpu_to_le32(datalen);
1454
1455 /* SenseBuffer low address */
1456 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1457 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1458
1459 /* Now add the SG list
1460 * Always have a SGE even if null length.
1461 */
1462 if (datalen == 0) {
1463 /* Add a NULL SGE */
1464 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1465 (dma_addr_t) -1);
1466 } else {
1467 /* Add a 32 or 64 bit SGE */
1468 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1469 goto fail;
1470 }
1471
Eric Moore3dc0b032006-07-11 17:32:33 -06001472 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001475 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301476 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1477 ioc->name, SCpnt, mf, my_idx));
1478 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return 0;
1480
1481 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001482 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1484 mpt_free_msg_frame(hd->ioc, mf);
1485 return SCSI_MLQUEUE_HOST_BUSY;
1486}
1487
1488/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1489/*
1490 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1491 * with a SCSI IO request
1492 * @hd: Pointer to the MPT_SCSI_HOST instance
1493 * @req_idx: Index of the SCSI IO request frame.
1494 *
1495 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1496 * No return.
1497 */
1498static void
1499mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1500{
1501 MPT_FRAME_HDR *chain;
1502 unsigned long flags;
1503 int chain_idx;
1504 int next;
1505
1506 /* Get the first chain index and reset
1507 * tracker state.
1508 */
1509 chain_idx = ioc->ReqToChain[req_idx];
1510 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1511
1512 while (chain_idx != MPT_HOST_NO_CHAIN) {
1513
1514 /* Save the next chain buffer index */
1515 next = ioc->ChainToChain[chain_idx];
1516
1517 /* Free this chain buffer and reset
1518 * tracker
1519 */
1520 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1521
1522 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1523 + (chain_idx * ioc->req_sz));
1524
1525 spin_lock_irqsave(&ioc->FreeQlock, flags);
1526 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1527 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1528
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301529 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 ioc->name, chain_idx));
1531
1532 /* handle next */
1533 chain_idx = next;
1534 }
1535 return;
1536}
1537
1538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1539/*
1540 * Reset Handling
1541 */
1542
1543/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001544/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001546 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001548 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001549 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 * @lun: Logical Unit for reset (if appropriate)
1551 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001552 * @timeout: timeout for task management control
1553 *
1554 * Fall through to mpt_HardResetHandler if: not operational, too many
1555 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 *
1557 * Remark: Currently invoked from a non-interrupt thread (_bh).
1558 *
1559 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1560 * will be active.
1561 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001562 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001563 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001564int
Eric Moore793955f2007-01-29 09:42:20 -07001565mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566{
1567 MPT_ADAPTER *ioc;
1568 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 u32 ioc_raw_state;
1570 unsigned long flags;
1571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 ioc = hd->ioc;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301573 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 // SJR - CHECKME - Can we avoid this here?
1576 // (mpt_HardResetHandler has this check...)
1577 spin_lock_irqsave(&ioc->diagLock, flags);
1578 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1579 spin_unlock_irqrestore(&ioc->diagLock, flags);
1580 return FAILED;
1581 }
1582 spin_unlock_irqrestore(&ioc->diagLock, flags);
1583
1584 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001585 * If we time out and not bus reset, then we return a FAILED status
1586 * to the caller.
1587 * The call to mptscsih_tm_pending_wait() will set the pending flag
1588 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 * successful. Otherwise, reload the FW.
1590 */
1591 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1592 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301593 dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301595 ioc->name, hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 return FAILED;
1597 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301598 dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target "
Eric Moorecd2c6192007-01-29 09:47:47 -07001599 "reset: Timed out waiting for last TM (%d) "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301600 "to complete! \n", ioc->name,
Eric Moorecd2c6192007-01-29 09:47:47 -07001601 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 return FAILED;
1603 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301604 dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301606 ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001607 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
1609 } else {
1610 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1611 hd->tmPending |= (1 << type);
1612 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1613 }
1614
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1616
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1618 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001619 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1620 ioc->name, type, ioc_raw_state);
1621 printk(KERN_WARNING " Issuing HardReset!!\n");
1622 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1623 printk((KERN_WARNING "TMHandler: HardReset "
1624 "FAILED!!\n"));
1625 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
1627
Eric Moorecd2c6192007-01-29 09:47:47 -07001628 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1629 printk(MYIOC_s_WARN_FMT
1630 "TM Handler for type=%x: ioc_state: "
1631 "DOORBELL_ACTIVE (0x%x)!\n",
1632 ioc->name, type, ioc_raw_state);
1633 return FAILED;
1634 }
1635
1636 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001638 if (hd->hard_resets < -1)
1639 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Eric Moorecd2c6192007-01-29 09:47:47 -07001641 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1642 ctx2abort, timeout);
1643 if (rc)
1644 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301645 ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001646 else
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301647 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1648 ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001649
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301650 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1651 "TMHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
1653 return rc;
1654}
1655
1656
1657/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001658/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1660 * @hd: Pointer to MPT_SCSI_HOST structure
1661 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001662 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001663 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 * @lun: Logical Unit for reset (if appropriate)
1665 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001666 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 *
1668 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1669 * or a non-interrupt thread. In the former, must not call schedule().
1670 *
1671 * Not all fields are meaningfull for all task types.
1672 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001673 * Returns 0 for SUCCESS, or FAILED.
1674 *
1675 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676static int
Eric Moore793955f2007-01-29 09:42:20 -07001677mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678{
1679 MPT_FRAME_HDR *mf;
1680 SCSITaskMgmt_t *pScsiTm;
1681 int ii;
1682 int retval;
1683
1684 /* Return Fail to calling function if no message frames available.
1685 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001686 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301687 dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001689 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301691 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 hd->ioc->name, mf));
1693
1694 /* Format the Request
1695 */
1696 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001697 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 pScsiTm->Bus = channel;
1699 pScsiTm->ChainOffset = 0;
1700 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1701
1702 pScsiTm->Reserved = 0;
1703 pScsiTm->TaskType = type;
1704 pScsiTm->Reserved1 = 0;
1705 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1706 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1707
Eric Moore793955f2007-01-29 09:42:20 -07001708 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
1710 for (ii=0; ii < 7; ii++)
1711 pScsiTm->Reserved2[ii] = 0;
1712
1713 pScsiTm->TaskMsgContext = ctx2abort;
1714
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301715 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
Eric Moorecd2c6192007-01-29 09:47:47 -07001716 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301718 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301720 if ((hd->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1721 (hd->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1722 mpt_put_msg_frame_hi_pri(hd->ioc->TaskCtx, hd->ioc, mf);
1723 else {
1724 retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
1725 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1726 if (retval) {
1727 dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
Eric Moorecd2c6192007-01-29 09:47:47 -07001728 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1729 hd->ioc, mf, retval));
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301730 goto fail_out;
1731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 }
1733
1734 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301735 dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1737 hd->ioc, mf));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301738 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 hd->ioc->name));
1740 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301741 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
Eric Moorecd2c6192007-01-29 09:47:47 -07001742 hd->ioc->name, retval));
1743 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
1745
Eric Moorecd2c6192007-01-29 09:47:47 -07001746 /*
1747 * Handle success case, see if theres a non-zero ioc_status.
1748 */
1749 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1750 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1751 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1752 retval = 0;
1753 else
1754 retval = FAILED;
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001757
1758 fail_out:
1759
1760 /*
1761 * Free task managment mf, and corresponding tm flags
1762 */
1763 mpt_free_msg_frame(hd->ioc, mf);
1764 hd->tmPending = 0;
1765 hd->tmState = TM_STATE_NONE;
1766 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767}
1768
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001769static int
1770mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1771{
1772 switch (ioc->bus_type) {
1773 case FC:
1774 return 40;
1775 case SAS:
1776 return 10;
1777 case SPI:
1778 default:
1779 return 2;
1780 }
1781}
1782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1784/**
1785 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1786 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1787 *
1788 * (linux scsi_host_template.eh_abort_handler routine)
1789 *
1790 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001791 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001792int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793mptscsih_abort(struct scsi_cmnd * SCpnt)
1794{
1795 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 MPT_FRAME_HDR *mf;
1797 u32 ctx2abort;
1798 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001800 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001801 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001802 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 /* If we can't locate our host adapter structure, return FAILED status.
1805 */
1806 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1807 SCpnt->result = DID_RESET << 16;
1808 SCpnt->scsi_done(SCpnt);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301809 printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate "
1810 "host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 return FAILED;
1812 }
1813
Eric Moore958d4a32007-06-15 17:24:14 -06001814 ioc = hd->ioc;
1815 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1816 ioc->name, SCpnt);
1817 scsi_print_command(SCpnt);
1818
1819 vdevice = SCpnt->device->hostdata;
1820 if (!vdevice || !vdevice->vtarget) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301821 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been "
Eric Moore958d4a32007-06-15 17:24:14 -06001822 "deleted (sc=%p)\n", ioc->name, SCpnt));
1823 SCpnt->result = DID_NO_CONNECT << 16;
1824 SCpnt->scsi_done(SCpnt);
1825 retval = 0;
1826 goto out;
1827 }
1828
Eric Moorecc78d302007-06-15 17:27:21 -06001829 /* Task aborts are not supported for hidden raid components.
1830 */
1831 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301832 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid "
Eric Moorecc78d302007-06-15 17:27:21 -06001833 "component (sc=%p)\n", ioc->name, SCpnt));
1834 SCpnt->result = DID_RESET << 16;
1835 retval = FAILED;
1836 goto out;
1837 }
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 /* Find this command
1840 */
1841 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 * Do OS callback.
1844 */
1845 SCpnt->result = DID_RESET << 16;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301846 dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001847 "Command not in the active list! (sc=%p)\n", ioc->name,
1848 SCpnt));
1849 retval = 0;
1850 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 }
1852
Eric Moore958d4a32007-06-15 17:24:14 -06001853 if (hd->resetPending) {
1854 retval = FAILED;
1855 goto out;
1856 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001857
1858 if (hd->timeouts < -1)
1859 hd->timeouts++;
1860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1862 * (the IO to be ABORT'd)
1863 *
1864 * NOTE: Since we do not byteswap MsgContext, we do not
1865 * swap it here either. It is an opaque cookie to
1866 * the controller, so it does not matter. -DaveM
1867 */
1868 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1869 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1870
1871 hd->abortSCpnt = SCpnt;
1872
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001873 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001874 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1875 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
Eric Moore3dc0b032006-07-11 17:32:33 -06001877 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001878 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001879 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001880
Eric Moore958d4a32007-06-15 17:24:14 -06001881 out:
1882 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1883 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001885 if (retval == 0)
1886 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001887 else
1888 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889}
1890
1891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1892/**
1893 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1894 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1895 *
1896 * (linux scsi_host_template.eh_dev_reset_handler routine)
1897 *
1898 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001899 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001900int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1902{
1903 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001904 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001905 VirtDevice *vdevice;
1906 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
1908 /* If we can't locate our host adapter structure, return FAILED status.
1909 */
1910 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301911 printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't "
1912 "locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 return FAILED;
1914 }
1915
Eric Moore958d4a32007-06-15 17:24:14 -06001916 ioc = hd->ioc;
1917 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1918 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001919 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Eric Moore958d4a32007-06-15 17:24:14 -06001921 if (hd->resetPending) {
1922 retval = FAILED;
1923 goto out;
1924 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001925
Eric Moore958d4a32007-06-15 17:24:14 -06001926 vdevice = SCpnt->device->hostdata;
1927 if (!vdevice || !vdevice->vtarget) {
1928 retval = 0;
1929 goto out;
1930 }
1931
Eric Moorecc78d302007-06-15 17:27:21 -06001932 /* Target reset to hidden raid component is not supported
1933 */
1934 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1935 retval = FAILED;
1936 goto out;
1937 }
1938
Eric Moore958d4a32007-06-15 17:24:14 -06001939 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1940 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1941 mptscsih_get_tm_timeout(ioc));
1942
1943 out:
1944 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1945 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001946
1947 if (retval == 0)
1948 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001949 else
1950 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951}
1952
Eric Moorecd2c6192007-01-29 09:47:47 -07001953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1955/**
1956 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1957 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1958 *
1959 * (linux scsi_host_template.eh_bus_reset_handler routine)
1960 *
1961 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001962 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001963int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1965{
1966 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001967 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001968 VirtDevice *vdev;
Eric Moore958d4a32007-06-15 17:24:14 -06001969 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971 /* If we can't locate our host adapter structure, return FAILED status.
1972 */
1973 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301974 printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't "
1975 "locate host! (sc=%p)\n", SCpnt );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 return FAILED;
1977 }
1978
Eric Moore958d4a32007-06-15 17:24:14 -06001979 ioc = hd->ioc;
1980 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1981 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001982 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984 if (hd->timeouts < -1)
1985 hd->timeouts++;
1986
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001987 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001988 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore958d4a32007-06-15 17:24:14 -06001989 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
Eric Moore958d4a32007-06-15 17:24:14 -06001991 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1992 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001993
1994 if (retval == 0)
1995 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001996 else
1997 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998}
1999
2000/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2001/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002002 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
2004 *
2005 * (linux scsi_host_template.eh_host_reset_handler routine)
2006 *
2007 * Returns SUCCESS or FAILED.
2008 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002009int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2011{
2012 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06002013 int retval;
2014 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
2016 /* If we can't locate the host to reset, then we failed. */
2017 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302018 printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't "
2019 "locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 return FAILED;
2021 }
2022
Eric Moore958d4a32007-06-15 17:24:14 -06002023 ioc = hd->ioc;
2024 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2025 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
2027 /* If our attempts to reset the host failed, then return a failed
2028 * status. The host will be taken off line by the SCSI mid-layer.
2029 */
Eric Moore958d4a32007-06-15 17:24:14 -06002030 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
2031 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 } else {
2033 /* Make sure TM pending is cleared and TM state is set to
2034 * NONE.
2035 */
Eric Moore958d4a32007-06-15 17:24:14 -06002036 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 hd->tmPending = 0;
2038 hd->tmState = TM_STATE_NONE;
2039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
Eric Moore958d4a32007-06-15 17:24:14 -06002041 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2042 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Eric Moore958d4a32007-06-15 17:24:14 -06002044 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045}
2046
2047/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2048/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002049 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 * @hd: Pointer to MPT host structure.
2051 *
2052 * Returns {SUCCESS,FAILED}.
2053 */
2054static int
2055mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2056{
2057 unsigned long flags;
2058 int loop_count = 4 * 10; /* Wait 10 seconds */
2059 int status = FAILED;
2060
2061 do {
2062 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2063 if (hd->tmState == TM_STATE_NONE) {
2064 hd->tmState = TM_STATE_IN_PROGRESS;
2065 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002067 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 break;
2069 }
2070 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2071 msleep(250);
2072 } while (--loop_count);
2073
2074 return status;
2075}
2076
2077/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2078/**
2079 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2080 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002081 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 *
2083 * Returns {SUCCESS,FAILED}.
2084 */
2085static int
2086mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2087{
2088 unsigned long flags;
2089 int loop_count = 4 * timeout;
2090 int status = FAILED;
2091
2092 do {
2093 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2094 if(hd->tmPending == 0) {
2095 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002096 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 break;
2098 }
2099 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002100 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 } while (--loop_count);
2102
2103 return status;
2104}
2105
2106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002107static void
2108mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2109{
2110 char *desc;
2111
2112 switch (response_code) {
2113 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2114 desc = "The task completed.";
2115 break;
2116 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2117 desc = "The IOC received an invalid frame status.";
2118 break;
2119 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2120 desc = "The task type is not supported.";
2121 break;
2122 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2123 desc = "The requested task failed.";
2124 break;
2125 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2126 desc = "The task completed successfully.";
2127 break;
2128 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2129 desc = "The LUN request is invalid.";
2130 break;
2131 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2132 desc = "The task is in the IOC queue and has not been sent to target.";
2133 break;
2134 default:
2135 desc = "unknown";
2136 break;
2137 }
2138 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2139 ioc->name, response_code, desc);
2140}
2141
2142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143/**
2144 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2145 * @ioc: Pointer to MPT_ADAPTER structure
2146 * @mf: Pointer to SCSI task mgmt request frame
2147 * @mr: Pointer to SCSI task mgmt reply frame
2148 *
2149 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2150 * of any SCSI task management request.
2151 * This routine is registered with the MPT (base) driver at driver
2152 * load/init time via the mpt_register() API call.
2153 *
2154 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002155 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002156int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2158{
2159 SCSITaskMgmtReply_t *pScsiTmReply;
2160 SCSITaskMgmt_t *pScsiTmReq;
2161 MPT_SCSI_HOST *hd;
2162 unsigned long flags;
2163 u16 iocstatus;
2164 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002165 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302167 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002168 ioc->name, mf, mr));
2169 if (!ioc->sh) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302170 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002171 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 return 1;
2173 }
2174
2175 if (mr == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302176 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002177 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 }
2180
Eric Moorecd2c6192007-01-29 09:47:47 -07002181 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2182 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2183 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2184 tmType = pScsiTmReq->TaskType;
2185 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2186 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2187
2188 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2189 pScsiTmReply->ResponseCode)
2190 mptscsih_taskmgmt_response_code(ioc,
2191 pScsiTmReply->ResponseCode);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302192 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Eric Moorecd2c6192007-01-29 09:47:47 -07002193
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302194#ifdef CONFIG_FUSION_LOGGING
2195 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2196 (ioc->debug_level & MPT_DEBUG_TM ))
2197 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2198 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2199 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2200 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2201 le16_to_cpu(pScsiTmReply->IOCStatus),
2202 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2203 le32_to_cpu(pScsiTmReply->TerminationCount));
Eric Moorecd2c6192007-01-29 09:47:47 -07002204#endif
2205 if (!iocstatus) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302206 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
Eric Moorecd2c6192007-01-29 09:47:47 -07002207 hd->abortSCpnt = NULL;
2208 goto out;
2209 }
2210
2211 /* Error? (anything non-zero?) */
2212
2213 /* clear flags and continue.
2214 */
2215 switch (tmType) {
2216
2217 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2218 if (termination_count == 1)
2219 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2220 hd->abortSCpnt = NULL;
2221 break;
2222
2223 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2224
2225 /* If an internal command is present
2226 * or the TM failed - reload the FW.
2227 * FC FW may respond FAILED to an ABORT
2228 */
2229 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2230 hd->cmdPtr)
2231 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2232 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2233 break;
2234
2235 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2236 default:
2237 break;
2238 }
2239
2240 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 spin_lock_irqsave(&ioc->FreeQlock, flags);
2242 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002244 hd->tm_iocstatus = iocstatus;
2245 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 return 1;
2248}
2249
2250/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2251/*
2252 * This is anyones guess quite frankly.
2253 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002254int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2256 sector_t capacity, int geom[])
2257{
2258 int heads;
2259 int sectors;
2260 sector_t cylinders;
2261 ulong dummy;
2262
2263 heads = 64;
2264 sectors = 32;
2265
2266 dummy = heads * sectors;
2267 cylinders = capacity;
2268 sector_div(cylinders,dummy);
2269
2270 /*
2271 * Handle extended translation size for logical drives
2272 * > 1Gb
2273 */
2274 if ((ulong)capacity >= 0x200000) {
2275 heads = 255;
2276 sectors = 63;
2277 dummy = heads * sectors;
2278 cylinders = capacity;
2279 sector_div(cylinders,dummy);
2280 }
2281
2282 /* return result */
2283 geom[0] = heads;
2284 geom[1] = sectors;
2285 geom[2] = cylinders;
2286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 return 0;
2288}
2289
Moore, Ericf44e5462006-03-14 09:14:21 -07002290/* Search IOC page 3 to determine if this is hidden physical disk
2291 *
2292 */
2293int
Eric Moore793955f2007-01-29 09:42:20 -07002294mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002295{
Eric Mooreb506ade2007-01-29 09:45:37 -07002296 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002297 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002298 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002299
Eric Moore793955f2007-01-29 09:42:20 -07002300 if (!ioc->raid_data.pIocPg3)
2301 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002302 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002303 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2304 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2305 rc = 1;
2306 goto out;
2307 }
2308 }
2309
Eric Mooreb506ade2007-01-29 09:45:37 -07002310 /*
2311 * Check inactive list for matching phys disks
2312 */
2313 if (list_empty(&ioc->raid_data.inactive_list))
2314 goto out;
2315
2316 down(&ioc->raid_data.inactive_list_mutex);
2317 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2318 list) {
2319 if ((component_info->d.PhysDiskID == id) &&
2320 (component_info->d.PhysDiskBus == channel))
2321 rc = 1;
2322 }
2323 up(&ioc->raid_data.inactive_list_mutex);
2324
Eric Moore793955f2007-01-29 09:42:20 -07002325 out:
2326 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002327}
2328EXPORT_SYMBOL(mptscsih_is_phys_disk);
2329
Eric Moore793955f2007-01-29 09:42:20 -07002330u8
2331mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002332{
Eric Mooreb506ade2007-01-29 09:45:37 -07002333 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002334 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002335 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002336
Eric Moore793955f2007-01-29 09:42:20 -07002337 if (!ioc->raid_data.pIocPg3)
2338 goto out;
2339 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2340 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2341 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2342 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2343 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002344 }
2345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
Eric Mooreb506ade2007-01-29 09:45:37 -07002347 /*
2348 * Check inactive list for matching phys disks
2349 */
2350 if (list_empty(&ioc->raid_data.inactive_list))
2351 goto out;
2352
2353 down(&ioc->raid_data.inactive_list_mutex);
2354 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2355 list) {
2356 if ((component_info->d.PhysDiskID == id) &&
2357 (component_info->d.PhysDiskBus == channel))
2358 rc = component_info->d.PhysDiskNum;
2359 }
2360 up(&ioc->raid_data.inactive_list_mutex);
2361
Eric Moore793955f2007-01-29 09:42:20 -07002362 out:
2363 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002364}
Eric Moore793955f2007-01-29 09:42:20 -07002365EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002366
2367/*
2368 * OS entry point to allow for host driver to free allocated memory
2369 * Called if no device present or device being unloaded
2370 */
2371void
2372mptscsih_slave_destroy(struct scsi_device *sdev)
2373{
2374 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002376 VirtTarget *vtarget;
2377 VirtDevice *vdevice;
2378 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002380 starget = scsi_target(sdev);
2381 vtarget = starget->hostdata;
2382 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002384 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002385 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002386 mptscsih_synchronize_cache(hd, vdevice);
2387 kfree(vdevice);
2388 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389}
2390
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002391/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2392/*
2393 * mptscsih_change_queue_depth - This function will set a devices queue depth
2394 * @sdev: per scsi_device pointer
2395 * @qdepth: requested queue depth
2396 *
2397 * Adding support for new 'change_queue_depth' api.
2398*/
2399int
2400mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002402 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2403 VirtTarget *vtarget;
2404 struct scsi_target *starget;
2405 int max_depth;
2406 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002408 starget = scsi_target(sdev);
2409 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002410
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002411 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002412 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002414 else if (sdev->type == TYPE_DISK &&
2415 vtarget->minSyncFactor <= MPT_ULTRA160)
2416 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2417 else
2418 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 } else
2420 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2421
2422 if (qdepth > max_depth)
2423 qdepth = max_depth;
2424 if (qdepth == 1)
2425 tagged = 0;
2426 else
2427 tagged = MSG_SIMPLE_TAG;
2428
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002429 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2430 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431}
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433/*
2434 * OS entry point to adjust the queue_depths on a per-device basis.
2435 * Called once per device the bus scan. Use it to force the queue_depth
2436 * member to 1 if a device does not support Q tags.
2437 * Return non-zero if fails.
2438 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002439int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002440mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002442 struct Scsi_Host *sh = sdev->host;
2443 VirtTarget *vtarget;
2444 VirtDevice *vdevice;
2445 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2447
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002448 starget = scsi_target(sdev);
2449 vtarget = starget->hostdata;
2450 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302452 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002453 "device @ %p, channel=%d, id=%d, lun=%d\n",
2454 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002455 if (hd->ioc->bus_type == SPI)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302456 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002457 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2458 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2459 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002461 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002463 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 goto slave_configure_exit;
2465 }
2466
Eric Moore793955f2007-01-29 09:42:20 -07002467 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002468 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302470 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002472 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002474 if (hd->ioc->bus_type == SPI)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302475 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002476 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2477 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2478 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480slave_configure_exit:
2481
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302482 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002484 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2485 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 return 0;
2488}
2489
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2491/*
2492 * Private routines...
2493 */
2494
2495/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2496/* Utility function to copy sense data from the scsi_cmnd buffer
2497 * to the FC and SCSI target structures.
2498 *
2499 */
2500static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002501mptscsih_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 -07002502{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002503 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 SCSIIORequest_t *pReq;
2505 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
2507 /* Get target structure
2508 */
2509 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002510 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 if (sense_count) {
2513 u8 *sense_data;
2514 int req_index;
2515
2516 /* Copy the sense received into the scsi command block. */
2517 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2518 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2519 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2520
2521 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2522 */
2523 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002524 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 int idx;
2526 MPT_ADAPTER *ioc = hd->ioc;
2527
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002528 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2530 ioc->events[idx].eventContext = ioc->eventContext;
2531
Dave Jones3d9780b2007-05-21 20:59:47 -04002532 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2533 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2534 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Dave Jones3d9780b2007-05-21 20:59:47 -04002536 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
2538 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002539 if (hd->ioc->pcidev->vendor ==
2540 PCI_VENDOR_ID_IBM) {
2541 mptscsih_issue_sep_command(hd->ioc,
2542 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2543 vdev->vtarget->tflags |=
2544 MPT_TARGET_FLAGS_LED_ON;
2545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547 }
2548 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302549 dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 hd->ioc->name));
2551 }
2552}
2553
Eric Moore3dc0b032006-07-11 17:32:33 -06002554static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2556{
2557 MPT_SCSI_HOST *hd;
2558 int i;
2559
2560 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2561
2562 for (i = 0; i < hd->ioc->req_depth; i++) {
2563 if (hd->ScsiLookup[i] == sc) {
2564 return i;
2565 }
2566 }
2567
2568 return -1;
2569}
2570
2571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002572int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2574{
2575 MPT_SCSI_HOST *hd;
2576 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002577 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302579 dtmprintk(ioc, printk(KERN_DEBUG MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 ": IOC %s_reset routed to SCSI host driver!\n",
2581 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2582 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2583
2584 /* If a FW reload request arrives after base installed but
2585 * before all scsi hosts have been attached, then an alt_ioc
2586 * may have a NULL sh pointer.
2587 */
2588 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2589 return 0;
2590 else
2591 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2592
2593 if (reset_phase == MPT_IOC_SETUP_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302594 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595
2596 /* Clean Up:
2597 * 1. Set Hard Reset Pending Flag
2598 * All new commands go to doneQ
2599 */
2600 hd->resetPending = 1;
2601
2602 } else if (reset_phase == MPT_IOC_PRE_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302603 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 /* 2. Flush running commands
2606 * Clean ScsiLookup (and associated memory)
2607 * AND clean mytaskQ
2608 */
2609
2610 /* 2b. Reply to OS all known outstanding I/O commands.
2611 */
2612 mptscsih_flush_running_cmds(hd);
2613
2614 /* 2c. If there was an internal command that
2615 * has not completed, configuration or io request,
2616 * free these resources.
2617 */
2618 if (hd->cmdPtr) {
2619 del_timer(&hd->timer);
2620 mpt_free_msg_frame(ioc, hd->cmdPtr);
2621 }
2622
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302623 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302626 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628 /* Once a FW reload begins, all new OS commands are
2629 * redirected to the doneQ w/ a reset status.
2630 * Init all control structures.
2631 */
2632
2633 /* ScsiLookup initialization
2634 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002635 for (ii=0; ii < hd->ioc->req_depth; ii++)
2636 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
2638 /* 2. Chain Buffer initialization
2639 */
2640
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002641 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
2644 /* 5. Enable new commands to be posted
2645 */
2646 spin_lock_irqsave(&ioc->FreeQlock, flags);
2647 hd->tmPending = 0;
2648 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2649 hd->resetPending = 0;
2650 hd->tmState = TM_STATE_NONE;
2651
2652 /* 6. If there was an internal command,
2653 * wake this process up.
2654 */
2655 if (hd->cmdPtr) {
2656 /*
2657 * Wake up the original calling thread
2658 */
2659 hd->pLocal = &hd->localReply;
2660 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002661 hd->scandv_wait_done = 1;
2662 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 hd->cmdPtr = NULL;
2664 }
2665
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302666 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
2668 }
2669
2670 return 1; /* currently means nothing really */
2671}
2672
2673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002674int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2676{
2677 MPT_SCSI_HOST *hd;
2678 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2679
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302680 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 ioc->name, event));
2682
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002683 if (ioc->sh == NULL ||
2684 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2685 return 1;
2686
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 switch (event) {
2688 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2689 /* FIXME! */
2690 break;
2691 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2692 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002693 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002694 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 break;
2696 case MPI_EVENT_LOGOUT: /* 09 */
2697 /* FIXME! */
2698 break;
2699
Michael Reed05e8ec12006-01-13 14:31:54 -06002700 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002701 break;
2702
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 /*
2704 * CHECKME! Don't think we need to do
2705 * anything for these, but...
2706 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2708 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2709 /*
2710 * CHECKME! Falling thru...
2711 */
2712 break;
2713
2714 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002715 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 case MPI_EVENT_NONE: /* 00 */
2718 case MPI_EVENT_LOG_DATA: /* 01 */
2719 case MPI_EVENT_STATE_CHANGE: /* 02 */
2720 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2721 default:
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302722 dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 break;
2724 }
2725
2726 return 1; /* currently means nothing really */
2727}
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2730/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 * Bus Scan and Domain Validation functionality ...
2732 */
2733
2734/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2735/*
2736 * mptscsih_scandv_complete - Scan and DV callback routine registered
2737 * to Fustion MPT (base) driver.
2738 *
2739 * @ioc: Pointer to MPT_ADAPTER structure
2740 * @mf: Pointer to original MPT request frame
2741 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2742 *
2743 * This routine is called from mpt.c::mpt_interrupt() at the completion
2744 * of any SCSI IO request.
2745 * This routine is registered with the Fusion MPT (base) driver at driver
2746 * load/init time via the mpt_register() API call.
2747 *
2748 * Returns 1 indicating alloc'd request frame ptr should be freed.
2749 *
2750 * Remark: Sets a completion code and (possibly) saves sense data
2751 * in the IOC member localReply structure.
2752 * Used ONLY for DV and other internal commands.
2753 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002754int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2756{
2757 MPT_SCSI_HOST *hd;
2758 SCSIIORequest_t *pReq;
2759 int completionCode;
2760 u16 req_idx;
2761
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002762 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2763
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 if ((mf == NULL) ||
2765 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2766 printk(MYIOC_s_ERR_FMT
2767 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2768 ioc->name, mf?"BAD":"NULL", (void *) mf);
2769 goto wakeup;
2770 }
2771
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 del_timer(&hd->timer);
2773 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2774 hd->ScsiLookup[req_idx] = NULL;
2775 pReq = (SCSIIORequest_t *) mf;
2776
2777 if (mf != hd->cmdPtr) {
2778 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2779 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2780 }
2781 hd->cmdPtr = NULL;
2782
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302783 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 hd->ioc->name, mf, mr, req_idx));
2785
2786 hd->pLocal = &hd->localReply;
2787 hd->pLocal->scsiStatus = 0;
2788
2789 /* If target struct exists, clear sense valid flag.
2790 */
2791 if (mr == NULL) {
2792 completionCode = MPT_SCANDV_GOOD;
2793 } else {
2794 SCSIIOReply_t *pReply;
2795 u16 status;
2796 u8 scsi_status;
2797
2798 pReply = (SCSIIOReply_t *) mr;
2799
2800 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2801 scsi_status = pReply->SCSIStatus;
2802
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
2804 switch(status) {
2805
2806 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2807 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2808 break;
2809
2810 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2811 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2812 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2813 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2814 completionCode = MPT_SCANDV_DID_RESET;
2815 break;
2816
2817 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2818 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2819 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2820 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2821 ConfigReply_t *pr = (ConfigReply_t *)mr;
2822 completionCode = MPT_SCANDV_GOOD;
2823 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2824 hd->pLocal->header.PageLength = pr->Header.PageLength;
2825 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2826 hd->pLocal->header.PageType = pr->Header.PageType;
2827
2828 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2829 /* If the RAID Volume request is successful,
2830 * return GOOD, else indicate that
2831 * some type of error occurred.
2832 */
2833 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002834 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 completionCode = MPT_SCANDV_GOOD;
2836 else
2837 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002838 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
2840 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2841 u8 *sense_data;
2842 int sz;
2843
2844 /* save sense data in global structure
2845 */
2846 completionCode = MPT_SCANDV_SENSE;
2847 hd->pLocal->scsiStatus = scsi_status;
2848 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2849 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2850
2851 sz = min_t(int, pReq->SenseBufferLength,
2852 SCSI_STD_SENSE_BYTES);
2853 memcpy(hd->pLocal->sense, sense_data, sz);
2854
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302855 ddvprintk(ioc, printk(KERN_DEBUG " Check Condition, sense ptr %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 sense_data));
2857 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2858 if (pReq->CDB[0] == INQUIRY)
2859 completionCode = MPT_SCANDV_ISSUE_SENSE;
2860 else
2861 completionCode = MPT_SCANDV_DID_RESET;
2862 }
2863 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2864 completionCode = MPT_SCANDV_DID_RESET;
2865 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2866 completionCode = MPT_SCANDV_DID_RESET;
2867 else {
2868 completionCode = MPT_SCANDV_GOOD;
2869 hd->pLocal->scsiStatus = scsi_status;
2870 }
2871 break;
2872
2873 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2874 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2875 completionCode = MPT_SCANDV_DID_RESET;
2876 else
2877 completionCode = MPT_SCANDV_SOME_ERROR;
2878 break;
2879
2880 default:
2881 completionCode = MPT_SCANDV_SOME_ERROR;
2882 break;
2883
2884 } /* switch(status) */
2885
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 } /* end of address reply case */
2887
2888 hd->pLocal->completion = completionCode;
2889
2890 /* MF and RF are freed in mpt_interrupt
2891 */
2892wakeup:
2893 /* Free Chain buffers (will never chain) in scan or dv */
2894 //mptscsih_freeChainBuffers(ioc, req_idx);
2895
2896 /*
2897 * Wake up the original calling thread
2898 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002899 hd->scandv_wait_done = 1;
2900 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902 return 1;
2903}
2904
2905/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2906/* mptscsih_timer_expired - Call back for timer process.
2907 * Used only for dv functionality.
2908 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2909 *
2910 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002911void
2912mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913{
2914 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2915
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302916 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
2918 if (hd->cmdPtr) {
2919 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2920
2921 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2922 /* Desire to issue a task management request here.
2923 * TM requests MUST be single threaded.
2924 * If old eh code and no TM current, issue request.
2925 * If new eh code, do nothing. Wait for OS cmd timeout
2926 * for bus reset.
2927 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 } else {
2929 /* Perform a FW reload */
2930 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2931 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2932 }
2933 }
2934 } else {
2935 /* This should NEVER happen */
2936 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2937 }
2938
2939 /* No more processing.
2940 * TM call will generate an interrupt for SCSI TM Management.
2941 * The FW will reply to all outstanding commands, callback will finish cleanup.
2942 * Hard reset clean-up will free all resources.
2943 */
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302944 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
2946 return;
2947}
2948
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
2950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2951/**
2952 * mptscsih_do_cmd - Do internal command.
2953 * @hd: MPT_SCSI_HOST pointer
2954 * @io: INTERNAL_CMD pointer.
2955 *
2956 * Issue the specified internally generated command and do command
2957 * specific cleanup. For bus scan / DV only.
2958 * NOTES: If command is Inquiry and status is good,
2959 * initialize a target structure, save the data
2960 *
2961 * Remark: Single threaded access only.
2962 *
2963 * Return:
2964 * < 0 if an illegal command or no resources
2965 *
2966 * 0 if good
2967 *
2968 * > 0 if command complete but some type of completion error.
2969 */
2970static int
2971mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2972{
2973 MPT_FRAME_HDR *mf;
2974 SCSIIORequest_t *pScsiReq;
2975 SCSIIORequest_t ReqCopy;
2976 int my_idx, ii, dir;
2977 int rc, cmdTimeout;
2978 int in_isr;
2979 char cmdLen;
2980 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2981 char cmd = io->cmd;
2982
2983 in_isr = in_interrupt();
2984 if (in_isr) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302985 dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 hd->ioc->name));
2987 return -EPERM;
2988 }
2989
2990
2991 /* Set command specific information
2992 */
2993 switch (cmd) {
2994 case INQUIRY:
2995 cmdLen = 6;
2996 dir = MPI_SCSIIO_CONTROL_READ;
2997 CDB[0] = cmd;
2998 CDB[4] = io->size;
2999 cmdTimeout = 10;
3000 break;
3001
3002 case TEST_UNIT_READY:
3003 cmdLen = 6;
3004 dir = MPI_SCSIIO_CONTROL_READ;
3005 cmdTimeout = 10;
3006 break;
3007
3008 case START_STOP:
3009 cmdLen = 6;
3010 dir = MPI_SCSIIO_CONTROL_READ;
3011 CDB[0] = cmd;
3012 CDB[4] = 1; /*Spin up the disk */
3013 cmdTimeout = 15;
3014 break;
3015
3016 case REQUEST_SENSE:
3017 cmdLen = 6;
3018 CDB[0] = cmd;
3019 CDB[4] = io->size;
3020 dir = MPI_SCSIIO_CONTROL_READ;
3021 cmdTimeout = 10;
3022 break;
3023
3024 case READ_BUFFER:
3025 cmdLen = 10;
3026 dir = MPI_SCSIIO_CONTROL_READ;
3027 CDB[0] = cmd;
3028 if (io->flags & MPT_ICFLAG_ECHO) {
3029 CDB[1] = 0x0A;
3030 } else {
3031 CDB[1] = 0x02;
3032 }
3033
3034 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3035 CDB[1] |= 0x01;
3036 }
3037 CDB[6] = (io->size >> 16) & 0xFF;
3038 CDB[7] = (io->size >> 8) & 0xFF;
3039 CDB[8] = io->size & 0xFF;
3040 cmdTimeout = 10;
3041 break;
3042
3043 case WRITE_BUFFER:
3044 cmdLen = 10;
3045 dir = MPI_SCSIIO_CONTROL_WRITE;
3046 CDB[0] = cmd;
3047 if (io->flags & MPT_ICFLAG_ECHO) {
3048 CDB[1] = 0x0A;
3049 } else {
3050 CDB[1] = 0x02;
3051 }
3052 CDB[6] = (io->size >> 16) & 0xFF;
3053 CDB[7] = (io->size >> 8) & 0xFF;
3054 CDB[8] = io->size & 0xFF;
3055 cmdTimeout = 10;
3056 break;
3057
3058 case RESERVE:
3059 cmdLen = 6;
3060 dir = MPI_SCSIIO_CONTROL_READ;
3061 CDB[0] = cmd;
3062 cmdTimeout = 10;
3063 break;
3064
3065 case RELEASE:
3066 cmdLen = 6;
3067 dir = MPI_SCSIIO_CONTROL_READ;
3068 CDB[0] = cmd;
3069 cmdTimeout = 10;
3070 break;
3071
3072 case SYNCHRONIZE_CACHE:
3073 cmdLen = 10;
3074 dir = MPI_SCSIIO_CONTROL_READ;
3075 CDB[0] = cmd;
3076// CDB[1] = 0x02; /* set immediate bit */
3077 cmdTimeout = 10;
3078 break;
3079
3080 default:
3081 /* Error Case */
3082 return -EFAULT;
3083 }
3084
3085 /* Get and Populate a free Frame
3086 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003087 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303088 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 hd->ioc->name));
3090 return -EBUSY;
3091 }
3092
3093 pScsiReq = (SCSIIORequest_t *) mf;
3094
3095 /* Get the request index */
3096 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3097 ADD_INDEX_LOG(my_idx); /* for debug */
3098
3099 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3100 pScsiReq->TargetID = io->physDiskNum;
3101 pScsiReq->Bus = 0;
3102 pScsiReq->ChainOffset = 0;
3103 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3104 } else {
3105 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003106 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 pScsiReq->ChainOffset = 0;
3108 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3109 }
3110
3111 pScsiReq->CDBLength = cmdLen;
3112 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3113
3114 pScsiReq->Reserved = 0;
3115
3116 pScsiReq->MsgFlags = mpt_msg_flags();
3117 /* MsgContext set in mpt_get_msg_fram call */
3118
Eric Moore793955f2007-01-29 09:42:20 -07003119 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3122 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3123 else
3124 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3125
3126 if (cmd == REQUEST_SENSE) {
3127 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303128 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 hd->ioc->name, cmd));
3130 }
3131
3132 for (ii=0; ii < 16; ii++)
3133 pScsiReq->CDB[ii] = CDB[ii];
3134
3135 pScsiReq->DataLength = cpu_to_le32(io->size);
3136 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3137 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3138
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303139 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003140 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
3142 if (dir == MPI_SCSIIO_CONTROL_READ) {
3143 mpt_add_sge((char *) &pScsiReq->SGL,
3144 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3145 io->data_dma);
3146 } else {
3147 mpt_add_sge((char *) &pScsiReq->SGL,
3148 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3149 io->data_dma);
3150 }
3151
3152 /* The ISR will free the request frame, but we need
3153 * the information to initialize the target. Duplicate.
3154 */
3155 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3156
3157 /* Issue this command after:
3158 * finish init
3159 * add timer
3160 * Wait until the reply has been received
3161 * ScsiScanDvCtx callback function will
3162 * set hd->pLocal;
3163 * set scandv_wait_done and call wake_up
3164 */
3165 hd->pLocal = NULL;
3166 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003167 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
3169 /* Save cmd pointer, for resource free if timeout or
3170 * FW reload occurs
3171 */
3172 hd->cmdPtr = mf;
3173
3174 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003175 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3176 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
3178 if (hd->pLocal) {
3179 rc = hd->pLocal->completion;
3180 hd->pLocal->skip = 0;
3181
3182 /* Always set fatal error codes in some cases.
3183 */
3184 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3185 rc = -ENXIO;
3186 else if (rc == MPT_SCANDV_SOME_ERROR)
3187 rc = -rc;
3188 } else {
3189 rc = -EFAULT;
3190 /* This should never happen. */
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303191 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 hd->ioc->name));
3193 }
3194
3195 return rc;
3196}
3197
3198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3199/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003200 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3201 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003202 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003203 *
3204 * Uses the ISR, but with special processing.
3205 * MUST be single-threaded.
3206 *
3207 */
3208static void
3209mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3210{
3211 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
Eric Moorecc78d302007-06-15 17:27:21 -06003213 /* Ignore hidden raid components, this is handled when the command
3214 * is sent to the volume
3215 */
3216 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3217 return;
3218
3219 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3220 !vdevice->configured_lun)
3221 return;
3222
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 /* Following parameters will not change
3224 * in this routine.
3225 */
3226 iocmd.cmd = SYNCHRONIZE_CACHE;
3227 iocmd.flags = 0;
3228 iocmd.physDiskNum = -1;
3229 iocmd.data = NULL;
3230 iocmd.data_dma = -1;
3231 iocmd.size = 0;
3232 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003233 iocmd.channel = vdevice->vtarget->channel;
3234 iocmd.id = vdevice->vtarget->id;
3235 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
Eric Moorecc78d302007-06-15 17:27:21 -06003237 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238}
3239
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303240static ssize_t
3241mptscsih_version_fw_show(struct class_device *cdev, char *buf)
3242{
3243 struct Scsi_Host *host = class_to_shost(cdev);
3244 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3245 MPT_ADAPTER *ioc = hd->ioc;
3246
3247 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3248 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3249 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3250 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3251 ioc->facts.FWVersion.Word & 0x000000FF);
3252}
3253static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3254
3255static ssize_t
3256mptscsih_version_bios_show(struct class_device *cdev, char *buf)
3257{
3258 struct Scsi_Host *host = class_to_shost(cdev);
3259 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3260 MPT_ADAPTER *ioc = hd->ioc;
3261
3262 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3263 (ioc->biosVersion & 0xFF000000) >> 24,
3264 (ioc->biosVersion & 0x00FF0000) >> 16,
3265 (ioc->biosVersion & 0x0000FF00) >> 8,
3266 ioc->biosVersion & 0x000000FF);
3267}
3268static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3269
3270static ssize_t
3271mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
3272{
3273 struct Scsi_Host *host = class_to_shost(cdev);
3274 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3275 MPT_ADAPTER *ioc = hd->ioc;
3276
3277 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3278}
3279static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3280
3281static ssize_t
3282mptscsih_version_product_show(struct class_device *cdev, char *buf)
3283{
3284 struct Scsi_Host *host = class_to_shost(cdev);
3285 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3286 MPT_ADAPTER *ioc = hd->ioc;
3287
3288 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3289}
3290static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
3291 mptscsih_version_product_show, NULL);
3292
3293static ssize_t
3294mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
3295{
3296 struct Scsi_Host *host = class_to_shost(cdev);
3297 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3298 MPT_ADAPTER *ioc = hd->ioc;
3299
3300 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3301 ioc->nvdata_version_persistent);
3302}
3303static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3304 mptscsih_version_nvdata_persistent_show, NULL);
3305
3306static ssize_t
3307mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
3308{
3309 struct Scsi_Host *host = class_to_shost(cdev);
3310 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3311 MPT_ADAPTER *ioc = hd->ioc;
3312
3313 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3314}
3315static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3316 mptscsih_version_nvdata_default_show, NULL);
3317
3318static ssize_t
3319mptscsih_board_name_show(struct class_device *cdev, char *buf)
3320{
3321 struct Scsi_Host *host = class_to_shost(cdev);
3322 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3323 MPT_ADAPTER *ioc = hd->ioc;
3324
3325 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3326}
3327static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3328
3329static ssize_t
3330mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
3331{
3332 struct Scsi_Host *host = class_to_shost(cdev);
3333 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3334 MPT_ADAPTER *ioc = hd->ioc;
3335
3336 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3337}
3338static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
3339 mptscsih_board_assembly_show, NULL);
3340
3341static ssize_t
3342mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
3343{
3344 struct Scsi_Host *host = class_to_shost(cdev);
3345 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3346 MPT_ADAPTER *ioc = hd->ioc;
3347
3348 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3349}
3350static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
3351 mptscsih_board_tracer_show, NULL);
3352
3353static ssize_t
3354mptscsih_io_delay_show(struct class_device *cdev, char *buf)
3355{
3356 struct Scsi_Host *host = class_to_shost(cdev);
3357 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3358 MPT_ADAPTER *ioc = hd->ioc;
3359
3360 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3361}
3362static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
3363 mptscsih_io_delay_show, NULL);
3364
3365static ssize_t
3366mptscsih_device_delay_show(struct class_device *cdev, char *buf)
3367{
3368 struct Scsi_Host *host = class_to_shost(cdev);
3369 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3370 MPT_ADAPTER *ioc = hd->ioc;
3371
3372 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3373}
3374static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
3375 mptscsih_device_delay_show, NULL);
3376
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303377static ssize_t
3378mptscsih_debug_level_show(struct class_device *cdev, char *buf)
3379{
3380 struct Scsi_Host *host = class_to_shost(cdev);
3381 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3382 MPT_ADAPTER *ioc = hd->ioc;
3383
3384 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3385}
3386static ssize_t
3387mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
3388 size_t count)
3389{
3390 struct Scsi_Host *host = class_to_shost(cdev);
3391 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3392 MPT_ADAPTER *ioc = hd->ioc;
3393 int val = 0;
3394
3395 if (sscanf(buf, "%x", &val) != 1)
3396 return -EINVAL;
3397
3398 ioc->debug_level = val;
3399 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3400 ioc->name, ioc->debug_level);
3401 return strlen(buf);
3402}
3403static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3404 mptscsih_debug_level_show, mptscsih_debug_level_store);
3405
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303406struct class_device_attribute *mptscsih_host_attrs[] = {
3407 &class_device_attr_version_fw,
3408 &class_device_attr_version_bios,
3409 &class_device_attr_version_mpi,
3410 &class_device_attr_version_product,
3411 &class_device_attr_version_nvdata_persistent,
3412 &class_device_attr_version_nvdata_default,
3413 &class_device_attr_board_name,
3414 &class_device_attr_board_assembly,
3415 &class_device_attr_board_tracer,
3416 &class_device_attr_io_delay,
3417 &class_device_attr_device_delay,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303418 &class_device_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303419 NULL,
3420};
3421EXPORT_SYMBOL(mptscsih_host_attrs);
3422
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003423EXPORT_SYMBOL(mptscsih_remove);
3424EXPORT_SYMBOL(mptscsih_shutdown);
3425#ifdef CONFIG_PM
3426EXPORT_SYMBOL(mptscsih_suspend);
3427EXPORT_SYMBOL(mptscsih_resume);
3428#endif
3429EXPORT_SYMBOL(mptscsih_proc_info);
3430EXPORT_SYMBOL(mptscsih_info);
3431EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003432EXPORT_SYMBOL(mptscsih_slave_destroy);
3433EXPORT_SYMBOL(mptscsih_slave_configure);
3434EXPORT_SYMBOL(mptscsih_abort);
3435EXPORT_SYMBOL(mptscsih_dev_reset);
3436EXPORT_SYMBOL(mptscsih_bus_reset);
3437EXPORT_SYMBOL(mptscsih_host_reset);
3438EXPORT_SYMBOL(mptscsih_bios_param);
3439EXPORT_SYMBOL(mptscsih_io_done);
3440EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3441EXPORT_SYMBOL(mptscsih_scandv_complete);
3442EXPORT_SYMBOL(mptscsih_event_process);
3443EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003444EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003445EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003446EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003448/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/