blob: 02f95900e09578318bf9da6fd3ddcf3f689ffd51 [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",
Eric Moore29dd3602007-09-14 18:46:51 -0600195 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 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;
Eric Moore29dd3602007-09-14 18:46:51 -0600206 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
207 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
208 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 } else {
210 rc = FAILED;
211 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600212 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
213 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 }
215 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
216
217 *retIndex = chain_idx;
218 return rc;
219} /* mptscsih_getFreeChainBuffer() */
220
221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
222/*
223 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
224 * SCSIIORequest_t Message Frame.
225 * @ioc: Pointer to MPT_ADAPTER structure
226 * @SCpnt: Pointer to scsi_cmnd structure
227 * @pReq: Pointer to SCSIIORequest_t structure
228 *
229 * Returns ...
230 */
231static int
232mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
233 SCSIIORequest_t *pReq, int req_idx)
234{
235 char *psge;
236 char *chainSge;
237 struct scatterlist *sg;
238 int frm_sz;
239 int sges_left, sg_done;
240 int chain_idx = MPT_HOST_NO_CHAIN;
241 int sgeOffset;
242 int numSgeSlots, numSgeThisFrame;
243 u32 sgflags, sgdir, thisxfer = 0;
244 int chain_dma_off = 0;
245 int newIndex;
246 int ii;
247 dma_addr_t v2;
248 u32 RequestNB;
249
250 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
251 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
252 sgdir = MPT_TRANSFER_HOST_TO_IOC;
253 } else {
254 sgdir = MPT_TRANSFER_IOC_TO_HOST;
255 }
256
257 psge = (char *) &pReq->SGL;
258 frm_sz = ioc->req_sz;
259
260 /* Map the data portion, if any.
261 * sges_left = 0 if no data transfer.
262 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900263 sges_left = scsi_dma_map(SCpnt);
264 if (sges_left < 0)
265 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 /* Handle the SG case.
268 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900269 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sg_done = 0;
271 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
272 chainSge = NULL;
273
274 /* Prior to entering this loop - the following must be set
275 * current MF: sgeOffset (bytes)
276 * chainSge (Null if original MF is not a chain buffer)
277 * sg_done (num SGE done for this MF)
278 */
279
280nextSGEset:
281 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
282 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
283
284 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
285
286 /* Get first (num - 1) SG elements
287 * Skip any SG entries with a length of 0
288 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
289 */
290 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
291 thisxfer = sg_dma_len(sg);
292 if (thisxfer == 0) {
293 sg ++; /* Get next SG element from the OS */
294 sg_done++;
295 continue;
296 }
297
298 v2 = sg_dma_address(sg);
299 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
300
301 sg++; /* Get next SG element from the OS */
302 psge += (sizeof(u32) + sizeof(dma_addr_t));
303 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
304 sg_done++;
305 }
306
307 if (numSgeThisFrame == sges_left) {
308 /* Add last element, end of buffer and end of list flags.
309 */
310 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
311 MPT_SGE_FLAGS_END_OF_BUFFER |
312 MPT_SGE_FLAGS_END_OF_LIST;
313
314 /* Add last SGE and set termination flags.
315 * Note: Last SGE may have a length of 0 - which should be ok.
316 */
317 thisxfer = sg_dma_len(sg);
318
319 v2 = sg_dma_address(sg);
320 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
321 /*
322 sg++;
323 psge += (sizeof(u32) + sizeof(dma_addr_t));
324 */
325 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
326 sg_done++;
327
328 if (chainSge) {
329 /* The current buffer is a chain buffer,
330 * but there is not another one.
331 * Update the chain element
332 * Offset and Length fields.
333 */
334 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
335 } else {
336 /* The current buffer is the original MF
337 * and there is no Chain buffer.
338 */
339 pReq->ChainOffset = 0;
340 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530341 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
343 ioc->RequestNB[req_idx] = RequestNB;
344 }
345 } else {
346 /* At least one chain buffer is needed.
347 * Complete the first MF
348 * - last SGE element, set the LastElement bit
349 * - set ChainOffset (words) for orig MF
350 * (OR finish previous MF chain buffer)
351 * - update MFStructPtr ChainIndex
352 * - Populate chain element
353 * Also
354 * Loop until done.
355 */
356
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530357 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 ioc->name, sg_done));
359
360 /* Set LAST_ELEMENT flag for last non-chain element
361 * in the buffer. Since psge points at the NEXT
362 * SGE element, go back one SGE element, update the flags
363 * and reset the pointer. (Note: sgflags & thisxfer are already
364 * set properly).
365 */
366 if (sg_done) {
367 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
368 sgflags = le32_to_cpu(*ptmp);
369 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
370 *ptmp = cpu_to_le32(sgflags);
371 }
372
373 if (chainSge) {
374 /* The current buffer is a chain buffer.
375 * chainSge points to the previous Chain Element.
376 * Update its chain element Offset and Length (must
377 * include chain element size) fields.
378 * Old chain element is now complete.
379 */
380 u8 nextChain = (u8) (sgeOffset >> 2);
381 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
382 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
383 } else {
384 /* The original MF buffer requires a chain buffer -
385 * set the offset.
386 * Last element in this MF is a chain element.
387 */
388 pReq->ChainOffset = (u8) (sgeOffset >> 2);
389 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530390 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 -0700391 ioc->RequestNB[req_idx] = RequestNB;
392 }
393
394 sges_left -= sg_done;
395
396
397 /* NOTE: psge points to the beginning of the chain element
398 * in current buffer. Get a chain buffer.
399 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200400 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530401 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200402 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
403 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 /* Update the tracking arrays.
408 * If chainSge == NULL, update ReqToChain, else ChainToChain
409 */
410 if (chainSge) {
411 ioc->ChainToChain[chain_idx] = newIndex;
412 } else {
413 ioc->ReqToChain[req_idx] = newIndex;
414 }
415 chain_idx = newIndex;
416 chain_dma_off = ioc->req_sz * chain_idx;
417
418 /* Populate the chainSGE for the current buffer.
419 * - Set chain buffer pointer to psge and fill
420 * out the Address and Flags fields.
421 */
422 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600423 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
424 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 /* Start the SGE for the next buffer
427 */
428 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
429 sgeOffset = 0;
430 sg_done = 0;
431
Eric Moore29dd3602007-09-14 18:46:51 -0600432 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
433 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 /* Start the SGE for the next buffer
436 */
437
438 goto nextSGEset;
439 }
440
441 return SUCCESS;
442} /* mptscsih_AddSGE() */
443
Eric Moore786899b2006-07-11 17:22:22 -0600444static void
445mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
446 U32 SlotStatus)
447{
448 MPT_FRAME_HDR *mf;
449 SEPRequest_t *SEPMsg;
450
Eric Moorecc78d302007-06-15 17:27:21 -0600451 if (ioc->bus_type != SAS)
452 return;
453
454 /* Not supported for hidden raid components
455 */
456 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600457 return;
458
459 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530460 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Eric Moore786899b2006-07-11 17:22:22 -0600461 ioc->name,__FUNCTION__));
462 return;
463 }
464
465 SEPMsg = (SEPRequest_t *)mf;
466 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700467 SEPMsg->Bus = vtarget->channel;
468 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600469 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
470 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530471 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700472 "Sending SEP cmd=%x channel=%d id=%d\n",
473 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600474 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
475}
476
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530477#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700478/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530479 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700480 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700481 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530482 * @pScsiReply: Pointer to MPT reply frame
483 *
484 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700485 *
486 * Refer to lsi/mpi.h.
487 **/
488static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530489mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700490{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530491 char *desc = NULL;
492 char *desc1 = NULL;
493 u16 ioc_status;
494 u8 skey, asc, ascq;
495
496 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700497
498 switch (ioc_status) {
499
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530500 case MPI_IOCSTATUS_SUCCESS:
501 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700502 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530503 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
504 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700505 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530506 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
507 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700508 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530509 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
510 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700511 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530512 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
513 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700514 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530515 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
516 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700517 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530518 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
519 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700520 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530521 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
522 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700523 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530524 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
525 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700526 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530527 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
528 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700529 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530530 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
531 desc = "task management failed";
532 break;
533 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
534 desc = "IOC terminated";
535 break;
536 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
537 desc = "ext terminated";
538 break;
539 default:
540 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700541 break;
542 }
543
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530544 switch (pScsiReply->SCSIStatus)
545 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700546
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530547 case MPI_SCSI_STATUS_SUCCESS:
548 desc1 = "success";
549 break;
550 case MPI_SCSI_STATUS_CHECK_CONDITION:
551 desc1 = "check condition";
552 break;
553 case MPI_SCSI_STATUS_CONDITION_MET:
554 desc1 = "condition met";
555 break;
556 case MPI_SCSI_STATUS_BUSY:
557 desc1 = "busy";
558 break;
559 case MPI_SCSI_STATUS_INTERMEDIATE:
560 desc1 = "intermediate";
561 break;
562 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
563 desc1 = "intermediate condmet";
564 break;
565 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
566 desc1 = "reservation conflict";
567 break;
568 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
569 desc1 = "command terminated";
570 break;
571 case MPI_SCSI_STATUS_TASK_SET_FULL:
572 desc1 = "task set full";
573 break;
574 case MPI_SCSI_STATUS_ACA_ACTIVE:
575 desc1 = "aca active";
576 break;
577 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
578 desc1 = "fcpext device logged out";
579 break;
580 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
581 desc1 = "fcpext no link";
582 break;
583 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
584 desc1 = "fcpext unassigned";
585 break;
586 default:
587 desc1 = "";
588 break;
589 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700590
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530591 scsi_print_command(sc);
Eric Moore29dd3602007-09-14 18:46:51 -0600592 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
593 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
594 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
595 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
596 scsi_get_resid(sc));
597 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
598 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530599 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Eric Moore29dd3602007-09-14 18:46:51 -0600600 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530601 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600602 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530603 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
Eric Moore29dd3602007-09-14 18:46:51 -0600610 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
611 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530612 }
613
614 /*
615 * Look for + dump FCP ResponseInfo[]!
616 */
617 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
618 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600619 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
620 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700621}
622#endif
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
625/*
626 * mptscsih_io_done - Main SCSI IO callback routine registered to
627 * Fusion MPT (base) driver
628 * @ioc: Pointer to MPT_ADAPTER structure
629 * @mf: Pointer to original MPT request frame
630 * @r: Pointer to MPT reply frame (NULL if TurboReply)
631 *
632 * This routine is called from mpt.c::mpt_interrupt() at the completion
633 * of any SCSI IO request.
634 * This routine is registered with the Fusion MPT (base) driver at driver
635 * load/init time via the mpt_register() API call.
636 *
637 * Returns 1 indicating alloc'd request frame ptr should be freed.
638 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400639int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
641{
642 struct scsi_cmnd *sc;
643 MPT_SCSI_HOST *hd;
644 SCSIIORequest_t *pScsiReq;
645 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700646 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600647 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600648 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
651
652 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700653 req_idx_MR = (mr != NULL) ?
654 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
655 if ((req_idx != req_idx_MR) ||
656 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
657 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
658 ioc->name);
659 printk (MYIOC_s_ERR_FMT
660 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
661 ioc->name, req_idx, req_idx_MR, mf, mr,
662 hd->ScsiLookup[req_idx_MR]);
663 return 0;
664 }
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600667 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (sc == NULL) {
669 MPIHeader_t *hdr = (MPIHeader_t *)mf;
670
671 /* Remark: writeSDP1 will use the ScsiDoneCtx
672 * If a SCSI I/O cmd, device disabled by OS and
673 * completion done. Cannot touch sc struct. Just free mem.
674 */
675 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
676 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
677 ioc->name);
678
679 mptscsih_freeChainBuffers(ioc, req_idx);
680 return 1;
681 }
682
Eric Moore3dc0b032006-07-11 17:32:33 -0600683 if ((unsigned char *)mf != sc->host_scribble) {
684 mptscsih_freeChainBuffers(ioc, req_idx);
685 return 1;
686 }
687
688 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 sc->result = DID_OK << 16; /* Set default reply as OK */
690 pScsiReq = (SCSIIORequest_t *) mf;
691 pScsiReply = (SCSIIOReply_t *) mr;
692
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200693 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530694 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200695 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
696 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
697 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530698 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200699 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
700 ioc->name, mf, mr, sc, req_idx));
701 }
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if (pScsiReply == NULL) {
704 /* special context reply handling */
705 ;
706 } else {
707 u32 xfer_cnt;
708 u16 status;
709 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700710 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
713 scsi_state = pScsiReply->SCSIState;
714 scsi_status = pScsiReply->SCSIStatus;
715 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900716 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700717 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600719 /*
720 * if we get a data underrun indication, yet no data was
721 * transferred and the SCSI status indicates that the
722 * command was never started, change the data underrun
723 * to success
724 */
725 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
726 (scsi_status == MPI_SCSI_STATUS_BUSY ||
727 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
728 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
729 status = MPI_IOCSTATUS_SUCCESS;
730 }
731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400733 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /*
736 * Look for + dump FCP ResponseInfo[]!
737 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600738 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
739 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600740 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
741 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700742 sc->device->host->host_no, sc->device->channel,
743 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 le32_to_cpu(pScsiReply->ResponseInfo));
745 }
746
747 switch(status) {
748 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
749 /* CHECKME!
750 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
751 * But not: DID_BUS_BUSY lest one risk
752 * killing interrupt handler:-(
753 */
754 sc->result = SAM_STAT_BUSY;
755 break;
756
757 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
758 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
759 sc->result = DID_BAD_TARGET << 16;
760 break;
761
762 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
763 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600764 if (ioc->bus_type != FC)
765 sc->result = DID_NO_CONNECT << 16;
766 /* else fibre, just stall until rescan event */
767 else
768 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
771 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600772
Eric Moorea69de502007-09-14 18:48:19 -0600773 vdevice = sc->device->hostdata;
774 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600775 break;
Eric Moorea69de502007-09-14 18:48:19 -0600776 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600777 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
778 mptscsih_issue_sep_command(ioc, vtarget,
779 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
780 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 break;
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600785 if ( ioc->bus_type == SAS ) {
786 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
787 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700788 if ((log_info & SAS_LOGINFO_MASK)
789 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600790 sc->result = (DID_BUS_BUSY << 16);
791 break;
792 }
793 }
Eric Moore86dd4242007-01-04 20:44:01 -0700794 } else if (ioc->bus_type == FC) {
795 /*
796 * The FC IOC may kill a request for variety of
797 * reasons, some of which may be recovered by a
798 * retry, some which are unlikely to be
799 * recovered. Return DID_ERROR instead of
800 * DID_RESET to permit retry of the command,
801 * just not an infinite number of them
802 */
803 sc->result = DID_ERROR << 16;
804 break;
Eric Moorebf451522006-07-11 17:25:35 -0600805 }
806
807 /*
808 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
809 */
810
811 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
813 /* Linux handles an unsolicited DID_RESET better
814 * than an unsolicited DID_ABORT.
815 */
816 sc->result = DID_RESET << 16;
817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 break;
819
820 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900821 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600822 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
823 sc->result=DID_SOFT_ERROR << 16;
824 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600826 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700827 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600828 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
832 /*
833 * Do upfront check for valid SenseData and give it
834 * precedence!
835 */
836 sc->result = (DID_OK << 16) | scsi_status;
837 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
838 /* Have already saved the status and sense data
839 */
840 ;
841 } else {
842 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600843 if (scsi_status == SAM_STAT_BUSY)
844 sc->result = SAM_STAT_BUSY;
845 else
846 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
849 /* What to do?
850 */
851 sc->result = DID_SOFT_ERROR << 16;
852 }
853 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
854 /* Not real sure here either... */
855 sc->result = DID_RESET << 16;
856 }
857 }
858
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530859
Eric Moore29dd3602007-09-14 18:46:51 -0600860 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
861 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
862 ioc->name, sc->underflow));
863 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
864 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /* Report Queue Full
867 */
868 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
869 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 break;
872
Moore, Eric7e551472006-01-16 18:53:21 -0700873 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900874 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
876 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600877 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (scsi_state == 0) {
879 ;
880 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
881 /*
882 * If running against circa 200003dd 909 MPT f/w,
883 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
884 * (QUEUE_FULL) returned from device! --> get 0x0000?128
885 * and with SenseBytes set to 0.
886 */
887 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
888 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
889
890 }
891 else if (scsi_state &
892 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
893 ) {
894 /*
895 * What to do?
896 */
897 sc->result = DID_SOFT_ERROR << 16;
898 }
899 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
900 /* Not real sure here either... */
901 sc->result = DID_RESET << 16;
902 }
903 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
904 /* Device Inq. data indicates that it supports
905 * QTags, but rejects QTag messages.
906 * This command completed OK.
907 *
908 * Not real sure here either so do nothing... */
909 }
910
911 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
912 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
913
914 /* Add handling of:
915 * Reservation Conflict, Busy,
916 * Command Terminated, CHECK
917 */
918 break;
919
920 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
921 sc->result = DID_SOFT_ERROR << 16;
922 break;
923
924 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
925 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
926 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
927 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
928 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
929 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
930 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
932 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
933 default:
934 /*
935 * What to do?
936 */
937 sc->result = DID_SOFT_ERROR << 16;
938 break;
939
940 } /* switch(status) */
941
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530942#ifdef CONFIG_FUSION_LOGGING
943 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
944 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700945#endif
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 } /* end of address reply case */
948
949 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900950 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 sc->scsi_done(sc); /* Issue the command callback */
953
954 /* Free Chain buffers */
955 mptscsih_freeChainBuffers(ioc, req_idx);
956 return 1;
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*
960 * mptscsih_flush_running_cmds - For each command found, search
961 * Scsi_Host instance taskQ and reply to OS.
962 * Called only if recovering from a FW reload.
963 * @hd: Pointer to a SCSI HOST structure
964 *
965 * Returns: None.
966 *
967 * Must be called while new I/Os are being queued.
968 */
969static void
970mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
971{
972 MPT_ADAPTER *ioc = hd->ioc;
973 struct scsi_cmnd *SCpnt;
974 MPT_FRAME_HDR *mf;
975 int ii;
976 int max = ioc->req_depth;
977
Eric Moore29dd3602007-09-14 18:46:51 -0600978 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": flush_ScsiLookup called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 for (ii= 0; ii < max; ii++) {
980 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
981
982 /* Command found.
983 */
984
985 /* Null ScsiLookup index
986 */
987 hd->ScsiLookup[ii] = NULL;
988
989 mf = MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore29dd3602007-09-14 18:46:51 -0600990 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": flush: ScsiDone (mf=%p,sc=%p)\n",
991 ioc->name, mf, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Eric Moore3dc0b032006-07-11 17:32:33 -0600993 /* Free Chain buffers */
994 mptscsih_freeChainBuffers(ioc, ii);
995
996 /* Free Message frames */
997 mpt_free_msg_frame(ioc, mf);
998
999 if ((unsigned char *)mf != SCpnt->host_scribble)
1000 continue;
1001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 /* Set status, free OS resources (SG DMA buffers)
1003 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001005 scsi_dma_unmap(SCpnt);
1006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 SCpnt->result = DID_RESET << 16;
1008 SCpnt->host_scribble = NULL;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
1011 }
1012 }
1013
1014 return;
1015}
1016
1017/*
1018 * mptscsih_search_running_cmds - Delete any commands associated
1019 * with the specified target and lun. Function called only
1020 * when a lun is disable by mid-layer.
1021 * Do NOT access the referenced scsi_cmnd structure or
1022 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001023 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001024 * @hd: Pointer to a SCSI HOST structure
1025 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 *
1027 * Returns: None.
1028 *
1029 * Called from slave_destroy.
1030 */
1031static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001032mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
1034 SCSIIORequest_t *mf = NULL;
1035 int ii;
1036 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001037 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001038 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Eric Moore29dd3602007-09-14 18:46:51 -06001040 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT ": search_running channel %d id %d lun %d max %d\n",
1041 hd->ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
1043 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001044 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
1046 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001047 if (mf == NULL)
1048 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001049 /* If the device is a hidden raid component, then its
1050 * expected that the mf->function will be RAID_SCSI_IO
1051 */
1052 if (vdevice->vtarget->tflags &
1053 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1054 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1055 continue;
1056
Eric Moore793955f2007-01-29 09:42:20 -07001057 int_to_scsilun(vdevice->lun, &lun);
1058 if ((mf->Bus != vdevice->vtarget->channel) ||
1059 (mf->TargetID != vdevice->vtarget->id) ||
1060 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 continue;
1062
1063 /* Cleanup
1064 */
1065 hd->ScsiLookup[ii] = NULL;
1066 mptscsih_freeChainBuffers(hd->ioc, ii);
1067 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001068 if ((unsigned char *)mf != sc->host_scribble)
1069 continue;
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001070 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001071 sc->host_scribble = NULL;
1072 sc->result = DID_NO_CONNECT << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001073 sdev_printk(MYIOC_s_INFO_FMT, sc->device, "completing cmds: fw_channel %d,"
1074 "fw_id %d, sc=%p, mf = %p, idx=%x\n", hd->ioc->name, vdevice->vtarget->channel,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301075 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001076 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 }
1078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return;
1080}
1081
1082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1085/*
1086 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1087 * from a SCSI target device.
1088 * @sc: Pointer to scsi_cmnd structure
1089 * @pScsiReply: Pointer to SCSIIOReply_t
1090 * @pScsiReq: Pointer to original SCSI request
1091 *
1092 * This routine periodically reports QUEUE_FULL status returned from a
1093 * SCSI target device. It reports this to the console via kernel
1094 * printk() API call, not more than once every 10 seconds.
1095 */
1096static void
1097mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1098{
1099 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001102 if (sc->device == NULL)
1103 return;
1104 if (sc->device->host == NULL)
1105 return;
1106 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1107 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001109 if (time - hd->last_queue_full > 10 * HZ) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301110 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 -04001111 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1112 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114}
1115
1116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1117/*
1118 * mptscsih_remove - Removed scsi devices
1119 * @pdev: Pointer to pci_dev structure
1120 *
1121 *
1122 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001123void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124mptscsih_remove(struct pci_dev *pdev)
1125{
1126 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1127 struct Scsi_Host *host = ioc->sh;
1128 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001129 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001131 if(!host) {
1132 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 scsi_remove_host(host);
1137
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001138 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1139 return;
1140
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001141 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001143 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001145 if (hd->ScsiLookup != NULL) {
1146 sz1 = hd->ioc->req_depth * sizeof(void *);
1147 kfree(hd->ScsiLookup);
1148 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 }
1150
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301151 dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001152 "Free'd ScsiLookup (%d) memory\n",
1153 hd->ioc->name, sz1));
1154
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001155 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156
1157 /* NULL the Scsi_Host pointer
1158 */
1159 hd->ioc->sh = NULL;
1160
1161 scsi_host_put(host);
1162
1163 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
1166
1167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1168/*
1169 * mptscsih_shutdown - reboot notifier
1170 *
1171 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001172void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001173mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001175 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 struct Scsi_Host *host = ioc->sh;
1177 MPT_SCSI_HOST *hd;
1178
1179 if(!host)
1180 return;
1181
1182 hd = (MPT_SCSI_HOST *)host->hostdata;
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184}
1185
1186#ifdef CONFIG_PM
1187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1188/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001189 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 *
1191 *
1192 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001193int
Pavel Machek8d189f72005-04-16 15:25:28 -07001194mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001196 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001197 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198}
1199
1200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1201/*
1202 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1203 *
1204 *
1205 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001206int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207mptscsih_resume(struct pci_dev *pdev)
1208{
Hormsb364fd52007-03-19 15:06:44 +09001209 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210}
1211
1212#endif
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1215/**
1216 * mptscsih_info - Return information about MPT adapter
1217 * @SChost: Pointer to Scsi_Host structure
1218 *
1219 * (linux scsi_host_template.info routine)
1220 *
1221 * Returns pointer to buffer where information was written.
1222 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001223const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224mptscsih_info(struct Scsi_Host *SChost)
1225{
1226 MPT_SCSI_HOST *h;
1227 int size = 0;
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001230
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001232 if (h->info_kbuf == NULL)
1233 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1234 return h->info_kbuf;
1235 h->info_kbuf[0] = '\0';
1236
1237 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1238 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 }
1240
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001241 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242}
1243
1244struct info_str {
1245 char *buffer;
1246 int length;
1247 int offset;
1248 int pos;
1249};
1250
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001251static void
1252mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253{
1254 if (info->pos + len > info->length)
1255 len = info->length - info->pos;
1256
1257 if (info->pos + len < info->offset) {
1258 info->pos += len;
1259 return;
1260 }
1261
1262 if (info->pos < info->offset) {
1263 data += (info->offset - info->pos);
1264 len -= (info->offset - info->pos);
1265 }
1266
1267 if (len > 0) {
1268 memcpy(info->buffer + info->pos, data, len);
1269 info->pos += len;
1270 }
1271}
1272
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001273static int
1274mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275{
1276 va_list args;
1277 char buf[81];
1278 int len;
1279
1280 va_start(args, fmt);
1281 len = vsprintf(buf, fmt, args);
1282 va_end(args);
1283
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001284 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 return len;
1286}
1287
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001288static int
1289mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
1291 struct info_str info;
1292
1293 info.buffer = pbuf;
1294 info.length = len;
1295 info.offset = offset;
1296 info.pos = 0;
1297
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001298 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1299 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1300 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1301 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1304}
1305
1306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1307/**
1308 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001309 * @host: scsi host struct
1310 * @buffer: if write, user data; if read, buffer for user
1311 * @start: returns the buffer address
1312 * @offset: if write, 0; if read, the current offset into the buffer from
1313 * the previous read.
1314 * @length: if write, return length;
1315 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 *
1317 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001319int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1321 int length, int func)
1322{
1323 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1324 MPT_ADAPTER *ioc = hd->ioc;
1325 int size = 0;
1326
1327 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001328 /*
1329 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 */
1331 } else {
1332 if (start)
1333 *start = buffer;
1334
1335 size = mptscsih_host_info(ioc, buffer, offset, length);
1336 }
1337
1338 return size;
1339}
1340
1341/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1342#define ADD_INDEX_LOG(req_ent) do { } while(0)
1343
1344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1345/**
1346 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1347 * @SCpnt: Pointer to scsi_cmnd structure
1348 * @done: Pointer SCSI mid-layer IO completion function
1349 *
1350 * (linux scsi_host_template.queuecommand routine)
1351 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1352 * from a linux scsi_cmnd request and send it to the IOC.
1353 *
1354 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1355 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001356int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1358{
1359 MPT_SCSI_HOST *hd;
1360 MPT_FRAME_HDR *mf;
1361 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001362 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 int lun;
1364 u32 datalen;
1365 u32 scsictl;
1366 u32 scsidir;
1367 u32 cmd_len;
1368 int my_idx;
1369 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301370 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301373 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 lun = SCpnt->device->lun;
1375 SCpnt->scsi_done = done;
1376
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301377 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1378 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
1380 if (hd->resetPending) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301381 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1382 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 return SCSI_MLQUEUE_HOST_BUSY;
1384 }
1385
1386 /*
1387 * Put together a MPT SCSI request...
1388 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001389 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301390 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1391 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 return SCSI_MLQUEUE_HOST_BUSY;
1393 }
1394
1395 pScsiReq = (SCSIIORequest_t *) mf;
1396
1397 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1398
1399 ADD_INDEX_LOG(my_idx);
1400
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001401 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 * Seems we may receive a buffer (datalen>0) even when there
1403 * will be no data transfer! GRRRRR...
1404 */
1405 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001406 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1408 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001409 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1411 } else {
1412 datalen = 0;
1413 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1414 }
1415
1416 /* Default to untagged. Once a target structure has been allocated,
1417 * use the Inquiry data to determine if device supports tagged.
1418 */
Eric Moorea69de502007-09-14 18:48:19 -06001419 if (vdevice
1420 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 && (SCpnt->device->tagged_supported)) {
1422 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1423 } else {
1424 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1425 }
1426
1427 /* Use the above information to set up the message frame
1428 */
Eric Moorea69de502007-09-14 18:48:19 -06001429 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1430 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001432 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001433 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1434 else
1435 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 pScsiReq->CDBLength = SCpnt->cmd_len;
1437 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1438 pScsiReq->Reserved = 0;
1439 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001440 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 pScsiReq->Control = cpu_to_le32(scsictl);
1442
1443 /*
1444 * Write SCSI CDB into the message
1445 */
1446 cmd_len = SCpnt->cmd_len;
1447 for (ii=0; ii < cmd_len; ii++)
1448 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1449
1450 for (ii=cmd_len; ii < 16; ii++)
1451 pScsiReq->CDB[ii] = 0;
1452
1453 /* DataLength */
1454 pScsiReq->DataLength = cpu_to_le32(datalen);
1455
1456 /* SenseBuffer low address */
1457 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1458 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1459
1460 /* Now add the SG list
1461 * Always have a SGE even if null length.
1462 */
1463 if (datalen == 0) {
1464 /* Add a NULL SGE */
1465 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1466 (dma_addr_t) -1);
1467 } else {
1468 /* Add a 32 or 64 bit SGE */
1469 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1470 goto fail;
1471 }
1472
Eric Moore3dc0b032006-07-11 17:32:33 -06001473 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001476 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301477 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1478 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001479 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return 0;
1481
1482 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001483 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1485 mpt_free_msg_frame(hd->ioc, mf);
1486 return SCSI_MLQUEUE_HOST_BUSY;
1487}
1488
1489/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1490/*
1491 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1492 * with a SCSI IO request
1493 * @hd: Pointer to the MPT_SCSI_HOST instance
1494 * @req_idx: Index of the SCSI IO request frame.
1495 *
1496 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1497 * No return.
1498 */
1499static void
1500mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1501{
1502 MPT_FRAME_HDR *chain;
1503 unsigned long flags;
1504 int chain_idx;
1505 int next;
1506
1507 /* Get the first chain index and reset
1508 * tracker state.
1509 */
1510 chain_idx = ioc->ReqToChain[req_idx];
1511 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1512
1513 while (chain_idx != MPT_HOST_NO_CHAIN) {
1514
1515 /* Save the next chain buffer index */
1516 next = ioc->ChainToChain[chain_idx];
1517
1518 /* Free this chain buffer and reset
1519 * tracker
1520 */
1521 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1522
1523 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1524 + (chain_idx * ioc->req_sz));
1525
1526 spin_lock_irqsave(&ioc->FreeQlock, flags);
1527 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1528 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1529
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301530 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 ioc->name, chain_idx));
1532
1533 /* handle next */
1534 chain_idx = next;
1535 }
1536 return;
1537}
1538
1539/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1540/*
1541 * Reset Handling
1542 */
1543
1544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001545/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001547 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001549 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001550 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 * @lun: Logical Unit for reset (if appropriate)
1552 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001553 * @timeout: timeout for task management control
1554 *
1555 * Fall through to mpt_HardResetHandler if: not operational, too many
1556 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 *
1558 * Remark: Currently invoked from a non-interrupt thread (_bh).
1559 *
1560 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1561 * will be active.
1562 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001563 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001564 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001565int
Eric Moore793955f2007-01-29 09:42:20 -07001566mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567{
1568 MPT_ADAPTER *ioc;
1569 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 u32 ioc_raw_state;
1571 unsigned long flags;
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 ioc = hd->ioc;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301574 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 // SJR - CHECKME - Can we avoid this here?
1577 // (mpt_HardResetHandler has this check...)
1578 spin_lock_irqsave(&ioc->diagLock, flags);
1579 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1580 spin_unlock_irqrestore(&ioc->diagLock, flags);
1581 return FAILED;
1582 }
1583 spin_unlock_irqrestore(&ioc->diagLock, flags);
1584
1585 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001586 * If we time out and not bus reset, then we return a FAILED status
1587 * to the caller.
1588 * The call to mptscsih_tm_pending_wait() will set the pending flag
1589 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 * successful. Otherwise, reload the FW.
1591 */
1592 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1593 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Eric Moore29dd3602007-09-14 18:46:51 -06001594 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301596 ioc->name, hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 return FAILED;
1598 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06001599 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
Eric Moorecd2c6192007-01-29 09:47:47 -07001600 "reset: Timed out waiting for last TM (%d) "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301601 "to complete! \n", ioc->name,
Eric Moorecd2c6192007-01-29 09:47:47 -07001602 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 return FAILED;
1604 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001605 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301607 ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001608 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 }
1610 } else {
1611 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1612 hd->tmPending |= (1 << type);
1613 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1614 }
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1619 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001620 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1621 ioc->name, type, ioc_raw_state);
Eric Moore29dd3602007-09-14 18:46:51 -06001622 printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001623 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06001624 printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
1625 "FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001626 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 }
1628
Eric Moorecd2c6192007-01-29 09:47:47 -07001629 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1630 printk(MYIOC_s_WARN_FMT
1631 "TM Handler for type=%x: ioc_state: "
1632 "DOORBELL_ACTIVE (0x%x)!\n",
1633 ioc->name, type, ioc_raw_state);
1634 return FAILED;
1635 }
1636
1637 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001639 if (hd->hard_resets < -1)
1640 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Eric Moorecd2c6192007-01-29 09:47:47 -07001642 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1643 ctx2abort, timeout);
1644 if (rc)
1645 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301646 ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001647 else
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301648 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1649 ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001650
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301651 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1652 "TMHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 return rc;
1655}
1656
1657
1658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001659/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1661 * @hd: Pointer to MPT_SCSI_HOST structure
1662 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001663 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001664 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 * @lun: Logical Unit for reset (if appropriate)
1666 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001667 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 *
1669 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1670 * or a non-interrupt thread. In the former, must not call schedule().
1671 *
1672 * Not all fields are meaningfull for all task types.
1673 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001674 * Returns 0 for SUCCESS, or FAILED.
1675 *
1676 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677static int
Eric Moore793955f2007-01-29 09:42:20 -07001678mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679{
1680 MPT_FRAME_HDR *mf;
1681 SCSITaskMgmt_t *pScsiTm;
1682 int ii;
1683 int retval;
1684
1685 /* Return Fail to calling function if no message frames available.
1686 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001687 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301688 dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001690 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 }
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301692 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 hd->ioc->name, mf));
1694
1695 /* Format the Request
1696 */
1697 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001698 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 pScsiTm->Bus = channel;
1700 pScsiTm->ChainOffset = 0;
1701 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1702
1703 pScsiTm->Reserved = 0;
1704 pScsiTm->TaskType = type;
1705 pScsiTm->Reserved1 = 0;
1706 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1707 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1708
Eric Moore793955f2007-01-29 09:42:20 -07001709 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 for (ii=0; ii < 7; ii++)
1712 pScsiTm->Reserved2[ii] = 0;
1713
1714 pScsiTm->TaskMsgContext = ctx2abort;
1715
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301716 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
Eric Moorecd2c6192007-01-29 09:47:47 -07001717 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301719 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301721 if ((hd->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1722 (hd->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1723 mpt_put_msg_frame_hi_pri(hd->ioc->TaskCtx, hd->ioc, mf);
1724 else {
1725 retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
1726 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1727 if (retval) {
1728 dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
Eric Moorecd2c6192007-01-29 09:47:47 -07001729 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1730 hd->ioc, mf, retval));
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301731 goto fail_out;
1732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 }
1734
1735 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301736 dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1738 hd->ioc, mf));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301739 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 hd->ioc->name));
1741 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301742 dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
Eric Moorecd2c6192007-01-29 09:47:47 -07001743 hd->ioc->name, retval));
1744 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 }
1746
Eric Moorecd2c6192007-01-29 09:47:47 -07001747 /*
1748 * Handle success case, see if theres a non-zero ioc_status.
1749 */
1750 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1751 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1752 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1753 retval = 0;
1754 else
1755 retval = FAILED;
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001758
1759 fail_out:
1760
1761 /*
1762 * Free task managment mf, and corresponding tm flags
1763 */
1764 mpt_free_msg_frame(hd->ioc, mf);
1765 hd->tmPending = 0;
1766 hd->tmState = TM_STATE_NONE;
1767 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768}
1769
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001770static int
1771mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1772{
1773 switch (ioc->bus_type) {
1774 case FC:
1775 return 40;
1776 case SAS:
1777 return 10;
1778 case SPI:
1779 default:
1780 return 2;
1781 }
1782}
1783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1785/**
1786 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1787 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1788 *
1789 * (linux scsi_host_template.eh_abort_handler routine)
1790 *
1791 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001792 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001793int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794mptscsih_abort(struct scsi_cmnd * SCpnt)
1795{
1796 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 MPT_FRAME_HDR *mf;
1798 u32 ctx2abort;
1799 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001801 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001802 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001803 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
1805 /* If we can't locate our host adapter structure, return FAILED status.
1806 */
1807 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1808 SCpnt->result = DID_RESET << 16;
1809 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001810 printk(KERN_ERR MYNAM ": task abort: "
1811 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 return FAILED;
1813 }
1814
Eric Moore958d4a32007-06-15 17:24:14 -06001815 ioc = hd->ioc;
1816 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1817 ioc->name, SCpnt);
1818 scsi_print_command(SCpnt);
1819
1820 vdevice = SCpnt->device->hostdata;
1821 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001822 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1823 "task abort: device has been deleted (sc=%p)\n",
1824 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001825 SCpnt->result = DID_NO_CONNECT << 16;
1826 SCpnt->scsi_done(SCpnt);
1827 retval = 0;
1828 goto out;
1829 }
1830
Eric Moorecc78d302007-06-15 17:27:21 -06001831 /* Task aborts are not supported for hidden raid components.
1832 */
1833 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001834 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1835 "task abort: hidden raid component (sc=%p)\n",
1836 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001837 SCpnt->result = DID_RESET << 16;
1838 retval = FAILED;
1839 goto out;
1840 }
1841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 /* Find this command
1843 */
1844 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001845 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 * Do OS callback.
1847 */
1848 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001849 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001850 "Command not in the active list! (sc=%p)\n", ioc->name,
1851 SCpnt));
1852 retval = 0;
1853 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 }
1855
Eric Moore958d4a32007-06-15 17:24:14 -06001856 if (hd->resetPending) {
1857 retval = FAILED;
1858 goto out;
1859 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001860
1861 if (hd->timeouts < -1)
1862 hd->timeouts++;
1863
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1865 * (the IO to be ABORT'd)
1866 *
1867 * NOTE: Since we do not byteswap MsgContext, we do not
1868 * swap it here either. It is an opaque cookie to
1869 * the controller, so it does not matter. -DaveM
1870 */
1871 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1872 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1873
1874 hd->abortSCpnt = SCpnt;
1875
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001876 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001877 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1878 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Eric Moore3dc0b032006-07-11 17:32:33 -06001880 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001881 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001882 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001883
Eric Moore958d4a32007-06-15 17:24:14 -06001884 out:
1885 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1886 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001888 if (retval == 0)
1889 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001890 else
1891 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892}
1893
1894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1895/**
1896 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1897 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1898 *
1899 * (linux scsi_host_template.eh_dev_reset_handler routine)
1900 *
1901 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001902 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001903int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1905{
1906 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001907 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001908 VirtDevice *vdevice;
1909 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
1911 /* If we can't locate our host adapter structure, return FAILED status.
1912 */
1913 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001914 printk(KERN_ERR MYNAM ": target reset: "
1915 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 return FAILED;
1917 }
1918
Eric Moore958d4a32007-06-15 17:24:14 -06001919 ioc = hd->ioc;
1920 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1921 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001922 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
Eric Moore958d4a32007-06-15 17:24:14 -06001924 if (hd->resetPending) {
1925 retval = FAILED;
1926 goto out;
1927 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001928
Eric Moore958d4a32007-06-15 17:24:14 -06001929 vdevice = SCpnt->device->hostdata;
1930 if (!vdevice || !vdevice->vtarget) {
1931 retval = 0;
1932 goto out;
1933 }
1934
Eric Moorecc78d302007-06-15 17:27:21 -06001935 /* Target reset to hidden raid component is not supported
1936 */
1937 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1938 retval = FAILED;
1939 goto out;
1940 }
1941
Eric Moore958d4a32007-06-15 17:24:14 -06001942 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1943 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1944 mptscsih_get_tm_timeout(ioc));
1945
1946 out:
1947 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1948 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001949
1950 if (retval == 0)
1951 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001952 else
1953 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954}
1955
Eric Moorecd2c6192007-01-29 09:47:47 -07001956
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1958/**
1959 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1960 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1961 *
1962 * (linux scsi_host_template.eh_bus_reset_handler routine)
1963 *
1964 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001965 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001966int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1968{
1969 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001970 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001971 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001972 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974 /* If we can't locate our host adapter structure, return FAILED status.
1975 */
1976 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001977 printk(KERN_ERR MYNAM ": bus reset: "
1978 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 return FAILED;
1980 }
1981
Eric Moore958d4a32007-06-15 17:24:14 -06001982 ioc = hd->ioc;
1983 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1984 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001985 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987 if (hd->timeouts < -1)
1988 hd->timeouts++;
1989
Eric Moorea69de502007-09-14 18:48:19 -06001990 vdevice = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001991 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moorea69de502007-09-14 18:48:19 -06001992 vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Eric Moore958d4a32007-06-15 17:24:14 -06001994 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1995 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001996
1997 if (retval == 0)
1998 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001999 else
2000 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001}
2002
2003/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2004/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002005 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
2007 *
2008 * (linux scsi_host_template.eh_host_reset_handler routine)
2009 *
2010 * Returns SUCCESS or FAILED.
2011 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002012int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2014{
2015 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06002016 int retval;
2017 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
2019 /* If we can't locate the host to reset, then we failed. */
2020 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06002021 printk(KERN_ERR MYNAM ": host reset: "
2022 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 return FAILED;
2024 }
2025
Eric Moore958d4a32007-06-15 17:24:14 -06002026 ioc = hd->ioc;
2027 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2028 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 /* If our attempts to reset the host failed, then return a failed
2031 * status. The host will be taken off line by the SCSI mid-layer.
2032 */
Eric Moore958d4a32007-06-15 17:24:14 -06002033 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
2034 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 } else {
2036 /* Make sure TM pending is cleared and TM state is set to
2037 * NONE.
2038 */
Eric Moore958d4a32007-06-15 17:24:14 -06002039 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 hd->tmPending = 0;
2041 hd->tmState = TM_STATE_NONE;
2042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Eric Moore958d4a32007-06-15 17:24:14 -06002044 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2045 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
Eric Moore958d4a32007-06-15 17:24:14 -06002047 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048}
2049
2050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2051/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002052 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 * @hd: Pointer to MPT host structure.
2054 *
2055 * Returns {SUCCESS,FAILED}.
2056 */
2057static int
2058mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2059{
2060 unsigned long flags;
2061 int loop_count = 4 * 10; /* Wait 10 seconds */
2062 int status = FAILED;
2063
2064 do {
2065 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2066 if (hd->tmState == TM_STATE_NONE) {
2067 hd->tmState = TM_STATE_IN_PROGRESS;
2068 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002070 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 break;
2072 }
2073 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2074 msleep(250);
2075 } while (--loop_count);
2076
2077 return status;
2078}
2079
2080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2081/**
2082 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2083 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002084 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 *
2086 * Returns {SUCCESS,FAILED}.
2087 */
2088static int
2089mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2090{
2091 unsigned long flags;
2092 int loop_count = 4 * timeout;
2093 int status = FAILED;
2094
2095 do {
2096 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2097 if(hd->tmPending == 0) {
2098 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002099 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 break;
2101 }
2102 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002103 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 } while (--loop_count);
2105
2106 return status;
2107}
2108
2109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002110static void
2111mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2112{
2113 char *desc;
2114
2115 switch (response_code) {
2116 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2117 desc = "The task completed.";
2118 break;
2119 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2120 desc = "The IOC received an invalid frame status.";
2121 break;
2122 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2123 desc = "The task type is not supported.";
2124 break;
2125 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2126 desc = "The requested task failed.";
2127 break;
2128 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2129 desc = "The task completed successfully.";
2130 break;
2131 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2132 desc = "The LUN request is invalid.";
2133 break;
2134 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2135 desc = "The task is in the IOC queue and has not been sent to target.";
2136 break;
2137 default:
2138 desc = "unknown";
2139 break;
2140 }
2141 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2142 ioc->name, response_code, desc);
2143}
2144
2145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146/**
2147 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2148 * @ioc: Pointer to MPT_ADAPTER structure
2149 * @mf: Pointer to SCSI task mgmt request frame
2150 * @mr: Pointer to SCSI task mgmt reply frame
2151 *
2152 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2153 * of any SCSI task management request.
2154 * This routine is registered with the MPT (base) driver at driver
2155 * load/init time via the mpt_register() API call.
2156 *
2157 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002158 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002159int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2161{
2162 SCSITaskMgmtReply_t *pScsiTmReply;
2163 SCSITaskMgmt_t *pScsiTmReq;
2164 MPT_SCSI_HOST *hd;
2165 unsigned long flags;
2166 u16 iocstatus;
2167 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002168 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302170 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002171 ioc->name, mf, mr));
2172 if (!ioc->sh) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302173 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002174 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 return 1;
2176 }
2177
2178 if (mr == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302179 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002180 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 }
2183
Eric Moorecd2c6192007-01-29 09:47:47 -07002184 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2185 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2186 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2187 tmType = pScsiTmReq->TaskType;
2188 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2189 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2190
2191 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2192 pScsiTmReply->ResponseCode)
2193 mptscsih_taskmgmt_response_code(ioc,
2194 pScsiTmReply->ResponseCode);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302195 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Eric Moorecd2c6192007-01-29 09:47:47 -07002196
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302197#ifdef CONFIG_FUSION_LOGGING
2198 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2199 (ioc->debug_level & MPT_DEBUG_TM ))
2200 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2201 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2202 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2203 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2204 le16_to_cpu(pScsiTmReply->IOCStatus),
2205 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2206 le32_to_cpu(pScsiTmReply->TerminationCount));
Eric Moorecd2c6192007-01-29 09:47:47 -07002207#endif
2208 if (!iocstatus) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302209 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
Eric Moorecd2c6192007-01-29 09:47:47 -07002210 hd->abortSCpnt = NULL;
2211 goto out;
2212 }
2213
2214 /* Error? (anything non-zero?) */
2215
2216 /* clear flags and continue.
2217 */
2218 switch (tmType) {
2219
2220 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2221 if (termination_count == 1)
2222 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2223 hd->abortSCpnt = NULL;
2224 break;
2225
2226 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2227
2228 /* If an internal command is present
2229 * or the TM failed - reload the FW.
2230 * FC FW may respond FAILED to an ABORT
2231 */
2232 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2233 hd->cmdPtr)
2234 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06002235 printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07002236 break;
2237
2238 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2239 default:
2240 break;
2241 }
2242
2243 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 spin_lock_irqsave(&ioc->FreeQlock, flags);
2245 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002247 hd->tm_iocstatus = iocstatus;
2248 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250 return 1;
2251}
2252
2253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2254/*
2255 * This is anyones guess quite frankly.
2256 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002257int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2259 sector_t capacity, int geom[])
2260{
2261 int heads;
2262 int sectors;
2263 sector_t cylinders;
2264 ulong dummy;
2265
2266 heads = 64;
2267 sectors = 32;
2268
2269 dummy = heads * sectors;
2270 cylinders = capacity;
2271 sector_div(cylinders,dummy);
2272
2273 /*
2274 * Handle extended translation size for logical drives
2275 * > 1Gb
2276 */
2277 if ((ulong)capacity >= 0x200000) {
2278 heads = 255;
2279 sectors = 63;
2280 dummy = heads * sectors;
2281 cylinders = capacity;
2282 sector_div(cylinders,dummy);
2283 }
2284
2285 /* return result */
2286 geom[0] = heads;
2287 geom[1] = sectors;
2288 geom[2] = cylinders;
2289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 return 0;
2291}
2292
Moore, Ericf44e5462006-03-14 09:14:21 -07002293/* Search IOC page 3 to determine if this is hidden physical disk
2294 *
2295 */
2296int
Eric Moore793955f2007-01-29 09:42:20 -07002297mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002298{
Eric Mooreb506ade2007-01-29 09:45:37 -07002299 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002300 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002301 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002302
Eric Moore793955f2007-01-29 09:42:20 -07002303 if (!ioc->raid_data.pIocPg3)
2304 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002305 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002306 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2307 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2308 rc = 1;
2309 goto out;
2310 }
2311 }
2312
Eric Mooreb506ade2007-01-29 09:45:37 -07002313 /*
2314 * Check inactive list for matching phys disks
2315 */
2316 if (list_empty(&ioc->raid_data.inactive_list))
2317 goto out;
2318
2319 down(&ioc->raid_data.inactive_list_mutex);
2320 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2321 list) {
2322 if ((component_info->d.PhysDiskID == id) &&
2323 (component_info->d.PhysDiskBus == channel))
2324 rc = 1;
2325 }
2326 up(&ioc->raid_data.inactive_list_mutex);
2327
Eric Moore793955f2007-01-29 09:42:20 -07002328 out:
2329 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002330}
2331EXPORT_SYMBOL(mptscsih_is_phys_disk);
2332
Eric Moore793955f2007-01-29 09:42:20 -07002333u8
2334mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002335{
Eric Mooreb506ade2007-01-29 09:45:37 -07002336 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002337 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002338 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002339
Eric Moore793955f2007-01-29 09:42:20 -07002340 if (!ioc->raid_data.pIocPg3)
2341 goto out;
2342 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2343 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2344 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2345 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2346 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002347 }
2348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
Eric Mooreb506ade2007-01-29 09:45:37 -07002350 /*
2351 * Check inactive list for matching phys disks
2352 */
2353 if (list_empty(&ioc->raid_data.inactive_list))
2354 goto out;
2355
2356 down(&ioc->raid_data.inactive_list_mutex);
2357 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2358 list) {
2359 if ((component_info->d.PhysDiskID == id) &&
2360 (component_info->d.PhysDiskBus == channel))
2361 rc = component_info->d.PhysDiskNum;
2362 }
2363 up(&ioc->raid_data.inactive_list_mutex);
2364
Eric Moore793955f2007-01-29 09:42:20 -07002365 out:
2366 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002367}
Eric Moore793955f2007-01-29 09:42:20 -07002368EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002369
2370/*
2371 * OS entry point to allow for host driver to free allocated memory
2372 * Called if no device present or device being unloaded
2373 */
2374void
2375mptscsih_slave_destroy(struct scsi_device *sdev)
2376{
2377 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379 VirtTarget *vtarget;
2380 VirtDevice *vdevice;
2381 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002383 starget = scsi_target(sdev);
2384 vtarget = starget->hostdata;
2385 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002387 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002388 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002389 mptscsih_synchronize_cache(hd, vdevice);
2390 kfree(vdevice);
2391 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392}
2393
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002394/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2395/*
2396 * mptscsih_change_queue_depth - This function will set a devices queue depth
2397 * @sdev: per scsi_device pointer
2398 * @qdepth: requested queue depth
2399 *
2400 * Adding support for new 'change_queue_depth' api.
2401*/
2402int
2403mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2406 VirtTarget *vtarget;
2407 struct scsi_target *starget;
2408 int max_depth;
2409 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 starget = scsi_target(sdev);
2412 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002413
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002414 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002415 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002417 else if (sdev->type == TYPE_DISK &&
2418 vtarget->minSyncFactor <= MPT_ULTRA160)
2419 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2420 else
2421 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 } else
2423 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2424
2425 if (qdepth > max_depth)
2426 qdepth = max_depth;
2427 if (qdepth == 1)
2428 tagged = 0;
2429 else
2430 tagged = MSG_SIMPLE_TAG;
2431
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002432 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2433 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434}
2435
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436/*
2437 * OS entry point to adjust the queue_depths on a per-device basis.
2438 * Called once per device the bus scan. Use it to force the queue_depth
2439 * member to 1 if a device does not support Q tags.
2440 * Return non-zero if fails.
2441 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002442int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002443mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002445 struct Scsi_Host *sh = sdev->host;
2446 VirtTarget *vtarget;
2447 VirtDevice *vdevice;
2448 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2450
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002451 starget = scsi_target(sdev);
2452 vtarget = starget->hostdata;
2453 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302455 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002456 "device @ %p, channel=%d, id=%d, lun=%d\n",
2457 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002458 if (hd->ioc->bus_type == SPI)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302459 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002460 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2461 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2462 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002464 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002466 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 goto slave_configure_exit;
2468 }
2469
Eric Moore793955f2007-01-29 09:42:20 -07002470 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002471 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302473 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002475 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002477 if (hd->ioc->bus_type == SPI)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302478 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002479 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2480 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2481 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
2483slave_configure_exit:
2484
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302485 dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002487 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2488 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 return 0;
2491}
2492
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2494/*
2495 * Private routines...
2496 */
2497
2498/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2499/* Utility function to copy sense data from the scsi_cmnd buffer
2500 * to the FC and SCSI target structures.
2501 *
2502 */
2503static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002504mptscsih_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 -07002505{
Eric Moorea69de502007-09-14 18:48:19 -06002506 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 SCSIIORequest_t *pReq;
2508 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
2510 /* Get target structure
2511 */
2512 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002513 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 if (sense_count) {
2516 u8 *sense_data;
2517 int req_index;
2518
2519 /* Copy the sense received into the scsi command block. */
2520 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2521 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2522 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2523
2524 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2525 */
2526 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002527 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 int idx;
2529 MPT_ADAPTER *ioc = hd->ioc;
2530
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002531 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2533 ioc->events[idx].eventContext = ioc->eventContext;
2534
Dave Jones3d9780b2007-05-21 20:59:47 -04002535 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2536 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2537 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Dave Jones3d9780b2007-05-21 20:59:47 -04002539 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
2541 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002542 if (hd->ioc->pcidev->vendor ==
2543 PCI_VENDOR_ID_IBM) {
2544 mptscsih_issue_sep_command(hd->ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002545 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2546 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002547 MPT_TARGET_FLAGS_LED_ON;
2548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 }
2550 }
2551 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302552 dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 hd->ioc->name));
2554 }
2555}
2556
Eric Moore3dc0b032006-07-11 17:32:33 -06002557static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2559{
2560 MPT_SCSI_HOST *hd;
2561 int i;
2562
2563 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2564
2565 for (i = 0; i < hd->ioc->req_depth; i++) {
2566 if (hd->ScsiLookup[i] == sc) {
2567 return i;
2568 }
2569 }
2570
2571 return -1;
2572}
2573
2574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002575int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2577{
2578 MPT_SCSI_HOST *hd;
2579 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002580 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Eric Moore29dd3602007-09-14 18:46:51 -06002582 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2583 ": IOC %s_reset routed to SCSI host driver!\n",
2584 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2585 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 /* If a FW reload request arrives after base installed but
2588 * before all scsi hosts have been attached, then an alt_ioc
2589 * may have a NULL sh pointer.
2590 */
2591 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2592 return 0;
2593 else
2594 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2595
2596 if (reset_phase == MPT_IOC_SETUP_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302597 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
2599 /* Clean Up:
2600 * 1. Set Hard Reset Pending Flag
2601 * All new commands go to doneQ
2602 */
2603 hd->resetPending = 1;
2604
2605 } else if (reset_phase == MPT_IOC_PRE_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302606 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 /* 2. Flush running commands
2609 * Clean ScsiLookup (and associated memory)
2610 * AND clean mytaskQ
2611 */
2612
2613 /* 2b. Reply to OS all known outstanding I/O commands.
2614 */
2615 mptscsih_flush_running_cmds(hd);
2616
2617 /* 2c. If there was an internal command that
2618 * has not completed, configuration or io request,
2619 * free these resources.
2620 */
2621 if (hd->cmdPtr) {
2622 del_timer(&hd->timer);
2623 mpt_free_msg_frame(ioc, hd->cmdPtr);
2624 }
2625
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302626 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302629 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
2631 /* Once a FW reload begins, all new OS commands are
2632 * redirected to the doneQ w/ a reset status.
2633 * Init all control structures.
2634 */
2635
2636 /* ScsiLookup initialization
2637 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002638 for (ii=0; ii < hd->ioc->req_depth; ii++)
2639 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
2641 /* 2. Chain Buffer initialization
2642 */
2643
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002644 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 /* 5. Enable new commands to be posted
2648 */
2649 spin_lock_irqsave(&ioc->FreeQlock, flags);
2650 hd->tmPending = 0;
2651 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2652 hd->resetPending = 0;
2653 hd->tmState = TM_STATE_NONE;
2654
2655 /* 6. If there was an internal command,
2656 * wake this process up.
2657 */
2658 if (hd->cmdPtr) {
2659 /*
2660 * Wake up the original calling thread
2661 */
2662 hd->pLocal = &hd->localReply;
2663 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002664 hd->scandv_wait_done = 1;
2665 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 hd->cmdPtr = NULL;
2667 }
2668
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302669 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
2671 }
2672
2673 return 1; /* currently means nothing really */
2674}
2675
2676/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002677int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2679{
2680 MPT_SCSI_HOST *hd;
2681 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2682
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302683 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 ioc->name, event));
2685
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002686 if (ioc->sh == NULL ||
2687 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2688 return 1;
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 switch (event) {
2691 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2692 /* FIXME! */
2693 break;
2694 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2695 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002696 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002697 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 break;
2699 case MPI_EVENT_LOGOUT: /* 09 */
2700 /* FIXME! */
2701 break;
2702
Michael Reed05e8ec12006-01-13 14:31:54 -06002703 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002704 break;
2705
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /*
2707 * CHECKME! Don't think we need to do
2708 * anything for these, but...
2709 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2711 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2712 /*
2713 * CHECKME! Falling thru...
2714 */
2715 break;
2716
2717 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002718 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 case MPI_EVENT_NONE: /* 00 */
2721 case MPI_EVENT_LOG_DATA: /* 01 */
2722 case MPI_EVENT_STATE_CHANGE: /* 02 */
2723 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2724 default:
Eric Moore29dd3602007-09-14 18:46:51 -06002725 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
2726 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 break;
2728 }
2729
2730 return 1; /* currently means nothing really */
2731}
2732
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2734/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 * Bus Scan and Domain Validation functionality ...
2736 */
2737
2738/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2739/*
2740 * mptscsih_scandv_complete - Scan and DV callback routine registered
2741 * to Fustion MPT (base) driver.
2742 *
2743 * @ioc: Pointer to MPT_ADAPTER structure
2744 * @mf: Pointer to original MPT request frame
2745 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2746 *
2747 * This routine is called from mpt.c::mpt_interrupt() at the completion
2748 * of any SCSI IO request.
2749 * This routine is registered with the Fusion MPT (base) driver at driver
2750 * load/init time via the mpt_register() API call.
2751 *
2752 * Returns 1 indicating alloc'd request frame ptr should be freed.
2753 *
2754 * Remark: Sets a completion code and (possibly) saves sense data
2755 * in the IOC member localReply structure.
2756 * Used ONLY for DV and other internal commands.
2757 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002758int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2760{
2761 MPT_SCSI_HOST *hd;
2762 SCSIIORequest_t *pReq;
2763 int completionCode;
2764 u16 req_idx;
2765
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002766 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2767
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 if ((mf == NULL) ||
2769 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2770 printk(MYIOC_s_ERR_FMT
2771 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2772 ioc->name, mf?"BAD":"NULL", (void *) mf);
2773 goto wakeup;
2774 }
2775
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 del_timer(&hd->timer);
2777 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2778 hd->ScsiLookup[req_idx] = NULL;
2779 pReq = (SCSIIORequest_t *) mf;
2780
2781 if (mf != hd->cmdPtr) {
2782 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2783 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2784 }
2785 hd->cmdPtr = NULL;
2786
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302787 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 hd->ioc->name, mf, mr, req_idx));
2789
2790 hd->pLocal = &hd->localReply;
2791 hd->pLocal->scsiStatus = 0;
2792
2793 /* If target struct exists, clear sense valid flag.
2794 */
2795 if (mr == NULL) {
2796 completionCode = MPT_SCANDV_GOOD;
2797 } else {
2798 SCSIIOReply_t *pReply;
2799 u16 status;
2800 u8 scsi_status;
2801
2802 pReply = (SCSIIOReply_t *) mr;
2803
2804 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2805 scsi_status = pReply->SCSIStatus;
2806
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 switch(status) {
2809
2810 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2811 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2812 break;
2813
2814 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2815 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2816 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2817 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2818 completionCode = MPT_SCANDV_DID_RESET;
2819 break;
2820
2821 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2822 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2823 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2824 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2825 ConfigReply_t *pr = (ConfigReply_t *)mr;
2826 completionCode = MPT_SCANDV_GOOD;
2827 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2828 hd->pLocal->header.PageLength = pr->Header.PageLength;
2829 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2830 hd->pLocal->header.PageType = pr->Header.PageType;
2831
2832 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2833 /* If the RAID Volume request is successful,
2834 * return GOOD, else indicate that
2835 * some type of error occurred.
2836 */
2837 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002838 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 completionCode = MPT_SCANDV_GOOD;
2840 else
2841 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002842 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
2844 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2845 u8 *sense_data;
2846 int sz;
2847
2848 /* save sense data in global structure
2849 */
2850 completionCode = MPT_SCANDV_SENSE;
2851 hd->pLocal->scsiStatus = scsi_status;
2852 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2853 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2854
2855 sz = min_t(int, pReq->SenseBufferLength,
2856 SCSI_STD_SENSE_BYTES);
2857 memcpy(hd->pLocal->sense, sense_data, sz);
2858
Eric Moore29dd3602007-09-14 18:46:51 -06002859 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
2860 ioc->name, sense_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2862 if (pReq->CDB[0] == INQUIRY)
2863 completionCode = MPT_SCANDV_ISSUE_SENSE;
2864 else
2865 completionCode = MPT_SCANDV_DID_RESET;
2866 }
2867 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2868 completionCode = MPT_SCANDV_DID_RESET;
2869 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2870 completionCode = MPT_SCANDV_DID_RESET;
2871 else {
2872 completionCode = MPT_SCANDV_GOOD;
2873 hd->pLocal->scsiStatus = scsi_status;
2874 }
2875 break;
2876
2877 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2878 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2879 completionCode = MPT_SCANDV_DID_RESET;
2880 else
2881 completionCode = MPT_SCANDV_SOME_ERROR;
2882 break;
2883
2884 default:
2885 completionCode = MPT_SCANDV_SOME_ERROR;
2886 break;
2887
2888 } /* switch(status) */
2889
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 } /* end of address reply case */
2891
2892 hd->pLocal->completion = completionCode;
2893
2894 /* MF and RF are freed in mpt_interrupt
2895 */
2896wakeup:
2897 /* Free Chain buffers (will never chain) in scan or dv */
2898 //mptscsih_freeChainBuffers(ioc, req_idx);
2899
2900 /*
2901 * Wake up the original calling thread
2902 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002903 hd->scandv_wait_done = 1;
2904 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
2906 return 1;
2907}
2908
2909/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2910/* mptscsih_timer_expired - Call back for timer process.
2911 * Used only for dv functionality.
2912 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2913 *
2914 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002915void
2916mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917{
2918 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2919
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302920 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 -07002921
2922 if (hd->cmdPtr) {
2923 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2924
2925 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2926 /* Desire to issue a task management request here.
2927 * TM requests MUST be single threaded.
2928 * If old eh code and no TM current, issue request.
2929 * If new eh code, do nothing. Wait for OS cmd timeout
2930 * for bus reset.
2931 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 } else {
2933 /* Perform a FW reload */
2934 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2935 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2936 }
2937 }
2938 } else {
2939 /* This should NEVER happen */
2940 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2941 }
2942
2943 /* No more processing.
2944 * TM call will generate an interrupt for SCSI TM Management.
2945 * The FW will reply to all outstanding commands, callback will finish cleanup.
2946 * Hard reset clean-up will free all resources.
2947 */
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302948 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
2950 return;
2951}
2952
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
2954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2955/**
2956 * mptscsih_do_cmd - Do internal command.
2957 * @hd: MPT_SCSI_HOST pointer
2958 * @io: INTERNAL_CMD pointer.
2959 *
2960 * Issue the specified internally generated command and do command
2961 * specific cleanup. For bus scan / DV only.
2962 * NOTES: If command is Inquiry and status is good,
2963 * initialize a target structure, save the data
2964 *
2965 * Remark: Single threaded access only.
2966 *
2967 * Return:
2968 * < 0 if an illegal command or no resources
2969 *
2970 * 0 if good
2971 *
2972 * > 0 if command complete but some type of completion error.
2973 */
2974static int
2975mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2976{
2977 MPT_FRAME_HDR *mf;
2978 SCSIIORequest_t *pScsiReq;
2979 SCSIIORequest_t ReqCopy;
2980 int my_idx, ii, dir;
2981 int rc, cmdTimeout;
2982 int in_isr;
2983 char cmdLen;
2984 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2985 char cmd = io->cmd;
2986
2987 in_isr = in_interrupt();
2988 if (in_isr) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302989 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 -07002990 hd->ioc->name));
2991 return -EPERM;
2992 }
2993
2994
2995 /* Set command specific information
2996 */
2997 switch (cmd) {
2998 case INQUIRY:
2999 cmdLen = 6;
3000 dir = MPI_SCSIIO_CONTROL_READ;
3001 CDB[0] = cmd;
3002 CDB[4] = io->size;
3003 cmdTimeout = 10;
3004 break;
3005
3006 case TEST_UNIT_READY:
3007 cmdLen = 6;
3008 dir = MPI_SCSIIO_CONTROL_READ;
3009 cmdTimeout = 10;
3010 break;
3011
3012 case START_STOP:
3013 cmdLen = 6;
3014 dir = MPI_SCSIIO_CONTROL_READ;
3015 CDB[0] = cmd;
3016 CDB[4] = 1; /*Spin up the disk */
3017 cmdTimeout = 15;
3018 break;
3019
3020 case REQUEST_SENSE:
3021 cmdLen = 6;
3022 CDB[0] = cmd;
3023 CDB[4] = io->size;
3024 dir = MPI_SCSIIO_CONTROL_READ;
3025 cmdTimeout = 10;
3026 break;
3027
3028 case READ_BUFFER:
3029 cmdLen = 10;
3030 dir = MPI_SCSIIO_CONTROL_READ;
3031 CDB[0] = cmd;
3032 if (io->flags & MPT_ICFLAG_ECHO) {
3033 CDB[1] = 0x0A;
3034 } else {
3035 CDB[1] = 0x02;
3036 }
3037
3038 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3039 CDB[1] |= 0x01;
3040 }
3041 CDB[6] = (io->size >> 16) & 0xFF;
3042 CDB[7] = (io->size >> 8) & 0xFF;
3043 CDB[8] = io->size & 0xFF;
3044 cmdTimeout = 10;
3045 break;
3046
3047 case WRITE_BUFFER:
3048 cmdLen = 10;
3049 dir = MPI_SCSIIO_CONTROL_WRITE;
3050 CDB[0] = cmd;
3051 if (io->flags & MPT_ICFLAG_ECHO) {
3052 CDB[1] = 0x0A;
3053 } else {
3054 CDB[1] = 0x02;
3055 }
3056 CDB[6] = (io->size >> 16) & 0xFF;
3057 CDB[7] = (io->size >> 8) & 0xFF;
3058 CDB[8] = io->size & 0xFF;
3059 cmdTimeout = 10;
3060 break;
3061
3062 case RESERVE:
3063 cmdLen = 6;
3064 dir = MPI_SCSIIO_CONTROL_READ;
3065 CDB[0] = cmd;
3066 cmdTimeout = 10;
3067 break;
3068
3069 case RELEASE:
3070 cmdLen = 6;
3071 dir = MPI_SCSIIO_CONTROL_READ;
3072 CDB[0] = cmd;
3073 cmdTimeout = 10;
3074 break;
3075
3076 case SYNCHRONIZE_CACHE:
3077 cmdLen = 10;
3078 dir = MPI_SCSIIO_CONTROL_READ;
3079 CDB[0] = cmd;
3080// CDB[1] = 0x02; /* set immediate bit */
3081 cmdTimeout = 10;
3082 break;
3083
3084 default:
3085 /* Error Case */
3086 return -EFAULT;
3087 }
3088
3089 /* Get and Populate a free Frame
3090 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003091 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06003092 dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
3093 hd->ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 return -EBUSY;
3095 }
3096
3097 pScsiReq = (SCSIIORequest_t *) mf;
3098
3099 /* Get the request index */
3100 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3101 ADD_INDEX_LOG(my_idx); /* for debug */
3102
3103 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3104 pScsiReq->TargetID = io->physDiskNum;
3105 pScsiReq->Bus = 0;
3106 pScsiReq->ChainOffset = 0;
3107 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3108 } else {
3109 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003110 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 pScsiReq->ChainOffset = 0;
3112 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3113 }
3114
3115 pScsiReq->CDBLength = cmdLen;
3116 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3117
3118 pScsiReq->Reserved = 0;
3119
3120 pScsiReq->MsgFlags = mpt_msg_flags();
3121 /* MsgContext set in mpt_get_msg_fram call */
3122
Eric Moore793955f2007-01-29 09:42:20 -07003123 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
3125 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3126 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3127 else
3128 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3129
3130 if (cmd == REQUEST_SENSE) {
3131 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303132 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 hd->ioc->name, cmd));
3134 }
3135
3136 for (ii=0; ii < 16; ii++)
3137 pScsiReq->CDB[ii] = CDB[ii];
3138
3139 pScsiReq->DataLength = cpu_to_le32(io->size);
3140 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3141 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3142
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303143 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003144 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145
3146 if (dir == MPI_SCSIIO_CONTROL_READ) {
3147 mpt_add_sge((char *) &pScsiReq->SGL,
3148 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3149 io->data_dma);
3150 } else {
3151 mpt_add_sge((char *) &pScsiReq->SGL,
3152 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3153 io->data_dma);
3154 }
3155
3156 /* The ISR will free the request frame, but we need
3157 * the information to initialize the target. Duplicate.
3158 */
3159 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3160
3161 /* Issue this command after:
3162 * finish init
3163 * add timer
3164 * Wait until the reply has been received
3165 * ScsiScanDvCtx callback function will
3166 * set hd->pLocal;
3167 * set scandv_wait_done and call wake_up
3168 */
3169 hd->pLocal = NULL;
3170 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003171 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
3173 /* Save cmd pointer, for resource free if timeout or
3174 * FW reload occurs
3175 */
3176 hd->cmdPtr = mf;
3177
3178 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003179 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3180 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
3182 if (hd->pLocal) {
3183 rc = hd->pLocal->completion;
3184 hd->pLocal->skip = 0;
3185
3186 /* Always set fatal error codes in some cases.
3187 */
3188 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3189 rc = -ENXIO;
3190 else if (rc == MPT_SCANDV_SOME_ERROR)
3191 rc = -rc;
3192 } else {
3193 rc = -EFAULT;
3194 /* This should never happen. */
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303195 ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 hd->ioc->name));
3197 }
3198
3199 return rc;
3200}
3201
3202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3203/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003204 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3205 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003206 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003207 *
3208 * Uses the ISR, but with special processing.
3209 * MUST be single-threaded.
3210 *
3211 */
3212static void
3213mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3214{
3215 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216
Eric Moorecc78d302007-06-15 17:27:21 -06003217 /* Ignore hidden raid components, this is handled when the command
3218 * is sent to the volume
3219 */
3220 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3221 return;
3222
3223 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3224 !vdevice->configured_lun)
3225 return;
3226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 /* Following parameters will not change
3228 * in this routine.
3229 */
3230 iocmd.cmd = SYNCHRONIZE_CACHE;
3231 iocmd.flags = 0;
3232 iocmd.physDiskNum = -1;
3233 iocmd.data = NULL;
3234 iocmd.data_dma = -1;
3235 iocmd.size = 0;
3236 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003237 iocmd.channel = vdevice->vtarget->channel;
3238 iocmd.id = vdevice->vtarget->id;
3239 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
Eric Moorecc78d302007-06-15 17:27:21 -06003241 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242}
3243
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303244static ssize_t
3245mptscsih_version_fw_show(struct class_device *cdev, char *buf)
3246{
3247 struct Scsi_Host *host = class_to_shost(cdev);
3248 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3249 MPT_ADAPTER *ioc = hd->ioc;
3250
3251 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3252 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3253 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3254 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3255 ioc->facts.FWVersion.Word & 0x000000FF);
3256}
3257static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3258
3259static ssize_t
3260mptscsih_version_bios_show(struct class_device *cdev, char *buf)
3261{
3262 struct Scsi_Host *host = class_to_shost(cdev);
3263 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3264 MPT_ADAPTER *ioc = hd->ioc;
3265
3266 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3267 (ioc->biosVersion & 0xFF000000) >> 24,
3268 (ioc->biosVersion & 0x00FF0000) >> 16,
3269 (ioc->biosVersion & 0x0000FF00) >> 8,
3270 ioc->biosVersion & 0x000000FF);
3271}
3272static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3273
3274static ssize_t
3275mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
3276{
3277 struct Scsi_Host *host = class_to_shost(cdev);
3278 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3279 MPT_ADAPTER *ioc = hd->ioc;
3280
3281 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3282}
3283static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3284
3285static ssize_t
3286mptscsih_version_product_show(struct class_device *cdev, char *buf)
3287{
3288 struct Scsi_Host *host = class_to_shost(cdev);
3289 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3290 MPT_ADAPTER *ioc = hd->ioc;
3291
3292 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3293}
3294static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
3295 mptscsih_version_product_show, NULL);
3296
3297static ssize_t
3298mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
3299{
3300 struct Scsi_Host *host = class_to_shost(cdev);
3301 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3302 MPT_ADAPTER *ioc = hd->ioc;
3303
3304 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3305 ioc->nvdata_version_persistent);
3306}
3307static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3308 mptscsih_version_nvdata_persistent_show, NULL);
3309
3310static ssize_t
3311mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
3312{
3313 struct Scsi_Host *host = class_to_shost(cdev);
3314 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3315 MPT_ADAPTER *ioc = hd->ioc;
3316
3317 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3318}
3319static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3320 mptscsih_version_nvdata_default_show, NULL);
3321
3322static ssize_t
3323mptscsih_board_name_show(struct class_device *cdev, char *buf)
3324{
3325 struct Scsi_Host *host = class_to_shost(cdev);
3326 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3327 MPT_ADAPTER *ioc = hd->ioc;
3328
3329 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3330}
3331static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3332
3333static ssize_t
3334mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
3335{
3336 struct Scsi_Host *host = class_to_shost(cdev);
3337 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3338 MPT_ADAPTER *ioc = hd->ioc;
3339
3340 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3341}
3342static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
3343 mptscsih_board_assembly_show, NULL);
3344
3345static ssize_t
3346mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
3347{
3348 struct Scsi_Host *host = class_to_shost(cdev);
3349 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3350 MPT_ADAPTER *ioc = hd->ioc;
3351
3352 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3353}
3354static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
3355 mptscsih_board_tracer_show, NULL);
3356
3357static ssize_t
3358mptscsih_io_delay_show(struct class_device *cdev, char *buf)
3359{
3360 struct Scsi_Host *host = class_to_shost(cdev);
3361 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3362 MPT_ADAPTER *ioc = hd->ioc;
3363
3364 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3365}
3366static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
3367 mptscsih_io_delay_show, NULL);
3368
3369static ssize_t
3370mptscsih_device_delay_show(struct class_device *cdev, char *buf)
3371{
3372 struct Scsi_Host *host = class_to_shost(cdev);
3373 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3374 MPT_ADAPTER *ioc = hd->ioc;
3375
3376 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3377}
3378static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
3379 mptscsih_device_delay_show, NULL);
3380
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303381static ssize_t
3382mptscsih_debug_level_show(struct class_device *cdev, char *buf)
3383{
3384 struct Scsi_Host *host = class_to_shost(cdev);
3385 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3386 MPT_ADAPTER *ioc = hd->ioc;
3387
3388 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3389}
3390static ssize_t
3391mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
3392 size_t count)
3393{
3394 struct Scsi_Host *host = class_to_shost(cdev);
3395 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3396 MPT_ADAPTER *ioc = hd->ioc;
3397 int val = 0;
3398
3399 if (sscanf(buf, "%x", &val) != 1)
3400 return -EINVAL;
3401
3402 ioc->debug_level = val;
3403 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3404 ioc->name, ioc->debug_level);
3405 return strlen(buf);
3406}
3407static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3408 mptscsih_debug_level_show, mptscsih_debug_level_store);
3409
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303410struct class_device_attribute *mptscsih_host_attrs[] = {
3411 &class_device_attr_version_fw,
3412 &class_device_attr_version_bios,
3413 &class_device_attr_version_mpi,
3414 &class_device_attr_version_product,
3415 &class_device_attr_version_nvdata_persistent,
3416 &class_device_attr_version_nvdata_default,
3417 &class_device_attr_board_name,
3418 &class_device_attr_board_assembly,
3419 &class_device_attr_board_tracer,
3420 &class_device_attr_io_delay,
3421 &class_device_attr_device_delay,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303422 &class_device_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303423 NULL,
3424};
3425EXPORT_SYMBOL(mptscsih_host_attrs);
3426
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003427EXPORT_SYMBOL(mptscsih_remove);
3428EXPORT_SYMBOL(mptscsih_shutdown);
3429#ifdef CONFIG_PM
3430EXPORT_SYMBOL(mptscsih_suspend);
3431EXPORT_SYMBOL(mptscsih_resume);
3432#endif
3433EXPORT_SYMBOL(mptscsih_proc_info);
3434EXPORT_SYMBOL(mptscsih_info);
3435EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003436EXPORT_SYMBOL(mptscsih_slave_destroy);
3437EXPORT_SYMBOL(mptscsih_slave_configure);
3438EXPORT_SYMBOL(mptscsih_abort);
3439EXPORT_SYMBOL(mptscsih_dev_reset);
3440EXPORT_SYMBOL(mptscsih_bus_reset);
3441EXPORT_SYMBOL(mptscsih_host_reset);
3442EXPORT_SYMBOL(mptscsih_bios_param);
3443EXPORT_SYMBOL(mptscsih_io_done);
3444EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3445EXPORT_SYMBOL(mptscsih_scandv_complete);
3446EXPORT_SYMBOL(mptscsih_event_process);
3447EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003448EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003449EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003450EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/