blob: b1f68caf9a1d3739487a9aaa181650238c430deb [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
Eric Mooree7eae9f2007-09-29 10:15:59 -0600650 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700652 req_idx_MR = (mr != NULL) ?
653 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
654 if ((req_idx != req_idx_MR) ||
655 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
656 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
657 ioc->name);
658 printk (MYIOC_s_ERR_FMT
659 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
660 ioc->name, req_idx, req_idx_MR, mf, mr,
661 hd->ScsiLookup[req_idx_MR]);
662 return 0;
663 }
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600666 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if (sc == NULL) {
668 MPIHeader_t *hdr = (MPIHeader_t *)mf;
669
670 /* Remark: writeSDP1 will use the ScsiDoneCtx
671 * If a SCSI I/O cmd, device disabled by OS and
672 * completion done. Cannot touch sc struct. Just free mem.
673 */
674 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
675 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
676 ioc->name);
677
678 mptscsih_freeChainBuffers(ioc, req_idx);
679 return 1;
680 }
681
Eric Moore3dc0b032006-07-11 17:32:33 -0600682 if ((unsigned char *)mf != sc->host_scribble) {
683 mptscsih_freeChainBuffers(ioc, req_idx);
684 return 1;
685 }
686
687 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 sc->result = DID_OK << 16; /* Set default reply as OK */
689 pScsiReq = (SCSIIORequest_t *) mf;
690 pScsiReply = (SCSIIOReply_t *) mr;
691
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200692 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530693 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200694 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
695 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
696 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530697 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200698 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
699 ioc->name, mf, mr, sc, req_idx));
700 }
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 if (pScsiReply == NULL) {
703 /* special context reply handling */
704 ;
705 } else {
706 u32 xfer_cnt;
707 u16 status;
708 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700709 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
712 scsi_state = pScsiReply->SCSIState;
713 scsi_status = pScsiReply->SCSIStatus;
714 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900715 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700716 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600718 /*
719 * if we get a data underrun indication, yet no data was
720 * transferred and the SCSI status indicates that the
721 * command was never started, change the data underrun
722 * to success
723 */
724 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
725 (scsi_status == MPI_SCSI_STATUS_BUSY ||
726 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
727 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
728 status = MPI_IOCSTATUS_SUCCESS;
729 }
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400732 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /*
735 * Look for + dump FCP ResponseInfo[]!
736 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600737 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
738 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600739 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
740 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700741 sc->device->host->host_no, sc->device->channel,
742 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 le32_to_cpu(pScsiReply->ResponseInfo));
744 }
745
746 switch(status) {
747 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
748 /* CHECKME!
749 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
750 * But not: DID_BUS_BUSY lest one risk
751 * killing interrupt handler:-(
752 */
753 sc->result = SAM_STAT_BUSY;
754 break;
755
756 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
757 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
758 sc->result = DID_BAD_TARGET << 16;
759 break;
760
761 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
762 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600763 if (ioc->bus_type != FC)
764 sc->result = DID_NO_CONNECT << 16;
765 /* else fibre, just stall until rescan event */
766 else
767 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
770 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600771
Eric Moorea69de502007-09-14 18:48:19 -0600772 vdevice = sc->device->hostdata;
773 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600774 break;
Eric Moorea69de502007-09-14 18:48:19 -0600775 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600776 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
777 mptscsih_issue_sep_command(ioc, vtarget,
778 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
779 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 break;
782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600784 if ( ioc->bus_type == SAS ) {
785 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
786 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700787 if ((log_info & SAS_LOGINFO_MASK)
788 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600789 sc->result = (DID_BUS_BUSY << 16);
790 break;
791 }
792 }
Eric Moore86dd4242007-01-04 20:44:01 -0700793 } else if (ioc->bus_type == FC) {
794 /*
795 * The FC IOC may kill a request for variety of
796 * reasons, some of which may be recovered by a
797 * retry, some which are unlikely to be
798 * recovered. Return DID_ERROR instead of
799 * DID_RESET to permit retry of the command,
800 * just not an infinite number of them
801 */
802 sc->result = DID_ERROR << 16;
803 break;
Eric Moorebf451522006-07-11 17:25:35 -0600804 }
805
806 /*
807 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
808 */
809
810 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
812 /* Linux handles an unsolicited DID_RESET better
813 * than an unsolicited DID_ABORT.
814 */
815 sc->result = DID_RESET << 16;
816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 break;
818
819 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900820 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600821 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
822 sc->result=DID_SOFT_ERROR << 16;
823 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600825 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700826 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600827 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
831 /*
832 * Do upfront check for valid SenseData and give it
833 * precedence!
834 */
835 sc->result = (DID_OK << 16) | scsi_status;
836 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
837 /* Have already saved the status and sense data
838 */
839 ;
840 } else {
841 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600842 if (scsi_status == SAM_STAT_BUSY)
843 sc->result = SAM_STAT_BUSY;
844 else
845 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
848 /* What to do?
849 */
850 sc->result = DID_SOFT_ERROR << 16;
851 }
852 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
853 /* Not real sure here either... */
854 sc->result = DID_RESET << 16;
855 }
856 }
857
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530858
Eric Moore29dd3602007-09-14 18:46:51 -0600859 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
860 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
861 ioc->name, sc->underflow));
862 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
863 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 /* Report Queue Full
866 */
867 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
868 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 break;
871
Moore, Eric7e551472006-01-16 18:53:21 -0700872 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900873 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
875 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600876 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (scsi_state == 0) {
878 ;
879 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
880 /*
881 * If running against circa 200003dd 909 MPT f/w,
882 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
883 * (QUEUE_FULL) returned from device! --> get 0x0000?128
884 * and with SenseBytes set to 0.
885 */
886 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
887 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
888
889 }
890 else if (scsi_state &
891 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
892 ) {
893 /*
894 * What to do?
895 */
896 sc->result = DID_SOFT_ERROR << 16;
897 }
898 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
899 /* Not real sure here either... */
900 sc->result = DID_RESET << 16;
901 }
902 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
903 /* Device Inq. data indicates that it supports
904 * QTags, but rejects QTag messages.
905 * This command completed OK.
906 *
907 * Not real sure here either so do nothing... */
908 }
909
910 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
911 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
912
913 /* Add handling of:
914 * Reservation Conflict, Busy,
915 * Command Terminated, CHECK
916 */
917 break;
918
919 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
920 sc->result = DID_SOFT_ERROR << 16;
921 break;
922
923 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
924 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
925 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
926 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
927 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
928 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
929 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
931 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
932 default:
933 /*
934 * What to do?
935 */
936 sc->result = DID_SOFT_ERROR << 16;
937 break;
938
939 } /* switch(status) */
940
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530941#ifdef CONFIG_FUSION_LOGGING
942 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
943 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700944#endif
945
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 } /* end of address reply case */
947
948 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900949 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 sc->scsi_done(sc); /* Issue the command callback */
952
953 /* Free Chain buffers */
954 mptscsih_freeChainBuffers(ioc, req_idx);
955 return 1;
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/*
959 * mptscsih_flush_running_cmds - For each command found, search
960 * Scsi_Host instance taskQ and reply to OS.
961 * Called only if recovering from a FW reload.
962 * @hd: Pointer to a SCSI HOST structure
963 *
964 * Returns: None.
965 *
966 * Must be called while new I/Os are being queued.
967 */
968static void
969mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
970{
971 MPT_ADAPTER *ioc = hd->ioc;
972 struct scsi_cmnd *SCpnt;
973 MPT_FRAME_HDR *mf;
974 int ii;
975 int max = ioc->req_depth;
976
Eric Moore29dd3602007-09-14 18:46:51 -0600977 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": flush_ScsiLookup called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 for (ii= 0; ii < max; ii++) {
979 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
980
981 /* Command found.
982 */
983
984 /* Null ScsiLookup index
985 */
986 hd->ScsiLookup[ii] = NULL;
987
988 mf = MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore29dd3602007-09-14 18:46:51 -0600989 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": flush: ScsiDone (mf=%p,sc=%p)\n",
990 ioc->name, mf, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Eric Moore3dc0b032006-07-11 17:32:33 -0600992 /* Free Chain buffers */
993 mptscsih_freeChainBuffers(ioc, ii);
994
995 /* Free Message frames */
996 mpt_free_msg_frame(ioc, mf);
997
998 if ((unsigned char *)mf != SCpnt->host_scribble)
999 continue;
1000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 /* Set status, free OS resources (SG DMA buffers)
1002 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001004 scsi_dma_unmap(SCpnt);
1005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 SCpnt->result = DID_RESET << 16;
1007 SCpnt->host_scribble = NULL;
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
1010 }
1011 }
1012
1013 return;
1014}
1015
1016/*
1017 * mptscsih_search_running_cmds - Delete any commands associated
1018 * with the specified target and lun. Function called only
1019 * when a lun is disable by mid-layer.
1020 * Do NOT access the referenced scsi_cmnd structure or
1021 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001022 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001023 * @hd: Pointer to a SCSI HOST structure
1024 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 *
1026 * Returns: None.
1027 *
1028 * Called from slave_destroy.
1029 */
1030static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001031mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
1033 SCSIIORequest_t *mf = NULL;
1034 int ii;
1035 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001036 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001037 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -06001038 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Eric Mooree80b0022007-09-14 18:49:03 -06001040 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": search_running channel %d id %d lun %d max %d\n",
1041 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
Eric Mooree80b0022007-09-14 18:49:03 -06001046 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(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;
Eric Mooree80b0022007-09-14 18:49:03 -06001066 mptscsih_freeChainBuffers(ioc, ii);
1067 mpt_free_msg_frame(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,"
Eric Mooree80b0022007-09-14 18:49:03 -06001074 "fw_id %d, sc=%p, mf = %p, idx=%x\n", 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;
Eric Mooree80b0022007-09-14 18:49:03 -06001101 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001103 if (sc->device == NULL)
1104 return;
1105 if (sc->device->host == NULL)
1106 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001107 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001108 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001109 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001110 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001111 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1112 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001113 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115}
1116
1117/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1118/*
1119 * mptscsih_remove - Removed scsi devices
1120 * @pdev: Pointer to pci_dev structure
1121 *
1122 *
1123 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001124void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125mptscsih_remove(struct pci_dev *pdev)
1126{
1127 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1128 struct Scsi_Host *host = ioc->sh;
1129 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001130 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001132 if(!host) {
1133 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137 scsi_remove_host(host);
1138
Eric Mooree7eae9f2007-09-29 10:15:59 -06001139 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001140 return;
1141
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001142 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001144 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001146 if (hd->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001147 sz1 = ioc->req_depth * sizeof(void *);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001148 kfree(hd->ScsiLookup);
1149 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
Eric Mooree80b0022007-09-14 18:49:03 -06001152 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001153 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001154 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001156 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001157
1158 /* NULL the Scsi_Host pointer
1159 */
Eric Mooree80b0022007-09-14 18:49:03 -06001160 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001161
1162 scsi_host_put(host);
1163
1164 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
1168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1169/*
1170 * mptscsih_shutdown - reboot notifier
1171 *
1172 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001173void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001174mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176}
1177
1178#ifdef CONFIG_PM
1179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1180/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001181 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 *
1183 *
1184 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001185int
Pavel Machek8d189f72005-04-16 15:25:28 -07001186mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001188 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001189 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190}
1191
1192/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1193/*
1194 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1195 *
1196 *
1197 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001198int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199mptscsih_resume(struct pci_dev *pdev)
1200{
Hormsb364fd52007-03-19 15:06:44 +09001201 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
1203
1204#endif
1205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1207/**
1208 * mptscsih_info - Return information about MPT adapter
1209 * @SChost: Pointer to Scsi_Host structure
1210 *
1211 * (linux scsi_host_template.info routine)
1212 *
1213 * Returns pointer to buffer where information was written.
1214 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001215const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216mptscsih_info(struct Scsi_Host *SChost)
1217{
1218 MPT_SCSI_HOST *h;
1219 int size = 0;
1220
Eric Mooree7eae9f2007-09-29 10:15:59 -06001221 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001224 if (h->info_kbuf == NULL)
1225 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1226 return h->info_kbuf;
1227 h->info_kbuf[0] = '\0';
1228
1229 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1230 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
1232
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001233 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234}
1235
1236struct info_str {
1237 char *buffer;
1238 int length;
1239 int offset;
1240 int pos;
1241};
1242
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001243static void
1244mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245{
1246 if (info->pos + len > info->length)
1247 len = info->length - info->pos;
1248
1249 if (info->pos + len < info->offset) {
1250 info->pos += len;
1251 return;
1252 }
1253
1254 if (info->pos < info->offset) {
1255 data += (info->offset - info->pos);
1256 len -= (info->offset - info->pos);
1257 }
1258
1259 if (len > 0) {
1260 memcpy(info->buffer + info->pos, data, len);
1261 info->pos += len;
1262 }
1263}
1264
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001265static int
1266mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267{
1268 va_list args;
1269 char buf[81];
1270 int len;
1271
1272 va_start(args, fmt);
1273 len = vsprintf(buf, fmt, args);
1274 va_end(args);
1275
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001276 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return len;
1278}
1279
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001280static int
1281mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
1283 struct info_str info;
1284
1285 info.buffer = pbuf;
1286 info.length = len;
1287 info.offset = offset;
1288 info.pos = 0;
1289
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001290 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1291 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1292 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1293 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
1295 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1296}
1297
1298/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1299/**
1300 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001301 * @host: scsi host struct
1302 * @buffer: if write, user data; if read, buffer for user
1303 * @start: returns the buffer address
1304 * @offset: if write, 0; if read, the current offset into the buffer from
1305 * the previous read.
1306 * @length: if write, return length;
1307 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 *
1309 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001311int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1313 int length, int func)
1314{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001315 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 MPT_ADAPTER *ioc = hd->ioc;
1317 int size = 0;
1318
1319 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001320 /*
1321 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 */
1323 } else {
1324 if (start)
1325 *start = buffer;
1326
1327 size = mptscsih_host_info(ioc, buffer, offset, length);
1328 }
1329
1330 return size;
1331}
1332
1333/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1334#define ADD_INDEX_LOG(req_ent) do { } while(0)
1335
1336/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1337/**
1338 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1339 * @SCpnt: Pointer to scsi_cmnd structure
1340 * @done: Pointer SCSI mid-layer IO completion function
1341 *
1342 * (linux scsi_host_template.queuecommand routine)
1343 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1344 * from a linux scsi_cmnd request and send it to the IOC.
1345 *
1346 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1347 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001348int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1350{
1351 MPT_SCSI_HOST *hd;
1352 MPT_FRAME_HDR *mf;
1353 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001354 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 int lun;
1356 u32 datalen;
1357 u32 scsictl;
1358 u32 scsidir;
1359 u32 cmd_len;
1360 int my_idx;
1361 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301362 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Eric Mooree7eae9f2007-09-29 10:15:59 -06001364 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301365 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 lun = SCpnt->device->lun;
1367 SCpnt->scsi_done = done;
1368
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301369 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1370 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 if (hd->resetPending) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301373 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1374 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 return SCSI_MLQUEUE_HOST_BUSY;
1376 }
1377
1378 /*
1379 * Put together a MPT SCSI request...
1380 */
Eric Mooree80b0022007-09-14 18:49:03 -06001381 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301382 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1383 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 return SCSI_MLQUEUE_HOST_BUSY;
1385 }
1386
1387 pScsiReq = (SCSIIORequest_t *) mf;
1388
1389 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1390
1391 ADD_INDEX_LOG(my_idx);
1392
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001393 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 * Seems we may receive a buffer (datalen>0) even when there
1395 * will be no data transfer! GRRRRR...
1396 */
1397 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001398 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1400 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001401 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1403 } else {
1404 datalen = 0;
1405 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1406 }
1407
1408 /* Default to untagged. Once a target structure has been allocated,
1409 * use the Inquiry data to determine if device supports tagged.
1410 */
Eric Moorea69de502007-09-14 18:48:19 -06001411 if (vdevice
1412 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 && (SCpnt->device->tagged_supported)) {
1414 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1415 } else {
1416 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1417 }
1418
1419 /* Use the above information to set up the message frame
1420 */
Eric Moorea69de502007-09-14 18:48:19 -06001421 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1422 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001424 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001425 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1426 else
1427 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 pScsiReq->CDBLength = SCpnt->cmd_len;
1429 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1430 pScsiReq->Reserved = 0;
1431 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001432 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 pScsiReq->Control = cpu_to_le32(scsictl);
1434
1435 /*
1436 * Write SCSI CDB into the message
1437 */
1438 cmd_len = SCpnt->cmd_len;
1439 for (ii=0; ii < cmd_len; ii++)
1440 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1441
1442 for (ii=cmd_len; ii < 16; ii++)
1443 pScsiReq->CDB[ii] = 0;
1444
1445 /* DataLength */
1446 pScsiReq->DataLength = cpu_to_le32(datalen);
1447
1448 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001449 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1451
1452 /* Now add the SG list
1453 * Always have a SGE even if null length.
1454 */
1455 if (datalen == 0) {
1456 /* Add a NULL SGE */
1457 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1458 (dma_addr_t) -1);
1459 } else {
1460 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001461 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 goto fail;
1463 }
1464
Eric Moore3dc0b032006-07-11 17:32:33 -06001465 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Eric Mooree80b0022007-09-14 18:49:03 -06001468 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301469 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1470 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001471 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 return 0;
1473
1474 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001475 hd->ScsiLookup[my_idx] = NULL;
Eric Mooree80b0022007-09-14 18:49:03 -06001476 mptscsih_freeChainBuffers(ioc, my_idx);
1477 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 return SCSI_MLQUEUE_HOST_BUSY;
1479}
1480
1481/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1482/*
1483 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1484 * with a SCSI IO request
1485 * @hd: Pointer to the MPT_SCSI_HOST instance
1486 * @req_idx: Index of the SCSI IO request frame.
1487 *
1488 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1489 * No return.
1490 */
1491static void
1492mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1493{
1494 MPT_FRAME_HDR *chain;
1495 unsigned long flags;
1496 int chain_idx;
1497 int next;
1498
1499 /* Get the first chain index and reset
1500 * tracker state.
1501 */
1502 chain_idx = ioc->ReqToChain[req_idx];
1503 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1504
1505 while (chain_idx != MPT_HOST_NO_CHAIN) {
1506
1507 /* Save the next chain buffer index */
1508 next = ioc->ChainToChain[chain_idx];
1509
1510 /* Free this chain buffer and reset
1511 * tracker
1512 */
1513 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1514
1515 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1516 + (chain_idx * ioc->req_sz));
1517
1518 spin_lock_irqsave(&ioc->FreeQlock, flags);
1519 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1520 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1521
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301522 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 ioc->name, chain_idx));
1524
1525 /* handle next */
1526 chain_idx = next;
1527 }
1528 return;
1529}
1530
1531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1532/*
1533 * Reset Handling
1534 */
1535
1536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001537/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001539 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001541 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001542 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 * @lun: Logical Unit for reset (if appropriate)
1544 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001545 * @timeout: timeout for task management control
1546 *
1547 * Fall through to mpt_HardResetHandler if: not operational, too many
1548 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 *
1550 * Remark: Currently invoked from a non-interrupt thread (_bh).
1551 *
1552 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1553 * will be active.
1554 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001555 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001556 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001557int
Eric Moore793955f2007-01-29 09:42:20 -07001558mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559{
1560 MPT_ADAPTER *ioc;
1561 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 u32 ioc_raw_state;
1563 unsigned long flags;
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 ioc = hd->ioc;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301566 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 // SJR - CHECKME - Can we avoid this here?
1569 // (mpt_HardResetHandler has this check...)
1570 spin_lock_irqsave(&ioc->diagLock, flags);
1571 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1572 spin_unlock_irqrestore(&ioc->diagLock, flags);
1573 return FAILED;
1574 }
1575 spin_unlock_irqrestore(&ioc->diagLock, flags);
1576
1577 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001578 * If we time out and not bus reset, then we return a FAILED status
1579 * to the caller.
1580 * The call to mptscsih_tm_pending_wait() will set the pending flag
1581 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 * successful. Otherwise, reload the FW.
1583 */
1584 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1585 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Eric Moore29dd3602007-09-14 18:46:51 -06001586 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301588 ioc->name, hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 return FAILED;
1590 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06001591 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
Eric Moorecd2c6192007-01-29 09:47:47 -07001592 "reset: Timed out waiting for last TM (%d) "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301593 "to complete! \n", ioc->name,
Eric Moorecd2c6192007-01-29 09:47:47 -07001594 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 return FAILED;
1596 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001597 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301599 ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001600 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 }
1602 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06001603 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 hd->tmPending |= (1 << type);
Eric Mooree80b0022007-09-14 18:49:03 -06001605 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 }
1607
Eric Mooree80b0022007-09-14 18:49:03 -06001608 ioc_raw_state = mpt_GetIocState(ioc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1611 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001612 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1613 ioc->name, type, ioc_raw_state);
Eric Moore29dd3602007-09-14 18:46:51 -06001614 printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001615 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06001616 printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
1617 "FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001618 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
1620
Eric Moorecd2c6192007-01-29 09:47:47 -07001621 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1622 printk(MYIOC_s_WARN_FMT
1623 "TM Handler for type=%x: ioc_state: "
1624 "DOORBELL_ACTIVE (0x%x)!\n",
1625 ioc->name, type, ioc_raw_state);
1626 return FAILED;
1627 }
1628
1629 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001631 if (hd->hard_resets < -1)
1632 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Eric Moorecd2c6192007-01-29 09:47:47 -07001634 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1635 ctx2abort, timeout);
1636 if (rc)
1637 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301638 ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001639 else
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301640 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1641 ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001642
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301643 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1644 "TMHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 return rc;
1647}
1648
1649
1650/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001651/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1653 * @hd: Pointer to MPT_SCSI_HOST structure
1654 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001655 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001656 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 * @lun: Logical Unit for reset (if appropriate)
1658 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001659 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 *
1661 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1662 * or a non-interrupt thread. In the former, must not call schedule().
1663 *
1664 * Not all fields are meaningfull for all task types.
1665 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001666 * Returns 0 for SUCCESS, or FAILED.
1667 *
1668 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669static int
Eric Moore793955f2007-01-29 09:42:20 -07001670mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671{
1672 MPT_FRAME_HDR *mf;
1673 SCSITaskMgmt_t *pScsiTm;
1674 int ii;
1675 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001676 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678 /* Return Fail to calling function if no message frames available.
1679 */
Eric Mooree80b0022007-09-14 18:49:03 -06001680 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
1681 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1682 ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001683 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
Eric Mooree80b0022007-09-14 18:49:03 -06001685 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
1686 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 /* Format the Request
1689 */
1690 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001691 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 pScsiTm->Bus = channel;
1693 pScsiTm->ChainOffset = 0;
1694 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1695
1696 pScsiTm->Reserved = 0;
1697 pScsiTm->TaskType = type;
1698 pScsiTm->Reserved1 = 0;
1699 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1700 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1701
Eric Moore793955f2007-01-29 09:42:20 -07001702 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 for (ii=0; ii < 7; ii++)
1705 pScsiTm->Reserved2[ii] = 0;
1706
1707 pScsiTm->TaskMsgContext = ctx2abort;
1708
Eric Mooree80b0022007-09-14 18:49:03 -06001709 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1710 "type=%d\n", ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301712 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
Eric Mooree80b0022007-09-14 18:49:03 -06001714 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1715 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1716 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301717 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001718 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301719 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1720 if (retval) {
Eric Mooree80b0022007-09-14 18:49:03 -06001721 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
1722 " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
1723 ioc, mf, retval));
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301724 goto fail_out;
1725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 }
1727
1728 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Mooree80b0022007-09-14 18:49:03 -06001729 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
1730 " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
1731 ioc, mf));
1732 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
1733 ioc->name));
1734 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1735 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
1736 ioc->name, retval));
Eric Moorecd2c6192007-01-29 09:47:47 -07001737 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 }
1739
Eric Moorecd2c6192007-01-29 09:47:47 -07001740 /*
1741 * Handle success case, see if theres a non-zero ioc_status.
1742 */
1743 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1744 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1745 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1746 retval = 0;
1747 else
1748 retval = FAILED;
1749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001751
1752 fail_out:
1753
1754 /*
1755 * Free task managment mf, and corresponding tm flags
1756 */
Eric Mooree80b0022007-09-14 18:49:03 -06001757 mpt_free_msg_frame(ioc, mf);
Eric Moorecd2c6192007-01-29 09:47:47 -07001758 hd->tmPending = 0;
1759 hd->tmState = TM_STATE_NONE;
1760 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761}
1762
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001763static int
1764mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1765{
1766 switch (ioc->bus_type) {
1767 case FC:
1768 return 40;
1769 case SAS:
1770 return 10;
1771 case SPI:
1772 default:
1773 return 2;
1774 }
1775}
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1778/**
1779 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1780 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1781 *
1782 * (linux scsi_host_template.eh_abort_handler routine)
1783 *
1784 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001785 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001786int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787mptscsih_abort(struct scsi_cmnd * SCpnt)
1788{
1789 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 MPT_FRAME_HDR *mf;
1791 u32 ctx2abort;
1792 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001793 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001794 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001795 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001796 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
1798 /* If we can't locate our host adapter structure, return FAILED status.
1799 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001800 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 SCpnt->result = DID_RESET << 16;
1802 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001803 printk(KERN_ERR MYNAM ": task abort: "
1804 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 return FAILED;
1806 }
1807
Eric Moore958d4a32007-06-15 17:24:14 -06001808 ioc = hd->ioc;
1809 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1810 ioc->name, SCpnt);
1811 scsi_print_command(SCpnt);
1812
1813 vdevice = SCpnt->device->hostdata;
1814 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001815 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1816 "task abort: device has been deleted (sc=%p)\n",
1817 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001818 SCpnt->result = DID_NO_CONNECT << 16;
1819 SCpnt->scsi_done(SCpnt);
1820 retval = 0;
1821 goto out;
1822 }
1823
Eric Moorecc78d302007-06-15 17:27:21 -06001824 /* Task aborts are not supported for hidden raid components.
1825 */
1826 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001827 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1828 "task abort: hidden raid component (sc=%p)\n",
1829 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001830 SCpnt->result = DID_RESET << 16;
1831 retval = FAILED;
1832 goto out;
1833 }
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 /* Find this command
1836 */
1837 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001838 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 * Do OS callback.
1840 */
1841 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001842 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001843 "Command not in the active list! (sc=%p)\n", ioc->name,
1844 SCpnt));
1845 retval = 0;
1846 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 }
1848
Eric Moore958d4a32007-06-15 17:24:14 -06001849 if (hd->resetPending) {
1850 retval = FAILED;
1851 goto out;
1852 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001853
1854 if (hd->timeouts < -1)
1855 hd->timeouts++;
1856
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1858 * (the IO to be ABORT'd)
1859 *
1860 * NOTE: Since we do not byteswap MsgContext, we do not
1861 * swap it here either. It is an opaque cookie to
1862 * the controller, so it does not matter. -DaveM
1863 */
Eric Mooree80b0022007-09-14 18:49:03 -06001864 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1866
1867 hd->abortSCpnt = SCpnt;
1868
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001869 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001870 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1871 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
Eric Moore3dc0b032006-07-11 17:32:33 -06001873 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001874 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001875 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001876
Eric Moore958d4a32007-06-15 17:24:14 -06001877 out:
1878 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1879 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001881 if (retval == 0)
1882 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001883 else
1884 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885}
1886
1887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1888/**
1889 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1890 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1891 *
1892 * (linux scsi_host_template.eh_dev_reset_handler routine)
1893 *
1894 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001895 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001896int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1898{
1899 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001900 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001901 VirtDevice *vdevice;
1902 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 /* If we can't locate our host adapter structure, return FAILED status.
1905 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001906 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001907 printk(KERN_ERR MYNAM ": target reset: "
1908 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 return FAILED;
1910 }
1911
Eric Moore958d4a32007-06-15 17:24:14 -06001912 ioc = hd->ioc;
1913 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1914 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001915 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
Eric Moore958d4a32007-06-15 17:24:14 -06001917 if (hd->resetPending) {
1918 retval = FAILED;
1919 goto out;
1920 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001921
Eric Moore958d4a32007-06-15 17:24:14 -06001922 vdevice = SCpnt->device->hostdata;
1923 if (!vdevice || !vdevice->vtarget) {
1924 retval = 0;
1925 goto out;
1926 }
1927
Eric Moorecc78d302007-06-15 17:27:21 -06001928 /* Target reset to hidden raid component is not supported
1929 */
1930 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1931 retval = FAILED;
1932 goto out;
1933 }
1934
Eric Moore958d4a32007-06-15 17:24:14 -06001935 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1936 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1937 mptscsih_get_tm_timeout(ioc));
1938
1939 out:
1940 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1941 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001942
1943 if (retval == 0)
1944 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001945 else
1946 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947}
1948
Eric Moorecd2c6192007-01-29 09:47:47 -07001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1951/**
1952 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1953 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1954 *
1955 * (linux scsi_host_template.eh_bus_reset_handler routine)
1956 *
1957 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001958 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001959int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1961{
1962 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001963 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001964 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001965 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966
1967 /* If we can't locate our host adapter structure, return FAILED status.
1968 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001969 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001970 printk(KERN_ERR MYNAM ": bus reset: "
1971 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 return FAILED;
1973 }
1974
Eric Moore958d4a32007-06-15 17:24:14 -06001975 ioc = hd->ioc;
1976 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1977 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001978 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979
1980 if (hd->timeouts < -1)
1981 hd->timeouts++;
1982
Eric Moorea69de502007-09-14 18:48:19 -06001983 vdevice = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001984 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moorea69de502007-09-14 18:48:19 -06001985 vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
Eric Moore958d4a32007-06-15 17:24:14 -06001987 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1988 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001989
1990 if (retval == 0)
1991 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001992 else
1993 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994}
1995
1996/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1997/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001998 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
2000 *
2001 * (linux scsi_host_template.eh_host_reset_handler routine)
2002 *
2003 * Returns SUCCESS or FAILED.
2004 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002005int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2007{
2008 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06002009 int retval;
2010 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
2012 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06002013 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06002014 printk(KERN_ERR MYNAM ": host reset: "
2015 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 return FAILED;
2017 }
2018
Eric Moore958d4a32007-06-15 17:24:14 -06002019 ioc = hd->ioc;
2020 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2021 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 /* If our attempts to reset the host failed, then return a failed
2024 * status. The host will be taken off line by the SCSI mid-layer.
2025 */
Eric Mooree80b0022007-09-14 18:49:03 -06002026 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06002027 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 } else {
2029 /* Make sure TM pending is cleared and TM state is set to
2030 * NONE.
2031 */
Eric Moore958d4a32007-06-15 17:24:14 -06002032 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 hd->tmPending = 0;
2034 hd->tmState = TM_STATE_NONE;
2035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Eric Moore958d4a32007-06-15 17:24:14 -06002037 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2038 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
Eric Moore958d4a32007-06-15 17:24:14 -06002040 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041}
2042
2043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2044/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002045 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 * @hd: Pointer to MPT host structure.
2047 *
2048 * Returns {SUCCESS,FAILED}.
2049 */
2050static int
2051mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2052{
2053 unsigned long flags;
2054 int loop_count = 4 * 10; /* Wait 10 seconds */
2055 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06002056 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
2058 do {
Eric Mooree80b0022007-09-14 18:49:03 -06002059 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 if (hd->tmState == TM_STATE_NONE) {
2061 hd->tmState = TM_STATE_IN_PROGRESS;
2062 hd->tmPending = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06002063 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002064 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 break;
2066 }
Eric Mooree80b0022007-09-14 18:49:03 -06002067 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 msleep(250);
2069 } while (--loop_count);
2070
2071 return status;
2072}
2073
2074/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2075/**
2076 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2077 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002078 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 *
2080 * Returns {SUCCESS,FAILED}.
2081 */
2082static int
2083mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2084{
2085 unsigned long flags;
2086 int loop_count = 4 * timeout;
2087 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06002088 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
2090 do {
Eric Mooree80b0022007-09-14 18:49:03 -06002091 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 if(hd->tmPending == 0) {
2093 status = SUCCESS;
Eric Mooree80b0022007-09-14 18:49:03 -06002094 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 break;
2096 }
Eric Mooree80b0022007-09-14 18:49:03 -06002097 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002098 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 } while (--loop_count);
2100
2101 return status;
2102}
2103
2104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002105static void
2106mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2107{
2108 char *desc;
2109
2110 switch (response_code) {
2111 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2112 desc = "The task completed.";
2113 break;
2114 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2115 desc = "The IOC received an invalid frame status.";
2116 break;
2117 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2118 desc = "The task type is not supported.";
2119 break;
2120 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2121 desc = "The requested task failed.";
2122 break;
2123 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2124 desc = "The task completed successfully.";
2125 break;
2126 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2127 desc = "The LUN request is invalid.";
2128 break;
2129 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2130 desc = "The task is in the IOC queue and has not been sent to target.";
2131 break;
2132 default:
2133 desc = "unknown";
2134 break;
2135 }
2136 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2137 ioc->name, response_code, desc);
2138}
2139
2140/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141/**
2142 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2143 * @ioc: Pointer to MPT_ADAPTER structure
2144 * @mf: Pointer to SCSI task mgmt request frame
2145 * @mr: Pointer to SCSI task mgmt reply frame
2146 *
2147 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2148 * of any SCSI task management request.
2149 * This routine is registered with the MPT (base) driver at driver
2150 * load/init time via the mpt_register() API call.
2151 *
2152 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002153 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002154int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2156{
2157 SCSITaskMgmtReply_t *pScsiTmReply;
2158 SCSITaskMgmt_t *pScsiTmReq;
2159 MPT_SCSI_HOST *hd;
2160 unsigned long flags;
2161 u16 iocstatus;
2162 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002163 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302165 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002166 ioc->name, mf, mr));
2167 if (!ioc->sh) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302168 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002169 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 return 1;
2171 }
2172
2173 if (mr == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302174 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002175 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 }
2178
Eric Mooree7eae9f2007-09-29 10:15:59 -06002179 hd = shost_priv(ioc->sh);
Eric Moorecd2c6192007-01-29 09:47:47 -07002180 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2181 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2182 tmType = pScsiTmReq->TaskType;
2183 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2184 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2185
2186 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2187 pScsiTmReply->ResponseCode)
2188 mptscsih_taskmgmt_response_code(ioc,
2189 pScsiTmReply->ResponseCode);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302190 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Eric Moorecd2c6192007-01-29 09:47:47 -07002191
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302192#ifdef CONFIG_FUSION_LOGGING
2193 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2194 (ioc->debug_level & MPT_DEBUG_TM ))
2195 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2196 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2197 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2198 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2199 le16_to_cpu(pScsiTmReply->IOCStatus),
2200 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2201 le32_to_cpu(pScsiTmReply->TerminationCount));
Eric Moorecd2c6192007-01-29 09:47:47 -07002202#endif
2203 if (!iocstatus) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302204 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
Eric Moorecd2c6192007-01-29 09:47:47 -07002205 hd->abortSCpnt = NULL;
2206 goto out;
2207 }
2208
2209 /* Error? (anything non-zero?) */
2210
2211 /* clear flags and continue.
2212 */
2213 switch (tmType) {
2214
2215 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2216 if (termination_count == 1)
2217 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2218 hd->abortSCpnt = NULL;
2219 break;
2220
2221 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2222
2223 /* If an internal command is present
2224 * or the TM failed - reload the FW.
2225 * FC FW may respond FAILED to an ABORT
2226 */
2227 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2228 hd->cmdPtr)
2229 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06002230 printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07002231 break;
2232
2233 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2234 default:
2235 break;
2236 }
2237
2238 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 spin_lock_irqsave(&ioc->FreeQlock, flags);
2240 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002242 hd->tm_iocstatus = iocstatus;
2243 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
2245 return 1;
2246}
2247
2248/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2249/*
2250 * This is anyones guess quite frankly.
2251 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002252int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2254 sector_t capacity, int geom[])
2255{
2256 int heads;
2257 int sectors;
2258 sector_t cylinders;
2259 ulong dummy;
2260
2261 heads = 64;
2262 sectors = 32;
2263
2264 dummy = heads * sectors;
2265 cylinders = capacity;
2266 sector_div(cylinders,dummy);
2267
2268 /*
2269 * Handle extended translation size for logical drives
2270 * > 1Gb
2271 */
2272 if ((ulong)capacity >= 0x200000) {
2273 heads = 255;
2274 sectors = 63;
2275 dummy = heads * sectors;
2276 cylinders = capacity;
2277 sector_div(cylinders,dummy);
2278 }
2279
2280 /* return result */
2281 geom[0] = heads;
2282 geom[1] = sectors;
2283 geom[2] = cylinders;
2284
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 return 0;
2286}
2287
Moore, Ericf44e5462006-03-14 09:14:21 -07002288/* Search IOC page 3 to determine if this is hidden physical disk
2289 *
2290 */
2291int
Eric Moore793955f2007-01-29 09:42:20 -07002292mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002293{
Eric Mooreb506ade2007-01-29 09:45:37 -07002294 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002295 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002296 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002297
Eric Moore793955f2007-01-29 09:42:20 -07002298 if (!ioc->raid_data.pIocPg3)
2299 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002300 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002301 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2302 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2303 rc = 1;
2304 goto out;
2305 }
2306 }
2307
Eric Mooreb506ade2007-01-29 09:45:37 -07002308 /*
2309 * Check inactive list for matching phys disks
2310 */
2311 if (list_empty(&ioc->raid_data.inactive_list))
2312 goto out;
2313
2314 down(&ioc->raid_data.inactive_list_mutex);
2315 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2316 list) {
2317 if ((component_info->d.PhysDiskID == id) &&
2318 (component_info->d.PhysDiskBus == channel))
2319 rc = 1;
2320 }
2321 up(&ioc->raid_data.inactive_list_mutex);
2322
Eric Moore793955f2007-01-29 09:42:20 -07002323 out:
2324 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002325}
2326EXPORT_SYMBOL(mptscsih_is_phys_disk);
2327
Eric Moore793955f2007-01-29 09:42:20 -07002328u8
2329mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002330{
Eric Mooreb506ade2007-01-29 09:45:37 -07002331 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002332 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002333 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002334
Eric Moore793955f2007-01-29 09:42:20 -07002335 if (!ioc->raid_data.pIocPg3)
2336 goto out;
2337 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2338 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2339 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2340 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2341 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002342 }
2343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Eric Mooreb506ade2007-01-29 09:45:37 -07002345 /*
2346 * Check inactive list for matching phys disks
2347 */
2348 if (list_empty(&ioc->raid_data.inactive_list))
2349 goto out;
2350
2351 down(&ioc->raid_data.inactive_list_mutex);
2352 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2353 list) {
2354 if ((component_info->d.PhysDiskID == id) &&
2355 (component_info->d.PhysDiskBus == channel))
2356 rc = component_info->d.PhysDiskNum;
2357 }
2358 up(&ioc->raid_data.inactive_list_mutex);
2359
Eric Moore793955f2007-01-29 09:42:20 -07002360 out:
2361 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002362}
Eric Moore793955f2007-01-29 09:42:20 -07002363EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002364
2365/*
2366 * OS entry point to allow for host driver to free allocated memory
2367 * Called if no device present or device being unloaded
2368 */
2369void
2370mptscsih_slave_destroy(struct scsi_device *sdev)
2371{
2372 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002373 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002374 VirtTarget *vtarget;
2375 VirtDevice *vdevice;
2376 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002378 starget = scsi_target(sdev);
2379 vtarget = starget->hostdata;
2380 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002382 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002383 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002384 mptscsih_synchronize_cache(hd, vdevice);
2385 kfree(vdevice);
2386 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387}
2388
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002389/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2390/*
2391 * mptscsih_change_queue_depth - This function will set a devices queue depth
2392 * @sdev: per scsi_device pointer
2393 * @qdepth: requested queue depth
2394 *
2395 * Adding support for new 'change_queue_depth' api.
2396*/
2397int
2398mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002400 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002401 VirtTarget *vtarget;
2402 struct scsi_target *starget;
2403 int max_depth;
2404 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002405 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 starget = scsi_target(sdev);
2408 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002409
Eric Mooree80b0022007-09-14 18:49:03 -06002410 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002411 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002413 else if (sdev->type == TYPE_DISK &&
2414 vtarget->minSyncFactor <= MPT_ULTRA160)
2415 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2416 else
2417 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 } else
2419 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2420
2421 if (qdepth > max_depth)
2422 qdepth = max_depth;
2423 if (qdepth == 1)
2424 tagged = 0;
2425 else
2426 tagged = MSG_SIMPLE_TAG;
2427
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002428 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2429 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430}
2431
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432/*
2433 * OS entry point to adjust the queue_depths on a per-device basis.
2434 * Called once per device the bus scan. Use it to force the queue_depth
2435 * member to 1 if a device does not support Q tags.
2436 * Return non-zero if fails.
2437 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002438int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002439mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002441 struct Scsi_Host *sh = sdev->host;
2442 VirtTarget *vtarget;
2443 VirtDevice *vdevice;
2444 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002445 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002446 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002448 starget = scsi_target(sdev);
2449 vtarget = starget->hostdata;
2450 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
Eric Mooree80b0022007-09-14 18:49:03 -06002452 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002453 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002454 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2455 if (ioc->bus_type == SPI)
2456 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002457 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002458 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002459 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002461 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002463 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 goto slave_configure_exit;
2465 }
2466
Eric Moore793955f2007-01-29 09:42:20 -07002467 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002468 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
Eric Mooree80b0022007-09-14 18:49:03 -06002470 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002472 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
Eric Mooree80b0022007-09-14 18:49:03 -06002474 if (ioc->bus_type == SPI)
2475 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002476 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002477 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002478 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480slave_configure_exit:
2481
Eric Mooree80b0022007-09-14 18:49:03 -06002482 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002484 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002485 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 return 0;
2488}
2489
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2491/*
2492 * Private routines...
2493 */
2494
2495/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2496/* Utility function to copy sense data from the scsi_cmnd buffer
2497 * to the FC and SCSI target structures.
2498 *
2499 */
2500static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002501mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502{
Eric Moorea69de502007-09-14 18:48:19 -06002503 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 SCSIIORequest_t *pReq;
2505 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002506 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
2508 /* Get target structure
2509 */
2510 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002511 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
2513 if (sense_count) {
2514 u8 *sense_data;
2515 int req_index;
2516
2517 /* Copy the sense received into the scsi command block. */
2518 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002519 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2521
2522 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2523 */
Eric Mooree80b0022007-09-14 18:49:03 -06002524 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002525 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002528 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2530 ioc->events[idx].eventContext = ioc->eventContext;
2531
Dave Jones3d9780b2007-05-21 20:59:47 -04002532 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2533 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2534 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
Dave Jones3d9780b2007-05-21 20:59:47 -04002536 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
2538 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002539 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002540 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002541 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002542 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2543 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002544 MPT_TARGET_FLAGS_LED_ON;
2545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547 }
2548 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002549 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2550 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 }
2552}
2553
Eric Moore3dc0b032006-07-11 17:32:33 -06002554static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2556{
2557 MPT_SCSI_HOST *hd;
2558 int i;
2559
Eric Mooree7eae9f2007-09-29 10:15:59 -06002560 hd = shost_priv(sc->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
2562 for (i = 0; i < hd->ioc->req_depth; i++) {
2563 if (hd->ScsiLookup[i] == sc) {
2564 return i;
2565 }
2566 }
2567
2568 return -1;
2569}
2570
2571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002572int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2574{
2575 MPT_SCSI_HOST *hd;
2576 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002577 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
Eric Moore29dd3602007-09-14 18:46:51 -06002579 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2580 ": IOC %s_reset routed to SCSI host driver!\n",
2581 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2582 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 /* If a FW reload request arrives after base installed but
2585 * before all scsi hosts have been attached, then an alt_ioc
2586 * may have a NULL sh pointer.
2587 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06002588 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 return 0;
2590 else
Eric Mooree7eae9f2007-09-29 10:15:59 -06002591 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
2593 if (reset_phase == MPT_IOC_SETUP_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302594 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595
2596 /* Clean Up:
2597 * 1. Set Hard Reset Pending Flag
2598 * All new commands go to doneQ
2599 */
2600 hd->resetPending = 1;
2601
2602 } else if (reset_phase == MPT_IOC_PRE_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302603 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 /* 2. Flush running commands
2606 * Clean ScsiLookup (and associated memory)
2607 * AND clean mytaskQ
2608 */
2609
2610 /* 2b. Reply to OS all known outstanding I/O commands.
2611 */
2612 mptscsih_flush_running_cmds(hd);
2613
2614 /* 2c. If there was an internal command that
2615 * has not completed, configuration or io request,
2616 * free these resources.
2617 */
2618 if (hd->cmdPtr) {
2619 del_timer(&hd->timer);
2620 mpt_free_msg_frame(ioc, hd->cmdPtr);
2621 }
2622
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302623 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302626 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628 /* Once a FW reload begins, all new OS commands are
2629 * redirected to the doneQ w/ a reset status.
2630 * Init all control structures.
2631 */
2632
2633 /* ScsiLookup initialization
2634 */
Eric Mooree80b0022007-09-14 18:49:03 -06002635 for (ii=0; ii < ioc->req_depth; ii++)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002636 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
2638 /* 2. Chain Buffer initialization
2639 */
2640
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002641 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
2644 /* 5. Enable new commands to be posted
2645 */
2646 spin_lock_irqsave(&ioc->FreeQlock, flags);
2647 hd->tmPending = 0;
2648 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2649 hd->resetPending = 0;
2650 hd->tmState = TM_STATE_NONE;
2651
2652 /* 6. If there was an internal command,
2653 * wake this process up.
2654 */
2655 if (hd->cmdPtr) {
2656 /*
2657 * Wake up the original calling thread
2658 */
2659 hd->pLocal = &hd->localReply;
2660 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002661 hd->scandv_wait_done = 1;
2662 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 hd->cmdPtr = NULL;
2664 }
2665
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302666 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
2668 }
2669
2670 return 1; /* currently means nothing really */
2671}
2672
2673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002674int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2676{
2677 MPT_SCSI_HOST *hd;
2678 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2679
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302680 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 ioc->name, event));
2682
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002683 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06002684 ((hd = shost_priv(ioc->sh)) == NULL))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002685 return 1;
2686
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 switch (event) {
2688 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2689 /* FIXME! */
2690 break;
2691 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2692 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002693 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002694 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 break;
2696 case MPI_EVENT_LOGOUT: /* 09 */
2697 /* FIXME! */
2698 break;
2699
Michael Reed05e8ec12006-01-13 14:31:54 -06002700 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002701 break;
2702
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 /*
2704 * CHECKME! Don't think we need to do
2705 * anything for these, but...
2706 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2708 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2709 /*
2710 * CHECKME! Falling thru...
2711 */
2712 break;
2713
2714 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002715 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 case MPI_EVENT_NONE: /* 00 */
2718 case MPI_EVENT_LOG_DATA: /* 01 */
2719 case MPI_EVENT_STATE_CHANGE: /* 02 */
2720 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2721 default:
Eric Moore29dd3602007-09-14 18:46:51 -06002722 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
2723 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 break;
2725 }
2726
2727 return 1; /* currently means nothing really */
2728}
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2731/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 * Bus Scan and Domain Validation functionality ...
2733 */
2734
2735/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2736/*
2737 * mptscsih_scandv_complete - Scan and DV callback routine registered
2738 * to Fustion MPT (base) driver.
2739 *
2740 * @ioc: Pointer to MPT_ADAPTER structure
2741 * @mf: Pointer to original MPT request frame
2742 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2743 *
2744 * This routine is called from mpt.c::mpt_interrupt() at the completion
2745 * of any SCSI IO request.
2746 * This routine is registered with the Fusion MPT (base) driver at driver
2747 * load/init time via the mpt_register() API call.
2748 *
2749 * Returns 1 indicating alloc'd request frame ptr should be freed.
2750 *
2751 * Remark: Sets a completion code and (possibly) saves sense data
2752 * in the IOC member localReply structure.
2753 * Used ONLY for DV and other internal commands.
2754 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002755int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2757{
2758 MPT_SCSI_HOST *hd;
2759 SCSIIORequest_t *pReq;
2760 int completionCode;
2761 u16 req_idx;
2762
Eric Mooree7eae9f2007-09-29 10:15:59 -06002763 hd = shost_priv(ioc->sh);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 if ((mf == NULL) ||
2766 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2767 printk(MYIOC_s_ERR_FMT
2768 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2769 ioc->name, mf?"BAD":"NULL", (void *) mf);
2770 goto wakeup;
2771 }
2772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 del_timer(&hd->timer);
2774 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2775 hd->ScsiLookup[req_idx] = NULL;
2776 pReq = (SCSIIORequest_t *) mf;
2777
2778 if (mf != hd->cmdPtr) {
2779 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002780 ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 }
2782 hd->cmdPtr = NULL;
2783
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302784 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002785 ioc->name, mf, mr, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
2787 hd->pLocal = &hd->localReply;
2788 hd->pLocal->scsiStatus = 0;
2789
2790 /* If target struct exists, clear sense valid flag.
2791 */
2792 if (mr == NULL) {
2793 completionCode = MPT_SCANDV_GOOD;
2794 } else {
2795 SCSIIOReply_t *pReply;
2796 u16 status;
2797 u8 scsi_status;
2798
2799 pReply = (SCSIIOReply_t *) mr;
2800
2801 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2802 scsi_status = pReply->SCSIStatus;
2803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
2805 switch(status) {
2806
2807 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2808 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2809 break;
2810
2811 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2812 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2813 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2814 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2815 completionCode = MPT_SCANDV_DID_RESET;
2816 break;
2817
2818 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2819 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2820 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2821 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2822 ConfigReply_t *pr = (ConfigReply_t *)mr;
2823 completionCode = MPT_SCANDV_GOOD;
2824 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2825 hd->pLocal->header.PageLength = pr->Header.PageLength;
2826 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2827 hd->pLocal->header.PageType = pr->Header.PageType;
2828
2829 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2830 /* If the RAID Volume request is successful,
2831 * return GOOD, else indicate that
2832 * some type of error occurred.
2833 */
2834 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002835 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 completionCode = MPT_SCANDV_GOOD;
2837 else
2838 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002839 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2842 u8 *sense_data;
2843 int sz;
2844
2845 /* save sense data in global structure
2846 */
2847 completionCode = MPT_SCANDV_SENSE;
2848 hd->pLocal->scsiStatus = scsi_status;
Eric Mooree80b0022007-09-14 18:49:03 -06002849 sense_data = ((u8 *)ioc->sense_buf_pool +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2851
2852 sz = min_t(int, pReq->SenseBufferLength,
2853 SCSI_STD_SENSE_BYTES);
2854 memcpy(hd->pLocal->sense, sense_data, sz);
2855
Eric Moore29dd3602007-09-14 18:46:51 -06002856 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
2857 ioc->name, sense_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2859 if (pReq->CDB[0] == INQUIRY)
2860 completionCode = MPT_SCANDV_ISSUE_SENSE;
2861 else
2862 completionCode = MPT_SCANDV_DID_RESET;
2863 }
2864 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2865 completionCode = MPT_SCANDV_DID_RESET;
2866 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2867 completionCode = MPT_SCANDV_DID_RESET;
2868 else {
2869 completionCode = MPT_SCANDV_GOOD;
2870 hd->pLocal->scsiStatus = scsi_status;
2871 }
2872 break;
2873
2874 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2875 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2876 completionCode = MPT_SCANDV_DID_RESET;
2877 else
2878 completionCode = MPT_SCANDV_SOME_ERROR;
2879 break;
2880
2881 default:
2882 completionCode = MPT_SCANDV_SOME_ERROR;
2883 break;
2884
2885 } /* switch(status) */
2886
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 } /* end of address reply case */
2888
2889 hd->pLocal->completion = completionCode;
2890
2891 /* MF and RF are freed in mpt_interrupt
2892 */
2893wakeup:
2894 /* Free Chain buffers (will never chain) in scan or dv */
2895 //mptscsih_freeChainBuffers(ioc, req_idx);
2896
2897 /*
2898 * Wake up the original calling thread
2899 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002900 hd->scandv_wait_done = 1;
2901 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
2903 return 1;
2904}
2905
2906/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2907/* mptscsih_timer_expired - Call back for timer process.
2908 * Used only for dv functionality.
2909 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2910 *
2911 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002912void
2913mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914{
2915 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002916 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Eric Mooree80b0022007-09-14 18:49:03 -06002918 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 if (hd->cmdPtr) {
2921 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2922
2923 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2924 /* Desire to issue a task management request here.
2925 * TM requests MUST be single threaded.
2926 * If old eh code and no TM current, issue request.
2927 * If new eh code, do nothing. Wait for OS cmd timeout
2928 * for bus reset.
2929 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 } else {
2931 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002932 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2933 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 }
2935 }
2936 } else {
2937 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002938 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 }
2940
2941 /* No more processing.
2942 * TM call will generate an interrupt for SCSI TM Management.
2943 * The FW will reply to all outstanding commands, callback will finish cleanup.
2944 * Hard reset clean-up will free all resources.
2945 */
Eric Mooree80b0022007-09-14 18:49:03 -06002946 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
2948 return;
2949}
2950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
2952/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2953/**
2954 * mptscsih_do_cmd - Do internal command.
2955 * @hd: MPT_SCSI_HOST pointer
2956 * @io: INTERNAL_CMD pointer.
2957 *
2958 * Issue the specified internally generated command and do command
2959 * specific cleanup. For bus scan / DV only.
2960 * NOTES: If command is Inquiry and status is good,
2961 * initialize a target structure, save the data
2962 *
2963 * Remark: Single threaded access only.
2964 *
2965 * Return:
2966 * < 0 if an illegal command or no resources
2967 *
2968 * 0 if good
2969 *
2970 * > 0 if command complete but some type of completion error.
2971 */
2972static int
2973mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2974{
2975 MPT_FRAME_HDR *mf;
2976 SCSIIORequest_t *pScsiReq;
2977 SCSIIORequest_t ReqCopy;
2978 int my_idx, ii, dir;
2979 int rc, cmdTimeout;
2980 int in_isr;
2981 char cmdLen;
2982 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2983 char cmd = io->cmd;
Eric Mooree80b0022007-09-14 18:49:03 -06002984 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
2986 in_isr = in_interrupt();
2987 if (in_isr) {
Eric Mooree80b0022007-09-14 18:49:03 -06002988 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2989 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 return -EPERM;
2991 }
2992
2993
2994 /* Set command specific information
2995 */
2996 switch (cmd) {
2997 case INQUIRY:
2998 cmdLen = 6;
2999 dir = MPI_SCSIIO_CONTROL_READ;
3000 CDB[0] = cmd;
3001 CDB[4] = io->size;
3002 cmdTimeout = 10;
3003 break;
3004
3005 case TEST_UNIT_READY:
3006 cmdLen = 6;
3007 dir = MPI_SCSIIO_CONTROL_READ;
3008 cmdTimeout = 10;
3009 break;
3010
3011 case START_STOP:
3012 cmdLen = 6;
3013 dir = MPI_SCSIIO_CONTROL_READ;
3014 CDB[0] = cmd;
3015 CDB[4] = 1; /*Spin up the disk */
3016 cmdTimeout = 15;
3017 break;
3018
3019 case REQUEST_SENSE:
3020 cmdLen = 6;
3021 CDB[0] = cmd;
3022 CDB[4] = io->size;
3023 dir = MPI_SCSIIO_CONTROL_READ;
3024 cmdTimeout = 10;
3025 break;
3026
3027 case READ_BUFFER:
3028 cmdLen = 10;
3029 dir = MPI_SCSIIO_CONTROL_READ;
3030 CDB[0] = cmd;
3031 if (io->flags & MPT_ICFLAG_ECHO) {
3032 CDB[1] = 0x0A;
3033 } else {
3034 CDB[1] = 0x02;
3035 }
3036
3037 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3038 CDB[1] |= 0x01;
3039 }
3040 CDB[6] = (io->size >> 16) & 0xFF;
3041 CDB[7] = (io->size >> 8) & 0xFF;
3042 CDB[8] = io->size & 0xFF;
3043 cmdTimeout = 10;
3044 break;
3045
3046 case WRITE_BUFFER:
3047 cmdLen = 10;
3048 dir = MPI_SCSIIO_CONTROL_WRITE;
3049 CDB[0] = cmd;
3050 if (io->flags & MPT_ICFLAG_ECHO) {
3051 CDB[1] = 0x0A;
3052 } else {
3053 CDB[1] = 0x02;
3054 }
3055 CDB[6] = (io->size >> 16) & 0xFF;
3056 CDB[7] = (io->size >> 8) & 0xFF;
3057 CDB[8] = io->size & 0xFF;
3058 cmdTimeout = 10;
3059 break;
3060
3061 case RESERVE:
3062 cmdLen = 6;
3063 dir = MPI_SCSIIO_CONTROL_READ;
3064 CDB[0] = cmd;
3065 cmdTimeout = 10;
3066 break;
3067
3068 case RELEASE:
3069 cmdLen = 6;
3070 dir = MPI_SCSIIO_CONTROL_READ;
3071 CDB[0] = cmd;
3072 cmdTimeout = 10;
3073 break;
3074
3075 case SYNCHRONIZE_CACHE:
3076 cmdLen = 10;
3077 dir = MPI_SCSIIO_CONTROL_READ;
3078 CDB[0] = cmd;
3079// CDB[1] = 0x02; /* set immediate bit */
3080 cmdTimeout = 10;
3081 break;
3082
3083 default:
3084 /* Error Case */
3085 return -EFAULT;
3086 }
3087
3088 /* Get and Populate a free Frame
3089 */
Eric Mooree80b0022007-09-14 18:49:03 -06003090 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
3091 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
3092 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 return -EBUSY;
3094 }
3095
3096 pScsiReq = (SCSIIORequest_t *) mf;
3097
3098 /* Get the request index */
3099 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3100 ADD_INDEX_LOG(my_idx); /* for debug */
3101
3102 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3103 pScsiReq->TargetID = io->physDiskNum;
3104 pScsiReq->Bus = 0;
3105 pScsiReq->ChainOffset = 0;
3106 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3107 } else {
3108 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003109 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 pScsiReq->ChainOffset = 0;
3111 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3112 }
3113
3114 pScsiReq->CDBLength = cmdLen;
3115 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3116
3117 pScsiReq->Reserved = 0;
3118
3119 pScsiReq->MsgFlags = mpt_msg_flags();
3120 /* MsgContext set in mpt_get_msg_fram call */
3121
Eric Moore793955f2007-01-29 09:42:20 -07003122 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123
3124 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3125 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3126 else
3127 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3128
3129 if (cmd == REQUEST_SENSE) {
3130 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Eric Mooree80b0022007-09-14 18:49:03 -06003131 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
3132 ioc->name, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 }
3134
3135 for (ii=0; ii < 16; ii++)
3136 pScsiReq->CDB[ii] = CDB[ii];
3137
3138 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003139 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3141
Eric Mooree80b0022007-09-14 18:49:03 -06003142 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3143 ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
3145 if (dir == MPI_SCSIIO_CONTROL_READ) {
3146 mpt_add_sge((char *) &pScsiReq->SGL,
3147 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3148 io->data_dma);
3149 } else {
3150 mpt_add_sge((char *) &pScsiReq->SGL,
3151 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3152 io->data_dma);
3153 }
3154
3155 /* The ISR will free the request frame, but we need
3156 * the information to initialize the target. Duplicate.
3157 */
3158 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3159
3160 /* Issue this command after:
3161 * finish init
3162 * add timer
3163 * Wait until the reply has been received
3164 * ScsiScanDvCtx callback function will
3165 * set hd->pLocal;
3166 * set scandv_wait_done and call wake_up
3167 */
3168 hd->pLocal = NULL;
3169 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003170 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 /* Save cmd pointer, for resource free if timeout or
3173 * FW reload occurs
3174 */
3175 hd->cmdPtr = mf;
3176
3177 add_timer(&hd->timer);
Eric Mooree80b0022007-09-14 18:49:03 -06003178 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003179 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
3181 if (hd->pLocal) {
3182 rc = hd->pLocal->completion;
3183 hd->pLocal->skip = 0;
3184
3185 /* Always set fatal error codes in some cases.
3186 */
3187 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3188 rc = -ENXIO;
3189 else if (rc == MPT_SCANDV_SOME_ERROR)
3190 rc = -rc;
3191 } else {
3192 rc = -EFAULT;
3193 /* This should never happen. */
Eric Mooree80b0022007-09-14 18:49:03 -06003194 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
3195 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 }
3197
3198 return rc;
3199}
3200
3201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3202/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003203 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3204 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003205 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003206 *
3207 * Uses the ISR, but with special processing.
3208 * MUST be single-threaded.
3209 *
3210 */
3211static void
3212mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3213{
3214 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
Eric Moorecc78d302007-06-15 17:27:21 -06003216 /* Ignore hidden raid components, this is handled when the command
3217 * is sent to the volume
3218 */
3219 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3220 return;
3221
3222 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3223 !vdevice->configured_lun)
3224 return;
3225
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 /* Following parameters will not change
3227 * in this routine.
3228 */
3229 iocmd.cmd = SYNCHRONIZE_CACHE;
3230 iocmd.flags = 0;
3231 iocmd.physDiskNum = -1;
3232 iocmd.data = NULL;
3233 iocmd.data_dma = -1;
3234 iocmd.size = 0;
3235 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003236 iocmd.channel = vdevice->vtarget->channel;
3237 iocmd.id = vdevice->vtarget->id;
3238 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
Eric Moorecc78d302007-06-15 17:27:21 -06003240 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241}
3242
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303243static ssize_t
3244mptscsih_version_fw_show(struct class_device *cdev, char *buf)
3245{
3246 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003247 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303248 MPT_ADAPTER *ioc = hd->ioc;
3249
3250 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3251 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3252 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3253 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3254 ioc->facts.FWVersion.Word & 0x000000FF);
3255}
3256static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3257
3258static ssize_t
3259mptscsih_version_bios_show(struct class_device *cdev, char *buf)
3260{
3261 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003262 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303263 MPT_ADAPTER *ioc = hd->ioc;
3264
3265 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3266 (ioc->biosVersion & 0xFF000000) >> 24,
3267 (ioc->biosVersion & 0x00FF0000) >> 16,
3268 (ioc->biosVersion & 0x0000FF00) >> 8,
3269 ioc->biosVersion & 0x000000FF);
3270}
3271static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3272
3273static ssize_t
3274mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
3275{
3276 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003277 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303278 MPT_ADAPTER *ioc = hd->ioc;
3279
3280 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3281}
3282static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3283
3284static ssize_t
3285mptscsih_version_product_show(struct class_device *cdev, char *buf)
3286{
3287 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003288 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303289 MPT_ADAPTER *ioc = hd->ioc;
3290
3291 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3292}
3293static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
3294 mptscsih_version_product_show, NULL);
3295
3296static ssize_t
3297mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
3298{
3299 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003300 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303301 MPT_ADAPTER *ioc = hd->ioc;
3302
3303 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3304 ioc->nvdata_version_persistent);
3305}
3306static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3307 mptscsih_version_nvdata_persistent_show, NULL);
3308
3309static ssize_t
3310mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
3311{
3312 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003313 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303314 MPT_ADAPTER *ioc = hd->ioc;
3315
3316 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3317}
3318static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3319 mptscsih_version_nvdata_default_show, NULL);
3320
3321static ssize_t
3322mptscsih_board_name_show(struct class_device *cdev, char *buf)
3323{
3324 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003325 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303326 MPT_ADAPTER *ioc = hd->ioc;
3327
3328 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3329}
3330static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3331
3332static ssize_t
3333mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
3334{
3335 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003336 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303337 MPT_ADAPTER *ioc = hd->ioc;
3338
3339 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3340}
3341static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
3342 mptscsih_board_assembly_show, NULL);
3343
3344static ssize_t
3345mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
3346{
3347 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003348 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303349 MPT_ADAPTER *ioc = hd->ioc;
3350
3351 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3352}
3353static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
3354 mptscsih_board_tracer_show, NULL);
3355
3356static ssize_t
3357mptscsih_io_delay_show(struct class_device *cdev, char *buf)
3358{
3359 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003360 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303361 MPT_ADAPTER *ioc = hd->ioc;
3362
3363 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3364}
3365static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
3366 mptscsih_io_delay_show, NULL);
3367
3368static ssize_t
3369mptscsih_device_delay_show(struct class_device *cdev, char *buf)
3370{
3371 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003372 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303373 MPT_ADAPTER *ioc = hd->ioc;
3374
3375 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3376}
3377static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
3378 mptscsih_device_delay_show, NULL);
3379
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303380static ssize_t
3381mptscsih_debug_level_show(struct class_device *cdev, char *buf)
3382{
3383 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003384 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303385 MPT_ADAPTER *ioc = hd->ioc;
3386
3387 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3388}
3389static ssize_t
3390mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
3391 size_t count)
3392{
3393 struct Scsi_Host *host = class_to_shost(cdev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003394 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303395 MPT_ADAPTER *ioc = hd->ioc;
3396 int val = 0;
3397
3398 if (sscanf(buf, "%x", &val) != 1)
3399 return -EINVAL;
3400
3401 ioc->debug_level = val;
3402 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3403 ioc->name, ioc->debug_level);
3404 return strlen(buf);
3405}
3406static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3407 mptscsih_debug_level_show, mptscsih_debug_level_store);
3408
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303409struct class_device_attribute *mptscsih_host_attrs[] = {
3410 &class_device_attr_version_fw,
3411 &class_device_attr_version_bios,
3412 &class_device_attr_version_mpi,
3413 &class_device_attr_version_product,
3414 &class_device_attr_version_nvdata_persistent,
3415 &class_device_attr_version_nvdata_default,
3416 &class_device_attr_board_name,
3417 &class_device_attr_board_assembly,
3418 &class_device_attr_board_tracer,
3419 &class_device_attr_io_delay,
3420 &class_device_attr_device_delay,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303421 &class_device_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303422 NULL,
3423};
3424EXPORT_SYMBOL(mptscsih_host_attrs);
3425
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003426EXPORT_SYMBOL(mptscsih_remove);
3427EXPORT_SYMBOL(mptscsih_shutdown);
3428#ifdef CONFIG_PM
3429EXPORT_SYMBOL(mptscsih_suspend);
3430EXPORT_SYMBOL(mptscsih_resume);
3431#endif
3432EXPORT_SYMBOL(mptscsih_proc_info);
3433EXPORT_SYMBOL(mptscsih_info);
3434EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003435EXPORT_SYMBOL(mptscsih_slave_destroy);
3436EXPORT_SYMBOL(mptscsih_slave_configure);
3437EXPORT_SYMBOL(mptscsih_abort);
3438EXPORT_SYMBOL(mptscsih_dev_reset);
3439EXPORT_SYMBOL(mptscsih_bus_reset);
3440EXPORT_SYMBOL(mptscsih_host_reset);
3441EXPORT_SYMBOL(mptscsih_bios_param);
3442EXPORT_SYMBOL(mptscsih_io_done);
3443EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3444EXPORT_SYMBOL(mptscsih_scandv_complete);
3445EXPORT_SYMBOL(mptscsih_event_process);
3446EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003447EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003448EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003449EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/