[SCSI] aic7xxx: Take the LED out of diagnostic mode on PM resume
[linux-2.6-block.git] / drivers / message / fusion / mptscsih.c
CommitLineData
1da177e4
LT
1/*
2 * linux/drivers/message/fusion/mptscsih.c
f36789e2
PS
3 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
1da177e4 5 *
cddc0ab7 6 * Copyright (c) 1999-2008 LSI Corporation
16d20101 7 * (mailto:DL-MPTFusionLinux@lsi.com)
1da177e4 8 *
1da177e4
LT
9 */
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
1da177e4
LT
47#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 */
1da177e4
LT
56#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>
e0fc15be 63#include <scsi/scsi_dbg.h>
1da177e4
LT
64
65#include "mptbase.h"
66#include "mptscsih.h"
bf451522 67#include "lsi/mpi_log_sas.h"
1da177e4
LT
68
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
9f4203b3 77MODULE_VERSION(my_VERSION);
1da177e4 78
1da177e4 79/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1da177e4
LT
80/*
81 * Other private/forward protos...
82 */
e8206381
EM
83static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
84static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
85static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
86static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
0d0c7974 87int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1da177e4 88static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
0d0c7974 89int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1da177e4
LT
90
91static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
92 SCSIIORequest_t *pReq, int req_idx);
93static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
0d0c7974 94static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
1da177e4
LT
95static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
96static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
1da177e4 97
793955f5 98static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
1da177e4 99
0d0c7974
MED
100int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
101int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
1da177e4 102
0d0c7974 103int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
1da177e4 104static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
c7c82987 105static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
1da177e4 106
0d0c7974 107void mptscsih_remove(struct pci_dev *);
d18c3db5 108void mptscsih_shutdown(struct pci_dev *);
1da177e4 109#ifdef CONFIG_PM
0d0c7974
MED
110int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
111int mptscsih_resume(struct pci_dev *pdev);
1da177e4
LT
112#endif
113
b80ca4f7 114#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
1da177e4 115
1da177e4
LT
116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
117/**
118 * mptscsih_add_sge - Place a simple SGE at address pAddr.
119 * @pAddr: virtual address for SGE
120 * @flagslength: SGE flags and data transfer length
121 * @dma_addr: Physical address
122 *
123 * This routine places a MPT request frame back on the MPT adapter's
124 * FreeQ.
125 */
126static inline void
127mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
128{
129 if (sizeof(dma_addr_t) == sizeof(u64)) {
130 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
131 u32 tmp = dma_addr & 0xFFFFFFFF;
132
133 pSge->FlagsLength = cpu_to_le32(flagslength);
134 pSge->Address.Low = cpu_to_le32(tmp);
135 tmp = (u32) ((u64)dma_addr >> 32);
136 pSge->Address.High = cpu_to_le32(tmp);
137
138 } else {
139 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
140 pSge->FlagsLength = cpu_to_le32(flagslength);
141 pSge->Address = cpu_to_le32(dma_addr);
142 }
143} /* mptscsih_add_sge() */
144
145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
146/**
147 * mptscsih_add_chain - Place a chain SGE at address pAddr.
148 * @pAddr: virtual address for SGE
149 * @next: nextChainOffset value (u32's)
150 * @length: length of next SGL segment
151 * @dma_addr: Physical address
152 *
153 * This routine places a MPT request frame back on the MPT adapter's
154 * FreeQ.
155 */
156static inline void
157mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
158{
159 if (sizeof(dma_addr_t) == sizeof(u64)) {
160 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
161 u32 tmp = dma_addr & 0xFFFFFFFF;
162
163 pChain->Length = cpu_to_le16(length);
164 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
165
166 pChain->NextChainOffset = next;
167
168 pChain->Address.Low = cpu_to_le32(tmp);
169 tmp = (u32) ((u64)dma_addr >> 32);
170 pChain->Address.High = cpu_to_le32(tmp);
171 } else {
172 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
173 pChain->Length = cpu_to_le16(length);
174 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
175 pChain->NextChainOffset = next;
176 pChain->Address = cpu_to_le32(dma_addr);
177 }
178} /* mptscsih_add_chain() */
179
180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
181/*
182 * mptscsih_getFreeChainBuffer - Function to get a free chain
183 * from the MPT_SCSI_HOST FreeChainQ.
184 * @ioc: Pointer to MPT_ADAPTER structure
185 * @req_idx: Index of the SCSI IO request frame. (output)
186 *
187 * return SUCCESS or FAILED
188 */
189static inline int
190mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
191{
192 MPT_FRAME_HDR *chainBuf;
193 unsigned long flags;
194 int rc;
195 int chain_idx;
196
6757d6b4 197 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
29dd3609 198 ioc->name));
1da177e4
LT
199 spin_lock_irqsave(&ioc->FreeQlock, flags);
200 if (!list_empty(&ioc->FreeChainQ)) {
201 int offset;
202
203 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
204 u.frame.linkage.list);
205 list_del(&chainBuf->u.frame.linkage.list);
206 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
207 chain_idx = offset / ioc->req_sz;
208 rc = SUCCESS;
29dd3609
EM
209 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
210 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
211 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
1da177e4
LT
212 } else {
213 rc = FAILED;
214 chain_idx = MPT_HOST_NO_CHAIN;
29dd3609
EM
215 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
216 ioc->name));
1da177e4
LT
217 }
218 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
219
220 *retIndex = chain_idx;
221 return rc;
222} /* mptscsih_getFreeChainBuffer() */
223
224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
225/*
226 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
227 * SCSIIORequest_t Message Frame.
228 * @ioc: Pointer to MPT_ADAPTER structure
229 * @SCpnt: Pointer to scsi_cmnd structure
230 * @pReq: Pointer to SCSIIORequest_t structure
231 *
232 * Returns ...
233 */
234static int
235mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
236 SCSIIORequest_t *pReq, int req_idx)
237{
238 char *psge;
239 char *chainSge;
240 struct scatterlist *sg;
241 int frm_sz;
242 int sges_left, sg_done;
243 int chain_idx = MPT_HOST_NO_CHAIN;
244 int sgeOffset;
245 int numSgeSlots, numSgeThisFrame;
246 u32 sgflags, sgdir, thisxfer = 0;
247 int chain_dma_off = 0;
248 int newIndex;
249 int ii;
250 dma_addr_t v2;
251 u32 RequestNB;
252
253 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
254 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
255 sgdir = MPT_TRANSFER_HOST_TO_IOC;
256 } else {
257 sgdir = MPT_TRANSFER_IOC_TO_HOST;
258 }
259
260 psge = (char *) &pReq->SGL;
261 frm_sz = ioc->req_sz;
262
263 /* Map the data portion, if any.
264 * sges_left = 0 if no data transfer.
265 */
1928d73f
FT
266 sges_left = scsi_dma_map(SCpnt);
267 if (sges_left < 0)
268 return FAILED;
1da177e4
LT
269
270 /* Handle the SG case.
271 */
1928d73f 272 sg = scsi_sglist(SCpnt);
1da177e4
LT
273 sg_done = 0;
274 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
275 chainSge = NULL;
276
277 /* Prior to entering this loop - the following must be set
278 * current MF: sgeOffset (bytes)
279 * chainSge (Null if original MF is not a chain buffer)
280 * sg_done (num SGE done for this MF)
281 */
282
283nextSGEset:
284 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
285 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
286
287 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
288
289 /* Get first (num - 1) SG elements
290 * Skip any SG entries with a length of 0
291 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
292 */
293 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
294 thisxfer = sg_dma_len(sg);
295 if (thisxfer == 0) {
ed17b031 296 sg = sg_next(sg); /* Get next SG element from the OS */
1da177e4
LT
297 sg_done++;
298 continue;
299 }
300
301 v2 = sg_dma_address(sg);
302 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
303
ed17b031 304 sg = sg_next(sg); /* Get next SG element from the OS */
1da177e4
LT
305 psge += (sizeof(u32) + sizeof(dma_addr_t));
306 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
307 sg_done++;
308 }
309
310 if (numSgeThisFrame == sges_left) {
311 /* Add last element, end of buffer and end of list flags.
312 */
313 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
314 MPT_SGE_FLAGS_END_OF_BUFFER |
315 MPT_SGE_FLAGS_END_OF_LIST;
316
317 /* Add last SGE and set termination flags.
318 * Note: Last SGE may have a length of 0 - which should be ok.
319 */
320 thisxfer = sg_dma_len(sg);
321
322 v2 = sg_dma_address(sg);
323 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
324 /*
ed17b031 325 sg = sg_next(sg);
1da177e4
LT
326 psge += (sizeof(u32) + sizeof(dma_addr_t));
327 */
328 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
329 sg_done++;
330
331 if (chainSge) {
332 /* The current buffer is a chain buffer,
333 * but there is not another one.
334 * Update the chain element
335 * Offset and Length fields.
336 */
337 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
338 } else {
339 /* The current buffer is the original MF
340 * and there is no Chain buffer.
341 */
342 pReq->ChainOffset = 0;
343 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
6757d6b4 344 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1da177e4
LT
345 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
346 ioc->RequestNB[req_idx] = RequestNB;
347 }
348 } else {
349 /* At least one chain buffer is needed.
350 * Complete the first MF
351 * - last SGE element, set the LastElement bit
352 * - set ChainOffset (words) for orig MF
353 * (OR finish previous MF chain buffer)
354 * - update MFStructPtr ChainIndex
355 * - Populate chain element
356 * Also
357 * Loop until done.
358 */
359
6757d6b4 360 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
1da177e4
LT
361 ioc->name, sg_done));
362
363 /* Set LAST_ELEMENT flag for last non-chain element
364 * in the buffer. Since psge points at the NEXT
365 * SGE element, go back one SGE element, update the flags
366 * and reset the pointer. (Note: sgflags & thisxfer are already
367 * set properly).
368 */
369 if (sg_done) {
370 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
371 sgflags = le32_to_cpu(*ptmp);
372 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
373 *ptmp = cpu_to_le32(sgflags);
374 }
375
376 if (chainSge) {
377 /* The current buffer is a chain buffer.
378 * chainSge points to the previous Chain Element.
379 * Update its chain element Offset and Length (must
380 * include chain element size) fields.
381 * Old chain element is now complete.
382 */
383 u8 nextChain = (u8) (sgeOffset >> 2);
384 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
385 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
386 } else {
387 /* The original MF buffer requires a chain buffer -
388 * set the offset.
389 * Last element in this MF is a chain element.
390 */
391 pReq->ChainOffset = (u8) (sgeOffset >> 2);
392 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
6757d6b4 393 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
1da177e4
LT
394 ioc->RequestNB[req_idx] = RequestNB;
395 }
396
397 sges_left -= sg_done;
398
399
400 /* NOTE: psge points to the beginning of the chain element
401 * in current buffer. Get a chain buffer.
402 */
c6678e0c 403 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
6757d6b4 404 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
c6678e0c
CH
405 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
406 ioc->name, pReq->CDB[0], SCpnt));
1da177e4 407 return FAILED;
c6678e0c 408 }
1da177e4
LT
409
410 /* Update the tracking arrays.
411 * If chainSge == NULL, update ReqToChain, else ChainToChain
412 */
413 if (chainSge) {
414 ioc->ChainToChain[chain_idx] = newIndex;
415 } else {
416 ioc->ReqToChain[req_idx] = newIndex;
417 }
418 chain_idx = newIndex;
419 chain_dma_off = ioc->req_sz * chain_idx;
420
421 /* Populate the chainSGE for the current buffer.
422 * - Set chain buffer pointer to psge and fill
423 * out the Address and Flags fields.
424 */
425 chainSge = (char *) psge;
29dd3609
EM
426 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
427 ioc->name, psge, req_idx));
1da177e4
LT
428
429 /* Start the SGE for the next buffer
430 */
431 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
432 sgeOffset = 0;
433 sg_done = 0;
434
29dd3609
EM
435 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
436 ioc->name, psge, chain_idx));
1da177e4
LT
437
438 /* Start the SGE for the next buffer
439 */
440
441 goto nextSGEset;
442 }
443
444 return SUCCESS;
445} /* mptscsih_AddSGE() */
446
786899b0
EM
447static void
448mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
449 U32 SlotStatus)
450{
451 MPT_FRAME_HDR *mf;
452 SEPRequest_t *SEPMsg;
453
cc78d30a
EM
454 if (ioc->bus_type != SAS)
455 return;
456
457 /* Not supported for hidden raid components
458 */
459 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
786899b0
EM
460 return;
461
462 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
6757d6b4 463 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
cadbd4a5 464 ioc->name,__func__));
786899b0
EM
465 return;
466 }
467
468 SEPMsg = (SEPRequest_t *)mf;
469 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
793955f5
EM
470 SEPMsg->Bus = vtarget->channel;
471 SEPMsg->TargetID = vtarget->id;
786899b0
EM
472 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
473 SEPMsg->SlotStatus = SlotStatus;
6757d6b4 474 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
793955f5
EM
475 "Sending SEP cmd=%x channel=%d id=%d\n",
476 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
786899b0
EM
477 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
478}
479
6757d6b4 480#ifdef CONFIG_FUSION_LOGGING
c6c727a1 481/**
6757d6b4 482 * mptscsih_info_scsiio - debug print info on reply frame
c6c727a1 483 * @ioc: Pointer to MPT_ADAPTER structure
c6c727a1 484 * @sc: original scsi cmnd pointer
6757d6b4
PS
485 * @pScsiReply: Pointer to MPT reply frame
486 *
487 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
c6c727a1
EM
488 *
489 * Refer to lsi/mpi.h.
490 **/
491static void
6757d6b4 492mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
c6c727a1 493{
6757d6b4
PS
494 char *desc = NULL;
495 char *desc1 = NULL;
496 u16 ioc_status;
497 u8 skey, asc, ascq;
498
499 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
c6c727a1
EM
500
501 switch (ioc_status) {
502
6757d6b4
PS
503 case MPI_IOCSTATUS_SUCCESS:
504 desc = "success";
c6c727a1 505 break;
6757d6b4
PS
506 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
507 desc = "invalid bus";
c6c727a1 508 break;
6757d6b4
PS
509 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
510 desc = "invalid target_id";
c6c727a1 511 break;
6757d6b4
PS
512 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
513 desc = "device not there";
c6c727a1 514 break;
6757d6b4
PS
515 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
516 desc = "data overrun";
c6c727a1 517 break;
6757d6b4
PS
518 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
519 desc = "data underrun";
c6c727a1 520 break;
6757d6b4
PS
521 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
522 desc = "I/O data error";
c6c727a1 523 break;
6757d6b4
PS
524 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
525 desc = "protocol error";
c6c727a1 526 break;
6757d6b4
PS
527 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
528 desc = "task terminated";
c6c727a1 529 break;
6757d6b4
PS
530 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
531 desc = "residual mismatch";
532 break;
533 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
534 desc = "task management failed";
535 break;
536 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
537 desc = "IOC terminated";
538 break;
539 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
540 desc = "ext terminated";
c6c727a1 541 break;
6757d6b4
PS
542 default:
543 desc = "";
544 break;
545 }
546
547 switch (pScsiReply->SCSIStatus)
548 {
c6c727a1 549
6757d6b4
PS
550 case MPI_SCSI_STATUS_SUCCESS:
551 desc1 = "success";
552 break;
553 case MPI_SCSI_STATUS_CHECK_CONDITION:
554 desc1 = "check condition";
555 break;
556 case MPI_SCSI_STATUS_CONDITION_MET:
557 desc1 = "condition met";
558 break;
559 case MPI_SCSI_STATUS_BUSY:
560 desc1 = "busy";
561 break;
562 case MPI_SCSI_STATUS_INTERMEDIATE:
563 desc1 = "intermediate";
564 break;
565 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
566 desc1 = "intermediate condmet";
567 break;
568 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
569 desc1 = "reservation conflict";
570 break;
571 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
572 desc1 = "command terminated";
573 break;
574 case MPI_SCSI_STATUS_TASK_SET_FULL:
575 desc1 = "task set full";
576 break;
577 case MPI_SCSI_STATUS_ACA_ACTIVE:
578 desc1 = "aca active";
579 break;
580 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
581 desc1 = "fcpext device logged out";
582 break;
583 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
584 desc1 = "fcpext no link";
585 break;
586 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
587 desc1 = "fcpext unassigned";
588 break;
589 default:
590 desc1 = "";
c6c727a1
EM
591 break;
592 }
593
6757d6b4 594 scsi_print_command(sc);
29dd3609
EM
595 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
596 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
597 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
598 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
599 scsi_get_resid(sc));
600 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
601 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
6757d6b4 602 le32_to_cpu(pScsiReply->TransferCount), sc->result);
29dd3609 603 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
6757d6b4 604 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
29dd3609 605 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
6757d6b4 606 pScsiReply->SCSIState);
c6c727a1 607
6757d6b4
PS
608 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
609 skey = sc->sense_buffer[2] & 0x0F;
610 asc = sc->sense_buffer[12];
611 ascq = sc->sense_buffer[13];
612
29dd3609
EM
613 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
614 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
6757d6b4
PS
615 }
616
617 /*
618 * Look for + dump FCP ResponseInfo[]!
619 */
620 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
621 pScsiReply->ResponseInfo)
29dd3609
EM
622 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
623 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
c6c727a1
EM
624}
625#endif
626
1da177e4
LT
627/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
628/*
629 * mptscsih_io_done - Main SCSI IO callback routine registered to
630 * Fusion MPT (base) driver
631 * @ioc: Pointer to MPT_ADAPTER structure
632 * @mf: Pointer to original MPT request frame
633 * @r: Pointer to MPT reply frame (NULL if TurboReply)
634 *
635 * This routine is called from mpt.c::mpt_interrupt() at the completion
636 * of any SCSI IO request.
637 * This routine is registered with the Fusion MPT (base) driver at driver
638 * load/init time via the mpt_register() API call.
639 *
640 * Returns 1 indicating alloc'd request frame ptr should be freed.
641 */
0d0c7974 642int
1da177e4
LT
643mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
644{
645 struct scsi_cmnd *sc;
646 MPT_SCSI_HOST *hd;
647 SCSIIORequest_t *pScsiReq;
648 SCSIIOReply_t *pScsiReply;
2254c86d 649 u16 req_idx, req_idx_MR;
a69de507 650 VirtDevice *vdevice;
786899b0 651 VirtTarget *vtarget;
1da177e4 652
e7eae9f6 653 hd = shost_priv(ioc->sh);
1da177e4 654 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2254c86d
ME
655 req_idx_MR = (mr != NULL) ?
656 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
657 if ((req_idx != req_idx_MR) ||
658 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
659 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
660 ioc->name);
661 printk (MYIOC_s_ERR_FMT
662 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
663 ioc->name, req_idx, req_idx_MR, mf, mr,
e8206381 664 mptscsih_get_scsi_lookup(ioc, req_idx_MR));
2254c86d
ME
665 return 0;
666 }
667
e8206381 668 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
1da177e4
LT
669 if (sc == NULL) {
670 MPIHeader_t *hdr = (MPIHeader_t *)mf;
671
672 /* Remark: writeSDP1 will use the ScsiDoneCtx
673 * If a SCSI I/O cmd, device disabled by OS and
674 * completion done. Cannot touch sc struct. Just free mem.
675 */
676 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
677 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
678 ioc->name);
679
680 mptscsih_freeChainBuffers(ioc, req_idx);
681 return 1;
682 }
683
3dc0b03f
EM
684 if ((unsigned char *)mf != sc->host_scribble) {
685 mptscsih_freeChainBuffers(ioc, req_idx);
686 return 1;
687 }
688
689 sc->host_scribble = NULL;
1da177e4
LT
690 sc->result = DID_OK << 16; /* Set default reply as OK */
691 pScsiReq = (SCSIIORequest_t *) mf;
692 pScsiReply = (SCSIIOReply_t *) mr;
693
c6678e0c 694 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
6757d6b4 695 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
c6678e0c
CH
696 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
697 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
698 }else{
6757d6b4 699 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
c6678e0c
CH
700 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
701 ioc->name, mf, mr, sc, req_idx));
702 }
703
1da177e4
LT
704 if (pScsiReply == NULL) {
705 /* special context reply handling */
706 ;
707 } else {
708 u32 xfer_cnt;
709 u16 status;
710 u8 scsi_state, scsi_status;
c6c727a1 711 u32 log_info;
1da177e4
LT
712
713 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
714 scsi_state = pScsiReply->SCSIState;
715 scsi_status = pScsiReply->SCSIStatus;
716 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
1928d73f 717 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
c6c727a1 718 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
1da177e4 719
466544d8
MED
720 /*
721 * if we get a data underrun indication, yet no data was
722 * transferred and the SCSI status indicates that the
723 * command was never started, change the data underrun
724 * to success
725 */
726 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
727 (scsi_status == MPI_SCSI_STATUS_BUSY ||
728 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
729 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
730 status = MPI_IOCSTATUS_SUCCESS;
731 }
732
1da177e4 733 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
0d0c7974
MED
734 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
735
1da177e4
LT
736 /*
737 * Look for + dump FCP ResponseInfo[]!
738 */
466544d8
MED
739 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
740 pScsiReply->ResponseInfo) {
29dd3609
EM
741 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
742 "FCP_ResponseInfo=%08xh\n", ioc->name,
c6c727a1
EM
743 sc->device->host->host_no, sc->device->channel,
744 sc->device->id, sc->device->lun,
1da177e4
LT
745 le32_to_cpu(pScsiReply->ResponseInfo));
746 }
747
748 switch(status) {
749 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
750 /* CHECKME!
751 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
752 * But not: DID_BUS_BUSY lest one risk
753 * killing interrupt handler:-(
754 */
755 sc->result = SAM_STAT_BUSY;
756 break;
757
758 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
759 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
760 sc->result = DID_BAD_TARGET << 16;
761 break;
762
763 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
764 /* Spoof to SCSI Selection Timeout! */
65207fed
ME
765 if (ioc->bus_type != FC)
766 sc->result = DID_NO_CONNECT << 16;
767 /* else fibre, just stall until rescan event */
768 else
769 sc->result = DID_REQUEUE << 16;
1da177e4
LT
770
771 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
772 hd->sel_timeout[pScsiReq->TargetID]++;
786899b0 773
a69de507
EM
774 vdevice = sc->device->hostdata;
775 if (!vdevice)
786899b0 776 break;
a69de507 777 vtarget = vdevice->vtarget;
786899b0
EM
778 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
779 mptscsih_issue_sep_command(ioc, vtarget,
780 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
781 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
782 }
1da177e4
LT
783 break;
784
1da177e4 785 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
bf451522
EM
786 if ( ioc->bus_type == SAS ) {
787 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
788 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
c6c727a1
EM
789 if ((log_info & SAS_LOGINFO_MASK)
790 == SAS_LOGINFO_NEXUS_LOSS) {
bf451522
EM
791 sc->result = (DID_BUS_BUSY << 16);
792 break;
793 }
794 }
86dd4242
EM
795 } else if (ioc->bus_type == FC) {
796 /*
797 * The FC IOC may kill a request for variety of
798 * reasons, some of which may be recovered by a
799 * retry, some which are unlikely to be
800 * recovered. Return DID_ERROR instead of
801 * DID_RESET to permit retry of the command,
802 * just not an infinite number of them
803 */
804 sc->result = DID_ERROR << 16;
805 break;
bf451522
EM
806 }
807
808 /*
809 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
810 */
811
812 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
1da177e4
LT
813 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
814 /* Linux handles an unsolicited DID_RESET better
815 * than an unsolicited DID_ABORT.
816 */
817 sc->result = DID_RESET << 16;
818
1da177e4
LT
819 break;
820
821 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
1928d73f 822 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
466544d8
MED
823 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
824 sc->result=DID_SOFT_ERROR << 16;
825 else /* Sufficient data transfer occurred */
1da177e4 826 sc->result = (DID_OK << 16) | scsi_status;
29dd3609 827 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
c6c727a1 828 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
29dd3609 829 ioc->name, sc->result, sc->device->channel, sc->device->id));
1da177e4 830 break;
0d0c7974 831
1da177e4
LT
832 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
833 /*
834 * Do upfront check for valid SenseData and give it
835 * precedence!
836 */
837 sc->result = (DID_OK << 16) | scsi_status;
838 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
839 /* Have already saved the status and sense data
840 */
841 ;
842 } else {
843 if (xfer_cnt < sc->underflow) {
466544d8
MED
844 if (scsi_status == SAM_STAT_BUSY)
845 sc->result = SAM_STAT_BUSY;
846 else
847 sc->result = DID_SOFT_ERROR << 16;
1da177e4
LT
848 }
849 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
850 /* What to do?
851 */
852 sc->result = DID_SOFT_ERROR << 16;
853 }
854 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
855 /* Not real sure here either... */
856 sc->result = DID_RESET << 16;
857 }
858 }
859
6757d6b4 860
29dd3609
EM
861 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
862 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
863 ioc->name, sc->underflow));
864 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
865 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
6757d6b4 866
1da177e4
LT
867 /* Report Queue Full
868 */
869 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
870 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
0d0c7974 871
1da177e4
LT
872 break;
873
7e55147f 874 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
1928d73f 875 scsi_set_resid(sc, 0);
1da177e4
LT
876 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
877 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
ad8c31bb 878 sc->result = (DID_OK << 16) | scsi_status;
1da177e4
LT
879 if (scsi_state == 0) {
880 ;
881 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
882 /*
883 * If running against circa 200003dd 909 MPT f/w,
884 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
885 * (QUEUE_FULL) returned from device! --> get 0x0000?128
886 * and with SenseBytes set to 0.
887 */
888 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
889 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
890
891 }
892 else if (scsi_state &
893 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
894 ) {
895 /*
896 * What to do?
897 */
898 sc->result = DID_SOFT_ERROR << 16;
899 }
900 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
901 /* Not real sure here either... */
902 sc->result = DID_RESET << 16;
903 }
904 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
905 /* Device Inq. data indicates that it supports
906 * QTags, but rejects QTag messages.
907 * This command completed OK.
908 *
909 * Not real sure here either so do nothing... */
910 }
911
912 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
913 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
914
915 /* Add handling of:
916 * Reservation Conflict, Busy,
917 * Command Terminated, CHECK
918 */
919 break;
920
921 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
922 sc->result = DID_SOFT_ERROR << 16;
923 break;
924
925 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
926 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
927 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
928 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
929 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
930 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
931 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
1da177e4
LT
932 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
933 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
934 default:
935 /*
936 * What to do?
937 */
938 sc->result = DID_SOFT_ERROR << 16;
939 break;
940
941 } /* switch(status) */
942
6757d6b4
PS
943#ifdef CONFIG_FUSION_LOGGING
944 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
945 mptscsih_info_scsiio(ioc, sc, pScsiReply);
c6c727a1
EM
946#endif
947
1da177e4
LT
948 } /* end of address reply case */
949
950 /* Unmap the DMA buffers, if any. */
1928d73f 951 scsi_dma_unmap(sc);
1da177e4 952
1da177e4
LT
953 sc->scsi_done(sc); /* Issue the command callback */
954
955 /* Free Chain buffers */
956 mptscsih_freeChainBuffers(ioc, req_idx);
957 return 1;
958}
959
1da177e4
LT
960/*
961 * mptscsih_flush_running_cmds - For each command found, search
962 * Scsi_Host instance taskQ and reply to OS.
963 * Called only if recovering from a FW reload.
964 * @hd: Pointer to a SCSI HOST structure
965 *
966 * Returns: None.
967 *
968 * Must be called while new I/Os are being queued.
969 */
970static void
971mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
972{
973 MPT_ADAPTER *ioc = hd->ioc;
e8206381
EM
974 struct scsi_cmnd *sc;
975 SCSIIORequest_t *mf = NULL;
1da177e4 976 int ii;
e8206381 977 int channel, id;
1da177e4 978
e8206381
EM
979 for (ii= 0; ii < ioc->req_depth; ii++) {
980 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
981 if (!sc)
982 continue;
983 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
984 if (!mf)
985 continue;
986 channel = mf->Bus;
987 id = mf->TargetID;
988 mptscsih_freeChainBuffers(ioc, ii);
989 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
990 if ((unsigned char *)mf != sc->host_scribble)
991 continue;
992 scsi_dma_unmap(sc);
993 sc->result = DID_RESET << 16;
994 sc->host_scribble = NULL;
c51d0bea 995 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
e8206381
EM
996 "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
997 " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
998 sc->scsi_done(sc);
1da177e4 999 }
1da177e4
LT
1000}
1001
1002/*
1003 * mptscsih_search_running_cmds - Delete any commands associated
1004 * with the specified target and lun. Function called only
1005 * when a lun is disable by mid-layer.
1006 * Do NOT access the referenced scsi_cmnd structure or
1007 * members. Will cause either a paging or NULL ptr error.
05e8ec17 1008 * (BUT, BUT, BUT, the code does reference it! - mdr)
c7c82987
MED
1009 * @hd: Pointer to a SCSI HOST structure
1010 * @vdevice: per device private data
1da177e4
LT
1011 *
1012 * Returns: None.
1013 *
1014 * Called from slave_destroy.
1015 */
1016static void
c7c82987 1017mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
1da177e4
LT
1018{
1019 SCSIIORequest_t *mf = NULL;
1020 int ii;
466544d8 1021 struct scsi_cmnd *sc;
793955f5 1022 struct scsi_lun lun;
e80b002b 1023 MPT_ADAPTER *ioc = hd->ioc;
e8206381 1024 unsigned long flags;
1da177e4 1025
e8206381
EM
1026 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1027 for (ii = 0; ii < ioc->req_depth; ii++) {
1028 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
1da177e4 1029
e80b002b 1030 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
3dc0b03f
EM
1031 if (mf == NULL)
1032 continue;
cc78d30a
EM
1033 /* If the device is a hidden raid component, then its
1034 * expected that the mf->function will be RAID_SCSI_IO
1035 */
1036 if (vdevice->vtarget->tflags &
1037 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1038 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1039 continue;
1040
793955f5
EM
1041 int_to_scsilun(vdevice->lun, &lun);
1042 if ((mf->Bus != vdevice->vtarget->channel) ||
1043 (mf->TargetID != vdevice->vtarget->id) ||
1044 memcmp(lun.scsi_lun, mf->LUN, 8))
1da177e4
LT
1045 continue;
1046
3dc0b03f
EM
1047 if ((unsigned char *)mf != sc->host_scribble)
1048 continue;
e8206381
EM
1049 ioc->ScsiLookup[ii] = NULL;
1050 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1051 mptscsih_freeChainBuffers(ioc, ii);
1052 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1928d73f 1053 scsi_dma_unmap(sc);
466544d8
MED
1054 sc->host_scribble = NULL;
1055 sc->result = DID_NO_CONNECT << 16;
c51d0bea 1056 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
e80b002b 1057 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
6757d6b4 1058 vdevice->vtarget->id, sc, mf, ii);
466544d8 1059 sc->scsi_done(sc);
e8206381 1060 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1da177e4
LT
1061 }
1062 }
e8206381 1063 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1da177e4
LT
1064 return;
1065}
1066
1067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1da177e4
LT
1068
1069/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1070/*
1071 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1072 * from a SCSI target device.
1073 * @sc: Pointer to scsi_cmnd structure
1074 * @pScsiReply: Pointer to SCSIIOReply_t
1075 * @pScsiReq: Pointer to original SCSI request
1076 *
1077 * This routine periodically reports QUEUE_FULL status returned from a
1078 * SCSI target device. It reports this to the console via kernel
1079 * printk() API call, not more than once every 10 seconds.
1080 */
1081static void
1082mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1083{
1084 long time = jiffies;
1da177e4 1085 MPT_SCSI_HOST *hd;
e80b002b 1086 MPT_ADAPTER *ioc;
1da177e4 1087
0d0c7974
MED
1088 if (sc->device == NULL)
1089 return;
1090 if (sc->device->host == NULL)
1091 return;
e7eae9f6 1092 if ((hd = shost_priv(sc->device->host)) == NULL)
0d0c7974 1093 return;
e80b002b 1094 ioc = hd->ioc;
0d0c7974 1095 if (time - hd->last_queue_full > 10 * HZ) {
e80b002b
EM
1096 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1097 ioc->name, 0, sc->device->id, sc->device->lun));
0d0c7974 1098 hd->last_queue_full = time;
1da177e4 1099 }
1da177e4
LT
1100}
1101
1102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1103/*
1104 * mptscsih_remove - Removed scsi devices
1105 * @pdev: Pointer to pci_dev structure
1106 *
1107 *
1108 */
0d0c7974 1109void
1da177e4
LT
1110mptscsih_remove(struct pci_dev *pdev)
1111{
1112 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1113 struct Scsi_Host *host = ioc->sh;
1114 MPT_SCSI_HOST *hd;
0d0c7974 1115 int sz1;
1da177e4 1116
466544d8
MED
1117 if(!host) {
1118 mpt_detach(pdev);
1da177e4 1119 return;
466544d8 1120 }
1da177e4
LT
1121
1122 scsi_remove_host(host);
1123
e7eae9f6 1124 if((hd = shost_priv(host)) == NULL)
0d0c7974
MED
1125 return;
1126
d18c3db5 1127 mptscsih_shutdown(pdev);
1da177e4 1128
0d0c7974 1129 sz1=0;
1da177e4 1130
e8206381 1131 if (ioc->ScsiLookup != NULL) {
e80b002b 1132 sz1 = ioc->req_depth * sizeof(void *);
e8206381
EM
1133 kfree(ioc->ScsiLookup);
1134 ioc->ScsiLookup = NULL;
0d0c7974 1135 }
1da177e4 1136
e80b002b 1137 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
0d0c7974 1138 "Free'd ScsiLookup (%d) memory\n",
e80b002b 1139 ioc->name, sz1));
1da177e4 1140
d485eb83 1141 kfree(hd->info_kbuf);
1da177e4 1142
0d0c7974
MED
1143 /* NULL the Scsi_Host pointer
1144 */
e80b002b 1145 ioc->sh = NULL;
1da177e4
LT
1146
1147 scsi_host_put(host);
1da177e4 1148
0d0c7974 1149 mpt_detach(pdev);
c6678e0c 1150
1da177e4
LT
1151}
1152
1153/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1154/*
1155 * mptscsih_shutdown - reboot notifier
1156 *
1157 */
0d0c7974 1158void
d18c3db5 1159mptscsih_shutdown(struct pci_dev *pdev)
1da177e4 1160{
1da177e4
LT
1161}
1162
1163#ifdef CONFIG_PM
1164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1165/*
0d0c7974 1166 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
1da177e4
LT
1167 *
1168 *
1169 */
0d0c7974 1170int
8d189f72 1171mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
1da177e4 1172{
4d4109d0
PS
1173 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1174
1175 scsi_block_requests(ioc->sh);
1176 flush_scheduled_work();
d18c3db5 1177 mptscsih_shutdown(pdev);
0d0c7974 1178 return mpt_suspend(pdev,state);
1da177e4
LT
1179}
1180
1181/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1182/*
1183 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1184 *
1185 *
1186 */
0d0c7974 1187int
1da177e4
LT
1188mptscsih_resume(struct pci_dev *pdev)
1189{
4d4109d0
PS
1190 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1191 int rc;
1192
1193 rc = mpt_resume(pdev);
1194 scsi_unblock_requests(ioc->sh);
1195 return rc;
1da177e4
LT
1196}
1197
1198#endif
1199
1da177e4
LT
1200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1201/**
1202 * mptscsih_info - Return information about MPT adapter
1203 * @SChost: Pointer to Scsi_Host structure
1204 *
1205 * (linux scsi_host_template.info routine)
1206 *
1207 * Returns pointer to buffer where information was written.
1208 */
0d0c7974 1209const char *
1da177e4
LT
1210mptscsih_info(struct Scsi_Host *SChost)
1211{
1212 MPT_SCSI_HOST *h;
1213 int size = 0;
1214
e7eae9f6 1215 h = shost_priv(SChost);
0d0c7974 1216
1da177e4 1217 if (h) {
0d0c7974
MED
1218 if (h->info_kbuf == NULL)
1219 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1220 return h->info_kbuf;
1221 h->info_kbuf[0] = '\0';
1222
1223 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1224 h->info_kbuf[size-1] = '\0';
1da177e4
LT
1225 }
1226
0d0c7974 1227 return h->info_kbuf;
1da177e4
LT
1228}
1229
1230struct info_str {
1231 char *buffer;
1232 int length;
1233 int offset;
1234 int pos;
1235};
1236
0d0c7974
MED
1237static void
1238mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
1da177e4
LT
1239{
1240 if (info->pos + len > info->length)
1241 len = info->length - info->pos;
1242
1243 if (info->pos + len < info->offset) {
1244 info->pos += len;
1245 return;
1246 }
1247
1248 if (info->pos < info->offset) {
1249 data += (info->offset - info->pos);
1250 len -= (info->offset - info->pos);
1251 }
1252
1253 if (len > 0) {
1254 memcpy(info->buffer + info->pos, data, len);
1255 info->pos += len;
1256 }
1257}
1258
0d0c7974
MED
1259static int
1260mptscsih_copy_info(struct info_str *info, char *fmt, ...)
1da177e4
LT
1261{
1262 va_list args;
1263 char buf[81];
1264 int len;
1265
1266 va_start(args, fmt);
1267 len = vsprintf(buf, fmt, args);
1268 va_end(args);
1269
0d0c7974 1270 mptscsih_copy_mem_info(info, buf, len);
1da177e4
LT
1271 return len;
1272}
1273
0d0c7974
MED
1274static int
1275mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
1da177e4
LT
1276{
1277 struct info_str info;
1278
1279 info.buffer = pbuf;
1280 info.length = len;
1281 info.offset = offset;
1282 info.pos = 0;
1283
0d0c7974
MED
1284 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1285 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1286 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1287 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
1da177e4
LT
1288
1289 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1290}
1291
1292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1293/**
1294 * mptscsih_proc_info - Return information about MPT adapter
d9489fb6
RD
1295 * @host: scsi host struct
1296 * @buffer: if write, user data; if read, buffer for user
1297 * @start: returns the buffer address
1298 * @offset: if write, 0; if read, the current offset into the buffer from
1299 * the previous read.
1300 * @length: if write, return length;
1301 * @func: write = 1; read = 0
1da177e4
LT
1302 *
1303 * (linux scsi_host_template.info routine)
1da177e4 1304 */
0d0c7974 1305int
1da177e4
LT
1306mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1307 int length, int func)
1308{
e7eae9f6 1309 MPT_SCSI_HOST *hd = shost_priv(host);
1da177e4
LT
1310 MPT_ADAPTER *ioc = hd->ioc;
1311 int size = 0;
1312
1313 if (func) {
c6678e0c
CH
1314 /*
1315 * write is not supported
1da177e4
LT
1316 */
1317 } else {
1318 if (start)
1319 *start = buffer;
1320
1321 size = mptscsih_host_info(ioc, buffer, offset, length);
1322 }
1323
1324 return size;
1325}
1326
1327/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1328#define ADD_INDEX_LOG(req_ent) do { } while(0)
1329
1330/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1331/**
1332 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1333 * @SCpnt: Pointer to scsi_cmnd structure
1334 * @done: Pointer SCSI mid-layer IO completion function
1335 *
1336 * (linux scsi_host_template.queuecommand routine)
1337 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1338 * from a linux scsi_cmnd request and send it to the IOC.
1339 *
1340 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1341 */
0d0c7974 1342int
1da177e4
LT
1343mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1344{
1345 MPT_SCSI_HOST *hd;
1346 MPT_FRAME_HDR *mf;
1347 SCSIIORequest_t *pScsiReq;
a69de507 1348 VirtDevice *vdevice = SCpnt->device->hostdata;
1da177e4
LT
1349 int lun;
1350 u32 datalen;
1351 u32 scsictl;
1352 u32 scsidir;
1353 u32 cmd_len;
1354 int my_idx;
1355 int ii;
6757d6b4 1356 MPT_ADAPTER *ioc;
1da177e4 1357
e7eae9f6 1358 hd = shost_priv(SCpnt->device->host);
6757d6b4 1359 ioc = hd->ioc;
1da177e4
LT
1360 lun = SCpnt->device->lun;
1361 SCpnt->scsi_done = done;
1362
6757d6b4
PS
1363 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1364 ioc->name, SCpnt, done));
1da177e4
LT
1365
1366 if (hd->resetPending) {
6757d6b4
PS
1367 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1368 ioc->name, SCpnt));
1da177e4
LT
1369 return SCSI_MLQUEUE_HOST_BUSY;
1370 }
1371
1372 /*
1373 * Put together a MPT SCSI request...
1374 */
e80b002b 1375 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
6757d6b4
PS
1376 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1377 ioc->name));
1da177e4
LT
1378 return SCSI_MLQUEUE_HOST_BUSY;
1379 }
1380
1381 pScsiReq = (SCSIIORequest_t *) mf;
1382
1383 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1384
1385 ADD_INDEX_LOG(my_idx);
1386
0d0c7974 1387 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
1da177e4
LT
1388 * Seems we may receive a buffer (datalen>0) even when there
1389 * will be no data transfer! GRRRRR...
1390 */
1391 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1928d73f 1392 datalen = scsi_bufflen(SCpnt);
1da177e4
LT
1393 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1394 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1928d73f 1395 datalen = scsi_bufflen(SCpnt);
1da177e4
LT
1396 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1397 } else {
1398 datalen = 0;
1399 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1400 }
1401
1402 /* Default to untagged. Once a target structure has been allocated,
1403 * use the Inquiry data to determine if device supports tagged.
1404 */
a69de507
EM
1405 if (vdevice
1406 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
1da177e4
LT
1407 && (SCpnt->device->tagged_supported)) {
1408 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1409 } else {
1410 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1411 }
1412
1413 /* Use the above information to set up the message frame
1414 */
a69de507
EM
1415 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1416 pScsiReq->Bus = vdevice->vtarget->channel;
1da177e4 1417 pScsiReq->ChainOffset = 0;
a69de507 1418 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
c92f222e
JB
1419 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1420 else
1421 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1da177e4
LT
1422 pScsiReq->CDBLength = SCpnt->cmd_len;
1423 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1424 pScsiReq->Reserved = 0;
1425 pScsiReq->MsgFlags = mpt_msg_flags();
793955f5 1426 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
1da177e4
LT
1427 pScsiReq->Control = cpu_to_le32(scsictl);
1428
1429 /*
1430 * Write SCSI CDB into the message
1431 */
1432 cmd_len = SCpnt->cmd_len;
1433 for (ii=0; ii < cmd_len; ii++)
1434 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1435
1436 for (ii=cmd_len; ii < 16; ii++)
1437 pScsiReq->CDB[ii] = 0;
1438
1439 /* DataLength */
1440 pScsiReq->DataLength = cpu_to_le32(datalen);
1441
1442 /* SenseBuffer low address */
e80b002b 1443 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
1da177e4
LT
1444 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1445
1446 /* Now add the SG list
1447 * Always have a SGE even if null length.
1448 */
1449 if (datalen == 0) {
1450 /* Add a NULL SGE */
1451 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1452 (dma_addr_t) -1);
1453 } else {
1454 /* Add a 32 or 64 bit SGE */
e80b002b 1455 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1da177e4
LT
1456 goto fail;
1457 }
1458
3dc0b03f 1459 SCpnt->host_scribble = (unsigned char *)mf;
e8206381 1460 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
1da177e4 1461
e80b002b 1462 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
6757d6b4
PS
1463 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1464 ioc->name, SCpnt, mf, my_idx));
29dd3609 1465 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
1da177e4
LT
1466 return 0;
1467
1468 fail:
e80b002b
EM
1469 mptscsih_freeChainBuffers(ioc, my_idx);
1470 mpt_free_msg_frame(ioc, mf);
1da177e4
LT
1471 return SCSI_MLQUEUE_HOST_BUSY;
1472}
1473
1474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1475/*
1476 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1477 * with a SCSI IO request
1478 * @hd: Pointer to the MPT_SCSI_HOST instance
1479 * @req_idx: Index of the SCSI IO request frame.
1480 *
1481 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1482 * No return.
1483 */
1484static void
1485mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1486{
1487 MPT_FRAME_HDR *chain;
1488 unsigned long flags;
1489 int chain_idx;
1490 int next;
1491
1492 /* Get the first chain index and reset
1493 * tracker state.
1494 */
1495 chain_idx = ioc->ReqToChain[req_idx];
1496 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1497
1498 while (chain_idx != MPT_HOST_NO_CHAIN) {
1499
1500 /* Save the next chain buffer index */
1501 next = ioc->ChainToChain[chain_idx];
1502
1503 /* Free this chain buffer and reset
1504 * tracker
1505 */
1506 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1507
1508 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1509 + (chain_idx * ioc->req_sz));
1510
1511 spin_lock_irqsave(&ioc->FreeQlock, flags);
1512 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1513 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1514
6757d6b4 1515 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
1da177e4
LT
1516 ioc->name, chain_idx));
1517
1518 /* handle next */
1519 chain_idx = next;
1520 }
1521 return;
1522}
1523
1524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1525/*
1526 * Reset Handling
1527 */
1528
1529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
cd2c6191 1530/**
1da177e4 1531 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1544d677 1532 * @hd: Pointer to MPT SCSI HOST structure
1da177e4 1533 * @type: Task Management type
1544d677 1534 * @channel: channel number for task management
793955f5 1535 * @id: Logical Target ID for reset (if appropriate)
1da177e4
LT
1536 * @lun: Logical Unit for reset (if appropriate)
1537 * @ctx2abort: Context for the task to be aborted (if appropriate)
1544d677
RD
1538 * @timeout: timeout for task management control
1539 *
1540 * Fall through to mpt_HardResetHandler if: not operational, too many
1541 * failed TM requests or handshake failure.
1da177e4
LT
1542 *
1543 * Remark: Currently invoked from a non-interrupt thread (_bh).
1544 *
7105a387 1545 * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1da177e4
LT
1546 * will be active.
1547 *
1544d677 1548 * Returns 0 for SUCCESS, or %FAILED.
cd2c6191 1549 **/
663e1aa1 1550int
793955f5 1551mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
1da177e4
LT
1552{
1553 MPT_ADAPTER *ioc;
1554 int rc = -1;
1da177e4
LT
1555 u32 ioc_raw_state;
1556 unsigned long flags;
1557
1da177e4 1558 ioc = hd->ioc;
6757d6b4 1559 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
1da177e4
LT
1560
1561 // SJR - CHECKME - Can we avoid this here?
1562 // (mpt_HardResetHandler has this check...)
1563 spin_lock_irqsave(&ioc->diagLock, flags);
1564 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1565 spin_unlock_irqrestore(&ioc->diagLock, flags);
1566 return FAILED;
1567 }
1568 spin_unlock_irqrestore(&ioc->diagLock, flags);
1569
1570 /* Wait a fixed amount of time for the TM pending flag to be cleared.
cd2c6191
EM
1571 * If we time out and not bus reset, then we return a FAILED status
1572 * to the caller.
1573 * The call to mptscsih_tm_pending_wait() will set the pending flag
1574 * if we are
1da177e4
LT
1575 * successful. Otherwise, reload the FW.
1576 */
1577 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1578 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
29dd3609 1579 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
1da177e4 1580 "Timed out waiting for last TM (%d) to complete! \n",
6757d6b4 1581 ioc->name, hd->tmPending));
1da177e4
LT
1582 return FAILED;
1583 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
29dd3609 1584 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
cd2c6191 1585 "reset: Timed out waiting for last TM (%d) "
6757d6b4 1586 "to complete! \n", ioc->name,
cd2c6191 1587 hd->tmPending));
1da177e4
LT
1588 return FAILED;
1589 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
29dd3609 1590 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
1da177e4 1591 "Timed out waiting for last TM (%d) to complete! \n",
6757d6b4 1592 ioc->name, hd->tmPending));
cd2c6191 1593 return FAILED;
1da177e4
LT
1594 }
1595 } else {
e80b002b 1596 spin_lock_irqsave(&ioc->FreeQlock, flags);
1da177e4 1597 hd->tmPending |= (1 << type);
e80b002b 1598 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1da177e4
LT
1599 }
1600
e80b002b 1601 ioc_raw_state = mpt_GetIocState(ioc, 0);
1da177e4 1602
1da177e4
LT
1603 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1604 printk(MYIOC_s_WARN_FMT
cd2c6191
EM
1605 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1606 ioc->name, type, ioc_raw_state);
29dd3609 1607 printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
cd2c6191 1608 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
29dd3609
EM
1609 printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
1610 "FAILED!!\n", ioc->name);
cd2c6191 1611 return FAILED;
1da177e4
LT
1612 }
1613
cd2c6191
EM
1614 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1615 printk(MYIOC_s_WARN_FMT
1616 "TM Handler for type=%x: ioc_state: "
1617 "DOORBELL_ACTIVE (0x%x)!\n",
1618 ioc->name, type, ioc_raw_state);
1619 return FAILED;
1da177e4
LT
1620 }
1621
cd2c6191 1622 /* Isse the Task Mgmt request.
3dc0b03f 1623 */
cd2c6191
EM
1624 if (hd->hard_resets < -1)
1625 hd->hard_resets++;
1626
1627 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1628 ctx2abort, timeout);
1629 if (rc)
1630 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
6757d6b4 1631 ioc->name);
cd2c6191 1632 else
6757d6b4
PS
1633 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1634 ioc->name));
3dc0b03f 1635
6757d6b4
PS
1636 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1637 "TMHandler rc = %d!\n", ioc->name, rc));
1da177e4
LT
1638
1639 return rc;
1640}
1641
1642
1643/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
cd2c6191 1644/**
1da177e4
LT
1645 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1646 * @hd: Pointer to MPT_SCSI_HOST structure
1647 * @type: Task Management type
1544d677 1648 * @channel: channel number for task management
793955f5 1649 * @id: Logical Target ID for reset (if appropriate)
1da177e4
LT
1650 * @lun: Logical Unit for reset (if appropriate)
1651 * @ctx2abort: Context for the task to be aborted (if appropriate)
1544d677 1652 * @timeout: timeout for task management control
1da177e4
LT
1653 *
1654 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1655 * or a non-interrupt thread. In the former, must not call schedule().
1656 *
1657 * Not all fields are meaningfull for all task types.
1658 *
cd2c6191
EM
1659 * Returns 0 for SUCCESS, or FAILED.
1660 *
1661 **/
1da177e4 1662static int
793955f5 1663mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
1da177e4
LT
1664{
1665 MPT_FRAME_HDR *mf;
1666 SCSITaskMgmt_t *pScsiTm;
1667 int ii;
1668 int retval;
e80b002b 1669 MPT_ADAPTER *ioc = hd->ioc;
1da177e4
LT
1670
1671 /* Return Fail to calling function if no message frames available.
1672 */
e80b002b
EM
1673 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
1674 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1675 ioc->name));
c6678e0c 1676 return FAILED;
1da177e4 1677 }
e80b002b
EM
1678 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
1679 ioc->name, mf));
1da177e4
LT
1680
1681 /* Format the Request
1682 */
1683 pScsiTm = (SCSITaskMgmt_t *) mf;
793955f5 1684 pScsiTm->TargetID = id;
1da177e4
LT
1685 pScsiTm->Bus = channel;
1686 pScsiTm->ChainOffset = 0;
1687 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1688
1689 pScsiTm->Reserved = 0;
1690 pScsiTm->TaskType = type;
1691 pScsiTm->Reserved1 = 0;
1692 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1693 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1694
793955f5 1695 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
1da177e4
LT
1696
1697 for (ii=0; ii < 7; ii++)
1698 pScsiTm->Reserved2[ii] = 0;
1699
1700 pScsiTm->TaskMsgContext = ctx2abort;
1701
e80b002b
EM
1702 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1703 "type=%d\n", ioc->name, ctx2abort, type));
1da177e4 1704
6757d6b4 1705 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
1da177e4 1706
e80b002b
EM
1707 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1708 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1709 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
7a195f46 1710 else {
e80b002b 1711 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
7a195f46
PS
1712 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1713 if (retval) {
e80b002b
EM
1714 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
1715 " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
1716 ioc, mf, retval));
7a195f46
PS
1717 goto fail_out;
1718 }
1da177e4
LT
1719 }
1720
1721 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
e80b002b
EM
1722 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
1723 " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
1724 ioc, mf));
1725 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
1726 ioc->name));
1727 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1728 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
1729 ioc->name, retval));
cd2c6191 1730 goto fail_out;
1da177e4
LT
1731 }
1732
cd2c6191
EM
1733 /*
1734 * Handle success case, see if theres a non-zero ioc_status.
1735 */
1736 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1737 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1738 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1739 retval = 0;
1740 else
1741 retval = FAILED;
1742
1da177e4 1743 return retval;
cd2c6191
EM
1744
1745 fail_out:
1746
1747 /*
fc1323bb 1748 * Free task management mf, and corresponding tm flags
cd2c6191 1749 */
e80b002b 1750 mpt_free_msg_frame(ioc, mf);
cd2c6191
EM
1751 hd->tmPending = 0;
1752 hd->tmState = TM_STATE_NONE;
1753 return FAILED;
1da177e4
LT
1754}
1755
d66c7a0f
CH
1756static int
1757mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1758{
1759 switch (ioc->bus_type) {
1760 case FC:
1761 return 40;
1762 case SAS:
1763 return 10;
1764 case SPI:
1765 default:
1766 return 2;
1767 }
1768}
1769
1da177e4
LT
1770/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1771/**
1772 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1773 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1774 *
1775 * (linux scsi_host_template.eh_abort_handler routine)
1776 *
1777 * Returns SUCCESS or FAILED.
cd2c6191 1778 **/
0d0c7974 1779int
1da177e4
LT
1780mptscsih_abort(struct scsi_cmnd * SCpnt)
1781{
1782 MPT_SCSI_HOST *hd;
1da177e4
LT
1783 MPT_FRAME_HDR *mf;
1784 u32 ctx2abort;
1785 int scpnt_idx;
466544d8 1786 int retval;
958d4a32 1787 VirtDevice *vdevice;
3dc0b03f 1788 ulong sn = SCpnt->serial_number;
958d4a32 1789 MPT_ADAPTER *ioc;
1da177e4
LT
1790
1791 /* If we can't locate our host adapter structure, return FAILED status.
1792 */
e7eae9f6 1793 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
1da177e4
LT
1794 SCpnt->result = DID_RESET << 16;
1795 SCpnt->scsi_done(SCpnt);
29dd3609
EM
1796 printk(KERN_ERR MYNAM ": task abort: "
1797 "can't locate host! (sc=%p)\n", SCpnt);
1da177e4
LT
1798 return FAILED;
1799 }
1800
958d4a32
EM
1801 ioc = hd->ioc;
1802 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1803 ioc->name, SCpnt);
1804 scsi_print_command(SCpnt);
1805
1806 vdevice = SCpnt->device->hostdata;
1807 if (!vdevice || !vdevice->vtarget) {
29dd3609
EM
1808 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1809 "task abort: device has been deleted (sc=%p)\n",
1810 ioc->name, SCpnt));
958d4a32
EM
1811 SCpnt->result = DID_NO_CONNECT << 16;
1812 SCpnt->scsi_done(SCpnt);
1813 retval = 0;
1814 goto out;
1815 }
1816
cc78d30a
EM
1817 /* Task aborts are not supported for hidden raid components.
1818 */
1819 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
29dd3609
EM
1820 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1821 "task abort: hidden raid component (sc=%p)\n",
1822 ioc->name, SCpnt));
cc78d30a
EM
1823 SCpnt->result = DID_RESET << 16;
1824 retval = FAILED;
1825 goto out;
1826 }
1827
1da177e4
LT
1828 /* Find this command
1829 */
e8206381 1830 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
466544d8 1831 /* Cmd not found in ScsiLookup.
1da177e4
LT
1832 * Do OS callback.
1833 */
1834 SCpnt->result = DID_RESET << 16;
29dd3609 1835 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
958d4a32
EM
1836 "Command not in the active list! (sc=%p)\n", ioc->name,
1837 SCpnt));
1838 retval = 0;
1839 goto out;
1da177e4
LT
1840 }
1841
958d4a32
EM
1842 if (hd->resetPending) {
1843 retval = FAILED;
1844 goto out;
1845 }
65207fed
ME
1846
1847 if (hd->timeouts < -1)
1848 hd->timeouts++;
1849
1da177e4
LT
1850 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1851 * (the IO to be ABORT'd)
1852 *
1853 * NOTE: Since we do not byteswap MsgContext, we do not
1854 * swap it here either. It is an opaque cookie to
1855 * the controller, so it does not matter. -DaveM
1856 */
e80b002b 1857 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
1da177e4
LT
1858 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1859
1860 hd->abortSCpnt = SCpnt;
1861
466544d8 1862 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
958d4a32
EM
1863 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1864 ctx2abort, mptscsih_get_tm_timeout(ioc));
1da177e4 1865
e8206381 1866 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
cd2c6191 1867 SCpnt->serial_number == sn)
3dc0b03f 1868 retval = FAILED;
3dc0b03f 1869
958d4a32
EM
1870 out:
1871 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1872 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1da177e4 1873
466544d8
MED
1874 if (retval == 0)
1875 return SUCCESS;
cd2c6191
EM
1876 else
1877 return FAILED;
1da177e4
LT
1878}
1879
1880/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1881/**
1882 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1883 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1884 *
1885 * (linux scsi_host_template.eh_dev_reset_handler routine)
1886 *
1887 * Returns SUCCESS or FAILED.
cd2c6191 1888 **/
0d0c7974 1889int
1da177e4
LT
1890mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1891{
1892 MPT_SCSI_HOST *hd;
466544d8 1893 int retval;
958d4a32
EM
1894 VirtDevice *vdevice;
1895 MPT_ADAPTER *ioc;
1da177e4
LT
1896
1897 /* If we can't locate our host adapter structure, return FAILED status.
1898 */
e7eae9f6 1899 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
29dd3609
EM
1900 printk(KERN_ERR MYNAM ": target reset: "
1901 "Can't locate host! (sc=%p)\n", SCpnt);
1da177e4
LT
1902 return FAILED;
1903 }
1904
958d4a32
EM
1905 ioc = hd->ioc;
1906 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1907 ioc->name, SCpnt);
466544d8 1908 scsi_print_command(SCpnt);
1da177e4 1909
958d4a32
EM
1910 if (hd->resetPending) {
1911 retval = FAILED;
1912 goto out;
1913 }
1914
1915 vdevice = SCpnt->device->hostdata;
1916 if (!vdevice || !vdevice->vtarget) {
1917 retval = 0;
1918 goto out;
1919 }
1920
cc78d30a
EM
1921 /* Target reset to hidden raid component is not supported
1922 */
1923 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1924 retval = FAILED;
1925 goto out;
1926 }
1927
466544d8 1928 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
958d4a32
EM
1929 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1930 mptscsih_get_tm_timeout(ioc));
466544d8 1931
958d4a32
EM
1932 out:
1933 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1934 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
466544d8
MED
1935
1936 if (retval == 0)
1937 return SUCCESS;
cd2c6191
EM
1938 else
1939 return FAILED;
1da177e4
LT
1940}
1941
cd2c6191 1942
1da177e4
LT
1943/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1944/**
1945 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1946 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1947 *
1948 * (linux scsi_host_template.eh_bus_reset_handler routine)
1949 *
1950 * Returns SUCCESS or FAILED.
cd2c6191 1951 **/
0d0c7974 1952int
1da177e4
LT
1953mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1954{
1955 MPT_SCSI_HOST *hd;
466544d8 1956 int retval;
a69de507 1957 VirtDevice *vdevice;
958d4a32 1958 MPT_ADAPTER *ioc;
1da177e4
LT
1959
1960 /* If we can't locate our host adapter structure, return FAILED status.
1961 */
e7eae9f6 1962 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
29dd3609
EM
1963 printk(KERN_ERR MYNAM ": bus reset: "
1964 "Can't locate host! (sc=%p)\n", SCpnt);
1da177e4
LT
1965 return FAILED;
1966 }
1967
958d4a32
EM
1968 ioc = hd->ioc;
1969 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1970 ioc->name, SCpnt);
466544d8 1971 scsi_print_command(SCpnt);
1da177e4
LT
1972
1973 if (hd->timeouts < -1)
1974 hd->timeouts++;
1975
a69de507 1976 vdevice = SCpnt->device->hostdata;
466544d8 1977 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
a69de507 1978 vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
1da177e4 1979
958d4a32
EM
1980 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1981 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
466544d8
MED
1982
1983 if (retval == 0)
1984 return SUCCESS;
cd2c6191
EM
1985 else
1986 return FAILED;
1da177e4
LT
1987}
1988
1989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1990/**
d9489fb6 1991 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
1da177e4
LT
1992 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1993 *
1994 * (linux scsi_host_template.eh_host_reset_handler routine)
1995 *
1996 * Returns SUCCESS or FAILED.
1997 */
0d0c7974 1998int
1da177e4
LT
1999mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2000{
2001 MPT_SCSI_HOST * hd;
958d4a32
EM
2002 int retval;
2003 MPT_ADAPTER *ioc;
1da177e4
LT
2004
2005 /* If we can't locate the host to reset, then we failed. */
e7eae9f6 2006 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
29dd3609
EM
2007 printk(KERN_ERR MYNAM ": host reset: "
2008 "Can't locate host! (sc=%p)\n", SCpnt);
1da177e4
LT
2009 return FAILED;
2010 }
2011
958d4a32
EM
2012 ioc = hd->ioc;
2013 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2014 ioc->name, SCpnt);
1da177e4
LT
2015
2016 /* If our attempts to reset the host failed, then return a failed
2017 * status. The host will be taken off line by the SCSI mid-layer.
2018 */
e80b002b 2019 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
958d4a32 2020 retval = FAILED;
1da177e4
LT
2021 } else {
2022 /* Make sure TM pending is cleared and TM state is set to
2023 * NONE.
2024 */
958d4a32 2025 retval = 0;
1da177e4
LT
2026 hd->tmPending = 0;
2027 hd->tmState = TM_STATE_NONE;
2028 }
1da177e4 2029
958d4a32
EM
2030 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2031 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1da177e4 2032
958d4a32 2033 return retval;
1da177e4
LT
2034}
2035
2036/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2037/**
d9489fb6 2038 * mptscsih_tm_pending_wait - wait for pending task management request to complete
1da177e4
LT
2039 * @hd: Pointer to MPT host structure.
2040 *
2041 * Returns {SUCCESS,FAILED}.
2042 */
2043static int
2044mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2045{
2046 unsigned long flags;
2047 int loop_count = 4 * 10; /* Wait 10 seconds */
2048 int status = FAILED;
e80b002b 2049 MPT_ADAPTER *ioc = hd->ioc;
1da177e4
LT
2050
2051 do {
e80b002b 2052 spin_lock_irqsave(&ioc->FreeQlock, flags);
1da177e4
LT
2053 if (hd->tmState == TM_STATE_NONE) {
2054 hd->tmState = TM_STATE_IN_PROGRESS;
2055 hd->tmPending = 1;
e80b002b 2056 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
c6678e0c 2057 status = SUCCESS;
1da177e4
LT
2058 break;
2059 }
e80b002b 2060 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1da177e4
LT
2061 msleep(250);
2062 } while (--loop_count);
2063
2064 return status;
2065}
2066
2067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2068/**
2069 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2070 * @hd: Pointer to MPT host structure.
1544d677 2071 * @timeout: timeout value
1da177e4
LT
2072 *
2073 * Returns {SUCCESS,FAILED}.
2074 */
2075static int
2076mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2077{
2078 unsigned long flags;
2079 int loop_count = 4 * timeout;
2080 int status = FAILED;
e80b002b 2081 MPT_ADAPTER *ioc = hd->ioc;
1da177e4
LT
2082
2083 do {
e80b002b 2084 spin_lock_irqsave(&ioc->FreeQlock, flags);
1da177e4
LT
2085 if(hd->tmPending == 0) {
2086 status = SUCCESS;
e80b002b 2087 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1da177e4
LT
2088 break;
2089 }
e80b002b 2090 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
d6be06c8 2091 msleep(250);
1da177e4
LT
2092 } while (--loop_count);
2093
2094 return status;
2095}
2096
9f63bb73
ME
2097/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2098static void
2099mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2100{
2101 char *desc;
2102
2103 switch (response_code) {
2104 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2105 desc = "The task completed.";
2106 break;
2107 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2108 desc = "The IOC received an invalid frame status.";
2109 break;
2110 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2111 desc = "The task type is not supported.";
2112 break;
2113 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2114 desc = "The requested task failed.";
2115 break;
2116 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2117 desc = "The task completed successfully.";
2118 break;
2119 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2120 desc = "The LUN request is invalid.";
2121 break;
2122 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2123 desc = "The task is in the IOC queue and has not been sent to target.";
2124 break;
2125 default:
2126 desc = "unknown";
2127 break;
2128 }
2129 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2130 ioc->name, response_code, desc);
2131}
2132
1da177e4
LT
2133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2134/**
2135 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2136 * @ioc: Pointer to MPT_ADAPTER structure
2137 * @mf: Pointer to SCSI task mgmt request frame
2138 * @mr: Pointer to SCSI task mgmt reply frame
2139 *
2140 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2141 * of any SCSI task management request.
2142 * This routine is registered with the MPT (base) driver at driver
2143 * load/init time via the mpt_register() API call.
2144 *
2145 * Returns 1 indicating alloc'd request frame ptr should be freed.
cd2c6191 2146 **/
0d0c7974 2147int
1da177e4
LT
2148mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2149{
2150 SCSITaskMgmtReply_t *pScsiTmReply;
2151 SCSITaskMgmt_t *pScsiTmReq;
2152 MPT_SCSI_HOST *hd;
2153 unsigned long flags;
2154 u16 iocstatus;
2155 u8 tmType;
cd2c6191 2156 u32 termination_count;
1da177e4 2157
6757d6b4 2158 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
cd2c6191
EM
2159 ioc->name, mf, mr));
2160 if (!ioc->sh) {
6757d6b4 2161 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
cd2c6191 2162 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
1da177e4
LT
2163 return 1;
2164 }
2165
2166 if (mr == NULL) {
6757d6b4 2167 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
cd2c6191 2168 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
1da177e4 2169 return 1;
cd2c6191 2170 }
1da177e4 2171
e7eae9f6 2172 hd = shost_priv(ioc->sh);
cd2c6191
EM
2173 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2174 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2175 tmType = pScsiTmReq->TaskType;
2176 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2177 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2178
2179 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2180 pScsiTmReply->ResponseCode)
2181 mptscsih_taskmgmt_response_code(ioc,
2182 pScsiTmReply->ResponseCode);
6757d6b4
PS
2183 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
2184
2185#ifdef CONFIG_FUSION_LOGGING
2186 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2187 (ioc->debug_level & MPT_DEBUG_TM ))
2188 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2189 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
cadbd4a5 2190 "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
6757d6b4
PS
2191 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2192 le16_to_cpu(pScsiTmReply->IOCStatus),
2193 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2194 le32_to_cpu(pScsiTmReply->TerminationCount));
cd2c6191
EM
2195#endif
2196 if (!iocstatus) {
6757d6b4 2197 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
cd2c6191
EM
2198 hd->abortSCpnt = NULL;
2199 goto out;
2200 }
1da177e4 2201
cd2c6191 2202 /* Error? (anything non-zero?) */
9f63bb73 2203
cd2c6191
EM
2204 /* clear flags and continue.
2205 */
2206 switch (tmType) {
1da177e4 2207
cd2c6191
EM
2208 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2209 if (termination_count == 1)
2210 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2211 hd->abortSCpnt = NULL;
2212 break;
1da177e4 2213
cd2c6191 2214 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
1da177e4 2215
cd2c6191
EM
2216 /* If an internal command is present
2217 * or the TM failed - reload the FW.
2218 * FC FW may respond FAILED to an ABORT
2219 */
2220 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2221 hd->cmdPtr)
2222 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
29dd3609 2223 printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
cd2c6191 2224 break;
1da177e4 2225
cd2c6191
EM
2226 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2227 default:
2228 break;
1da177e4
LT
2229 }
2230
cd2c6191 2231 out:
1da177e4
LT
2232 spin_lock_irqsave(&ioc->FreeQlock, flags);
2233 hd->tmPending = 0;
1da177e4 2234 hd->tmState = TM_STATE_NONE;
cd2c6191
EM
2235 hd->tm_iocstatus = iocstatus;
2236 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1da177e4
LT
2237
2238 return 1;
2239}
2240
2241/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2242/*
2243 * This is anyones guess quite frankly.
2244 */
0d0c7974 2245int
1da177e4
LT
2246mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2247 sector_t capacity, int geom[])
2248{
2249 int heads;
2250 int sectors;
2251 sector_t cylinders;
2252 ulong dummy;
2253
2254 heads = 64;
2255 sectors = 32;
2256
2257 dummy = heads * sectors;
2258 cylinders = capacity;
2259 sector_div(cylinders,dummy);
2260
2261 /*
2262 * Handle extended translation size for logical drives
2263 * > 1Gb
2264 */
2265 if ((ulong)capacity >= 0x200000) {
2266 heads = 255;
2267 sectors = 63;
2268 dummy = heads * sectors;
2269 cylinders = capacity;
2270 sector_div(cylinders,dummy);
2271 }
2272
2273 /* return result */
2274 geom[0] = heads;
2275 geom[1] = sectors;
2276 geom[2] = cylinders;
2277
1da177e4
LT
2278 return 0;
2279}
2280
f44e5461
ME
2281/* Search IOC page 3 to determine if this is hidden physical disk
2282 *
2283 */
2284int
793955f5 2285mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
f44e5461 2286{
b506ade9 2287 struct inactive_raid_component_info *component_info;
f44e5461 2288 int i;
793955f5 2289 int rc = 0;
f44e5461 2290
793955f5
EM
2291 if (!ioc->raid_data.pIocPg3)
2292 goto out;
f44e5461 2293 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
793955f5
EM
2294 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2295 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2296 rc = 1;
2297 goto out;
2298 }
c92f222e
JB
2299 }
2300
b506ade9
EM
2301 /*
2302 * Check inactive list for matching phys disks
2303 */
2304 if (list_empty(&ioc->raid_data.inactive_list))
2305 goto out;
2306
ed5f606f 2307 mutex_lock(&ioc->raid_data.inactive_list_mutex);
b506ade9
EM
2308 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2309 list) {
2310 if ((component_info->d.PhysDiskID == id) &&
2311 (component_info->d.PhysDiskBus == channel))
2312 rc = 1;
2313 }
ed5f606f 2314 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
b506ade9 2315
793955f5
EM
2316 out:
2317 return rc;
c7c82987 2318}
793955f5 2319EXPORT_SYMBOL(mptscsih_is_phys_disk);
c7c82987 2320
793955f5
EM
2321u8
2322mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
1da177e4 2323{
b506ade9 2324 struct inactive_raid_component_info *component_info;
793955f5
EM
2325 int i;
2326 int rc = -ENXIO;
c92f222e 2327
793955f5
EM
2328 if (!ioc->raid_data.pIocPg3)
2329 goto out;
2330 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2331 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2332 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2333 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2334 goto out;
1da177e4 2335 }
1da177e4 2336 }
1da177e4 2337
b506ade9
EM
2338 /*
2339 * Check inactive list for matching phys disks
2340 */
2341 if (list_empty(&ioc->raid_data.inactive_list))
2342 goto out;
2343
ed5f606f 2344 mutex_lock(&ioc->raid_data.inactive_list_mutex);
b506ade9
EM
2345 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2346 list) {
2347 if ((component_info->d.PhysDiskID == id) &&
2348 (component_info->d.PhysDiskBus == channel))
2349 rc = component_info->d.PhysDiskNum;
2350 }
ed5f606f 2351 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
b506ade9 2352
793955f5
EM
2353 out:
2354 return rc;
c7c82987 2355}
793955f5 2356EXPORT_SYMBOL(mptscsih_raid_id_to_num);
1da177e4 2357
c7c82987
MED
2358/*
2359 * OS entry point to allow for host driver to free allocated memory
2360 * Called if no device present or device being unloaded
2361 */
2362void
2363mptscsih_slave_destroy(struct scsi_device *sdev)
2364{
2365 struct Scsi_Host *host = sdev->host;
e7eae9f6 2366 MPT_SCSI_HOST *hd = shost_priv(host);
c7c82987
MED
2367 VirtTarget *vtarget;
2368 VirtDevice *vdevice;
2369 struct scsi_target *starget;
2370
2371 starget = scsi_target(sdev);
2372 vtarget = starget->hostdata;
2373 vdevice = sdev->hostdata;
2374
2375 mptscsih_search_running_cmds(hd, vdevice);
c7c82987 2376 vtarget->num_luns--;
c7c82987
MED
2377 mptscsih_synchronize_cache(hd, vdevice);
2378 kfree(vdevice);
2379 sdev->hostdata = NULL;
1da177e4
LT
2380}
2381
6e3815ba
MED
2382/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2383/*
2384 * mptscsih_change_queue_depth - This function will set a devices queue depth
2385 * @sdev: per scsi_device pointer
2386 * @qdepth: requested queue depth
2387 *
2388 * Adding support for new 'change_queue_depth' api.
2389*/
2390int
2391mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
1da177e4 2392{
e7eae9f6 2393 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
c7c82987
MED
2394 VirtTarget *vtarget;
2395 struct scsi_target *starget;
2396 int max_depth;
2397 int tagged;
e80b002b 2398 MPT_ADAPTER *ioc = hd->ioc;
1da177e4 2399
c7c82987
MED
2400 starget = scsi_target(sdev);
2401 vtarget = starget->hostdata;
6e3815ba 2402
e80b002b 2403 if (ioc->bus_type == SPI) {
c92f222e 2404 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
1da177e4 2405 max_depth = 1;
c92f222e
JB
2406 else if (sdev->type == TYPE_DISK &&
2407 vtarget->minSyncFactor <= MPT_ULTRA160)
2408 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2409 else
2410 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
1da177e4
LT
2411 } else
2412 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2413
2414 if (qdepth > max_depth)
2415 qdepth = max_depth;
2416 if (qdepth == 1)
2417 tagged = 0;
2418 else
2419 tagged = MSG_SIMPLE_TAG;
2420
6e3815ba
MED
2421 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2422 return sdev->queue_depth;
1da177e4
LT
2423}
2424
1da177e4
LT
2425/*
2426 * OS entry point to adjust the queue_depths on a per-device basis.
2427 * Called once per device the bus scan. Use it to force the queue_depth
2428 * member to 1 if a device does not support Q tags.
2429 * Return non-zero if fails.
2430 */
0d0c7974 2431int
c7c82987 2432mptscsih_slave_configure(struct scsi_device *sdev)
1da177e4 2433{
c7c82987
MED
2434 struct Scsi_Host *sh = sdev->host;
2435 VirtTarget *vtarget;
2436 VirtDevice *vdevice;
2437 struct scsi_target *starget;
e7eae9f6 2438 MPT_SCSI_HOST *hd = shost_priv(sh);
e80b002b 2439 MPT_ADAPTER *ioc = hd->ioc;
1da177e4 2440
c7c82987
MED
2441 starget = scsi_target(sdev);
2442 vtarget = starget->hostdata;
2443 vdevice = sdev->hostdata;
1da177e4 2444
e80b002b 2445 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
793955f5 2446 "device @ %p, channel=%d, id=%d, lun=%d\n",
e80b002b
EM
2447 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2448 if (ioc->bus_type == SPI)
2449 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
c7c82987 2450 "sdtr %d wdtr %d ppr %d inq length=%d\n",
e80b002b 2451 ioc->name, sdev->sdtr, sdev->wdtr,
c7c82987
MED
2452 sdev->ppr, sdev->inquiry_len));
2453
793955f5 2454 vdevice->configured_lun = 1;
c7c82987 2455 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
1da177e4 2456
e80b002b 2457 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1da177e4 2458 "Queue depth=%d, tflags=%x\n",
e80b002b 2459 ioc->name, sdev->queue_depth, vtarget->tflags));
1da177e4 2460
e80b002b
EM
2461 if (ioc->bus_type == SPI)
2462 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
c7c82987 2463 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
e80b002b 2464 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
c7c82987 2465 vtarget->minSyncFactor));
1da177e4 2466
e80b002b 2467 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1da177e4 2468 "tagged %d, simple %d, ordered %d\n",
e80b002b 2469 ioc->name,sdev->tagged_supported, sdev->simple_tags,
c7c82987 2470 sdev->ordered_tags));
1da177e4
LT
2471
2472 return 0;
2473}
2474
1da177e4
LT
2475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2476/*
2477 * Private routines...
2478 */
2479
2480/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2481/* Utility function to copy sense data from the scsi_cmnd buffer
2482 * to the FC and SCSI target structures.
2483 *
2484 */
2485static void
0d0c7974 2486mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
1da177e4 2487{
a69de507 2488 VirtDevice *vdevice;
1da177e4
LT
2489 SCSIIORequest_t *pReq;
2490 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
e80b002b 2491 MPT_ADAPTER *ioc = hd->ioc;
1da177e4
LT
2492
2493 /* Get target structure
2494 */
2495 pReq = (SCSIIORequest_t *) mf;
a69de507 2496 vdevice = sc->device->hostdata;
1da177e4
LT
2497
2498 if (sense_count) {
2499 u8 *sense_data;
2500 int req_index;
2501
2502 /* Copy the sense received into the scsi command block. */
2503 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
e80b002b 2504 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
1da177e4
LT
2505 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2506
2507 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2508 */
e80b002b 2509 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
a69de507 2510 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
1da177e4 2511 int idx;
1da177e4 2512
5b5ef4f6 2513 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
1da177e4
LT
2514 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2515 ioc->events[idx].eventContext = ioc->eventContext;
2516
3d9780b9
DJ
2517 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2518 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2519 (sc->device->channel << 8) | sc->device->id;
1da177e4 2520
3d9780b9 2521 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
1da177e4
LT
2522
2523 ioc->eventContext++;
e80b002b 2524 if (ioc->pcidev->vendor ==
786899b0 2525 PCI_VENDOR_ID_IBM) {
e80b002b 2526 mptscsih_issue_sep_command(ioc,
a69de507
EM
2527 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2528 vdevice->vtarget->tflags |=
786899b0
EM
2529 MPT_TARGET_FLAGS_LED_ON;
2530 }
1da177e4
LT
2531 }
2532 }
2533 } else {
e80b002b
EM
2534 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2535 ioc->name));
1da177e4
LT
2536 }
2537}
2538
e8206381
EM
2539/**
2540 * mptscsih_get_scsi_lookup
e8206381
EM
2541 * @ioc: Pointer to MPT_ADAPTER structure
2542 * @i: index into the array
2543 *
7105a387 2544 * retrieves scmd entry from ScsiLookup[] array list
e8206381 2545 *
7105a387 2546 * Returns the scsi_cmd pointer
e8206381
EM
2547 **/
2548static struct scsi_cmnd *
2549mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
1da177e4 2550{
e8206381
EM
2551 unsigned long flags;
2552 struct scsi_cmnd *scmd;
2553
2554 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2555 scmd = ioc->ScsiLookup[i];
2556 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2557
2558 return scmd;
2559}
2560
2561/**
2562 * mptscsih_getclear_scsi_lookup
e8206381
EM
2563 * @ioc: Pointer to MPT_ADAPTER structure
2564 * @i: index into the array
2565 *
7105a387 2566 * retrieves and clears scmd entry from ScsiLookup[] array list
e8206381 2567 *
7105a387 2568 * Returns the scsi_cmd pointer
e8206381
EM
2569 **/
2570static struct scsi_cmnd *
2571mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2572{
2573 unsigned long flags;
2574 struct scsi_cmnd *scmd;
2575
2576 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2577 scmd = ioc->ScsiLookup[i];
2578 ioc->ScsiLookup[i] = NULL;
2579 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2580
2581 return scmd;
2582}
2583
2584/**
2585 * mptscsih_set_scsi_lookup
2586 *
2587 * writes a scmd entry into the ScsiLookup[] array list
2588 *
2589 * @ioc: Pointer to MPT_ADAPTER structure
2590 * @i: index into the array
2591 * @scmd: scsi_cmnd pointer
2592 *
2593 **/
2594static void
2595mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2596{
2597 unsigned long flags;
1da177e4 2598
e8206381
EM
2599 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2600 ioc->ScsiLookup[i] = scmd;
2601 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2602}
2603
2604/**
23f9b75e 2605 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
e8206381 2606 * @ioc: Pointer to MPT_ADAPTER structure
23f9b75e
RD
2607 * @sc: scsi_cmnd pointer
2608 */
e8206381
EM
2609static int
2610SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2611{
2612 unsigned long flags;
2613 int i, index=-1;
1da177e4 2614
e8206381
EM
2615 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2616 for (i = 0; i < ioc->req_depth; i++) {
2617 if (ioc->ScsiLookup[i] == sc) {
2618 index = i;
2619 goto out;
1da177e4
LT
2620 }
2621 }
2622
e8206381
EM
2623 out:
2624 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2625 return index;
1da177e4
LT
2626}
2627
2628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
0d0c7974 2629int
1da177e4
LT
2630mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2631{
2632 MPT_SCSI_HOST *hd;
2633 unsigned long flags;
2634
29dd3609
EM
2635 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2636 ": IOC %s_reset routed to SCSI host driver!\n",
2637 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2638 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1da177e4
LT
2639
2640 /* If a FW reload request arrives after base installed but
2641 * before all scsi hosts have been attached, then an alt_ioc
2642 * may have a NULL sh pointer.
2643 */
e7eae9f6 2644 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
1da177e4
LT
2645 return 0;
2646 else
e7eae9f6 2647 hd = shost_priv(ioc->sh);
1da177e4
LT
2648
2649 if (reset_phase == MPT_IOC_SETUP_RESET) {
6757d6b4 2650 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
1da177e4
LT
2651
2652 /* Clean Up:
2653 * 1. Set Hard Reset Pending Flag
2654 * All new commands go to doneQ
2655 */
2656 hd->resetPending = 1;
2657
2658 } else if (reset_phase == MPT_IOC_PRE_RESET) {
6757d6b4 2659 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
1da177e4
LT
2660
2661 /* 2. Flush running commands
2662 * Clean ScsiLookup (and associated memory)
2663 * AND clean mytaskQ
2664 */
2665
2666 /* 2b. Reply to OS all known outstanding I/O commands.
2667 */
2668 mptscsih_flush_running_cmds(hd);
2669
2670 /* 2c. If there was an internal command that
2671 * has not completed, configuration or io request,
2672 * free these resources.
2673 */
2674 if (hd->cmdPtr) {
2675 del_timer(&hd->timer);
2676 mpt_free_msg_frame(ioc, hd->cmdPtr);
2677 }
2678
6757d6b4 2679 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
1da177e4
LT
2680
2681 } else {
6757d6b4 2682 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
1da177e4
LT
2683
2684 /* Once a FW reload begins, all new OS commands are
2685 * redirected to the doneQ w/ a reset status.
2686 * Init all control structures.
2687 */
2688
1da177e4
LT
2689 /* 2. Chain Buffer initialization
2690 */
2691
a9b2937a 2692 /* 4. Renegotiate to all devices, if SPI
1da177e4 2693 */
1da177e4
LT
2694
2695 /* 5. Enable new commands to be posted
2696 */
2697 spin_lock_irqsave(&ioc->FreeQlock, flags);
2698 hd->tmPending = 0;
2699 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2700 hd->resetPending = 0;
2701 hd->tmState = TM_STATE_NONE;
2702
2703 /* 6. If there was an internal command,
2704 * wake this process up.
2705 */
2706 if (hd->cmdPtr) {
2707 /*
2708 * Wake up the original calling thread
2709 */
2710 hd->pLocal = &hd->localReply;
2711 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
0d0c7974
MED
2712 hd->scandv_wait_done = 1;
2713 wake_up(&hd->scandv_waitq);
1da177e4
LT
2714 hd->cmdPtr = NULL;
2715 }
2716
6757d6b4 2717 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
1da177e4
LT
2718
2719 }
2720
2721 return 1; /* currently means nothing really */
2722}
2723
2724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
0d0c7974 2725int
1da177e4
LT
2726mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2727{
2728 MPT_SCSI_HOST *hd;
2729 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2730
6757d6b4 2731 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
1da177e4
LT
2732 ioc->name, event));
2733
466544d8 2734 if (ioc->sh == NULL ||
e7eae9f6 2735 ((hd = shost_priv(ioc->sh)) == NULL))
466544d8
MED
2736 return 1;
2737
1da177e4
LT
2738 switch (event) {
2739 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2740 /* FIXME! */
2741 break;
2742 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2743 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
a9b2937a 2744 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
466544d8 2745 hd->soft_resets++;
1da177e4
LT
2746 break;
2747 case MPI_EVENT_LOGOUT: /* 09 */
2748 /* FIXME! */
2749 break;
2750
05e8ec17 2751 case MPI_EVENT_RESCAN: /* 06 */
05e8ec17
MR
2752 break;
2753
1da177e4
LT
2754 /*
2755 * CHECKME! Don't think we need to do
2756 * anything for these, but...
2757 */
1da177e4
LT
2758 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2759 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2760 /*
2761 * CHECKME! Falling thru...
2762 */
2763 break;
2764
2765 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
466544d8 2766 break;
1da177e4 2767
1da177e4
LT
2768 case MPI_EVENT_NONE: /* 00 */
2769 case MPI_EVENT_LOG_DATA: /* 01 */
2770 case MPI_EVENT_STATE_CHANGE: /* 02 */
2771 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2772 default:
29dd3609
EM
2773 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
2774 ioc->name, event));
1da177e4
LT
2775 break;
2776 }
2777
2778 return 1; /* currently means nothing really */
2779}
2780
1da177e4
LT
2781/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2782/*
2783 * Bus Scan and Domain Validation functionality ...
2784 */
2785
2786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2787/*
2788 * mptscsih_scandv_complete - Scan and DV callback routine registered
2789 * to Fustion MPT (base) driver.
2790 *
2791 * @ioc: Pointer to MPT_ADAPTER structure
2792 * @mf: Pointer to original MPT request frame
2793 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2794 *
2795 * This routine is called from mpt.c::mpt_interrupt() at the completion
2796 * of any SCSI IO request.
2797 * This routine is registered with the Fusion MPT (base) driver at driver
2798 * load/init time via the mpt_register() API call.
2799 *
2800 * Returns 1 indicating alloc'd request frame ptr should be freed.
2801 *
2802 * Remark: Sets a completion code and (possibly) saves sense data
2803 * in the IOC member localReply structure.
2804 * Used ONLY for DV and other internal commands.
2805 */
0d0c7974 2806int
1da177e4
LT
2807mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2808{
2809 MPT_SCSI_HOST *hd;
2810 SCSIIORequest_t *pReq;
2811 int completionCode;
2812 u16 req_idx;
2813
e7eae9f6 2814 hd = shost_priv(ioc->sh);
0d0c7974 2815
1da177e4
LT
2816 if ((mf == NULL) ||
2817 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2818 printk(MYIOC_s_ERR_FMT
2819 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2820 ioc->name, mf?"BAD":"NULL", (void *) mf);
2821 goto wakeup;
2822 }
2823
1da177e4
LT
2824 del_timer(&hd->timer);
2825 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
e8206381 2826 mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
1da177e4
LT
2827 pReq = (SCSIIORequest_t *) mf;
2828
2829 if (mf != hd->cmdPtr) {
2830 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
e80b002b 2831 ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
1da177e4
LT
2832 }
2833 hd->cmdPtr = NULL;
2834
6757d6b4 2835 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
e80b002b 2836 ioc->name, mf, mr, req_idx));
1da177e4
LT
2837
2838 hd->pLocal = &hd->localReply;
2839 hd->pLocal->scsiStatus = 0;
2840
2841 /* If target struct exists, clear sense valid flag.
2842 */
2843 if (mr == NULL) {
2844 completionCode = MPT_SCANDV_GOOD;
2845 } else {
2846 SCSIIOReply_t *pReply;
2847 u16 status;
2848 u8 scsi_status;
2849
2850 pReply = (SCSIIOReply_t *) mr;
2851
2852 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2853 scsi_status = pReply->SCSIStatus;
2854
1da177e4
LT
2855
2856 switch(status) {
2857
2858 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2859 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2860 break;
2861
2862 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2863 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2864 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2865 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2866 completionCode = MPT_SCANDV_DID_RESET;
2867 break;
2868
2869 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2870 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2871 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2872 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2873 ConfigReply_t *pr = (ConfigReply_t *)mr;
2874 completionCode = MPT_SCANDV_GOOD;
2875 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2876 hd->pLocal->header.PageLength = pr->Header.PageLength;
2877 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2878 hd->pLocal->header.PageType = pr->Header.PageType;
2879
2880 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2881 /* If the RAID Volume request is successful,
2882 * return GOOD, else indicate that
2883 * some type of error occurred.
2884 */
2885 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
637fa99b 2886 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
1da177e4
LT
2887 completionCode = MPT_SCANDV_GOOD;
2888 else
2889 completionCode = MPT_SCANDV_SOME_ERROR;
c92f222e 2890 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
1da177e4
LT
2891
2892 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2893 u8 *sense_data;
2894 int sz;
2895
2896 /* save sense data in global structure
2897 */
2898 completionCode = MPT_SCANDV_SENSE;
2899 hd->pLocal->scsiStatus = scsi_status;
e80b002b 2900 sense_data = ((u8 *)ioc->sense_buf_pool +
1da177e4
LT
2901 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2902
2903 sz = min_t(int, pReq->SenseBufferLength,
2904 SCSI_STD_SENSE_BYTES);
2905 memcpy(hd->pLocal->sense, sense_data, sz);
2906
29dd3609
EM
2907 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
2908 ioc->name, sense_data));
1da177e4
LT
2909 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2910 if (pReq->CDB[0] == INQUIRY)
2911 completionCode = MPT_SCANDV_ISSUE_SENSE;
2912 else
2913 completionCode = MPT_SCANDV_DID_RESET;
2914 }
2915 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2916 completionCode = MPT_SCANDV_DID_RESET;
2917 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2918 completionCode = MPT_SCANDV_DID_RESET;
2919 else {
2920 completionCode = MPT_SCANDV_GOOD;
2921 hd->pLocal->scsiStatus = scsi_status;
2922 }
2923 break;
2924
2925 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2926 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2927 completionCode = MPT_SCANDV_DID_RESET;
2928 else
2929 completionCode = MPT_SCANDV_SOME_ERROR;
2930 break;
2931
2932 default:
2933 completionCode = MPT_SCANDV_SOME_ERROR;
2934 break;
2935
2936 } /* switch(status) */
2937
1da177e4
LT
2938 } /* end of address reply case */
2939
2940 hd->pLocal->completion = completionCode;
2941
2942 /* MF and RF are freed in mpt_interrupt
2943 */
2944wakeup:
2945 /* Free Chain buffers (will never chain) in scan or dv */
2946 //mptscsih_freeChainBuffers(ioc, req_idx);
2947
2948 /*
2949 * Wake up the original calling thread
2950 */
0d0c7974
MED
2951 hd->scandv_wait_done = 1;
2952 wake_up(&hd->scandv_waitq);
1da177e4
LT
2953
2954 return 1;
2955}
2956
2957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2958/* mptscsih_timer_expired - Call back for timer process.
2959 * Used only for dv functionality.
2960 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2961 *
2962 */
0d0c7974
MED
2963void
2964mptscsih_timer_expired(unsigned long data)
1da177e4
LT
2965{
2966 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
e80b002b 2967 MPT_ADAPTER *ioc = hd->ioc;
1da177e4 2968
e80b002b 2969 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
1da177e4
LT
2970
2971 if (hd->cmdPtr) {
2972 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2973
2974 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2975 /* Desire to issue a task management request here.
2976 * TM requests MUST be single threaded.
2977 * If old eh code and no TM current, issue request.
2978 * If new eh code, do nothing. Wait for OS cmd timeout
2979 * for bus reset.
2980 */
1da177e4
LT
2981 } else {
2982 /* Perform a FW reload */
e80b002b
EM
2983 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2984 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
1da177e4
LT
2985 }
2986 }
2987 } else {
2988 /* This should NEVER happen */
e80b002b 2989 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
1da177e4
LT
2990 }
2991
2992 /* No more processing.
2993 * TM call will generate an interrupt for SCSI TM Management.
2994 * The FW will reply to all outstanding commands, callback will finish cleanup.
2995 * Hard reset clean-up will free all resources.
2996 */
e80b002b 2997 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
1da177e4
LT
2998
2999 return;
3000}
3001
1da177e4
LT
3002
3003/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3004/**
3005 * mptscsih_do_cmd - Do internal command.
3006 * @hd: MPT_SCSI_HOST pointer
3007 * @io: INTERNAL_CMD pointer.
3008 *
3009 * Issue the specified internally generated command and do command
3010 * specific cleanup. For bus scan / DV only.
3011 * NOTES: If command is Inquiry and status is good,
3012 * initialize a target structure, save the data
3013 *
3014 * Remark: Single threaded access only.
3015 *
3016 * Return:
3017 * < 0 if an illegal command or no resources
3018 *
3019 * 0 if good
3020 *
3021 * > 0 if command complete but some type of completion error.
3022 */
3023static int
3024mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3025{
3026 MPT_FRAME_HDR *mf;
3027 SCSIIORequest_t *pScsiReq;
3028 SCSIIORequest_t ReqCopy;
3029 int my_idx, ii, dir;
3030 int rc, cmdTimeout;
3031 int in_isr;
3032 char cmdLen;
3033 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3034 char cmd = io->cmd;
e80b002b 3035 MPT_ADAPTER *ioc = hd->ioc;
1da177e4
LT
3036
3037 in_isr = in_interrupt();
3038 if (in_isr) {
e80b002b
EM
3039 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3040 ioc->name));
1da177e4
LT
3041 return -EPERM;
3042 }
3043
3044
3045 /* Set command specific information
3046 */
3047 switch (cmd) {
3048 case INQUIRY:
3049 cmdLen = 6;
3050 dir = MPI_SCSIIO_CONTROL_READ;
3051 CDB[0] = cmd;
3052 CDB[4] = io->size;
3053 cmdTimeout = 10;
3054 break;
3055
3056 case TEST_UNIT_READY:
3057 cmdLen = 6;
3058 dir = MPI_SCSIIO_CONTROL_READ;
3059 cmdTimeout = 10;
3060 break;
3061
3062 case START_STOP:
3063 cmdLen = 6;
3064 dir = MPI_SCSIIO_CONTROL_READ;
3065 CDB[0] = cmd;
3066 CDB[4] = 1; /*Spin up the disk */
3067 cmdTimeout = 15;
3068 break;
3069
3070 case REQUEST_SENSE:
3071 cmdLen = 6;
3072 CDB[0] = cmd;
3073 CDB[4] = io->size;
3074 dir = MPI_SCSIIO_CONTROL_READ;
3075 cmdTimeout = 10;
3076 break;
3077
3078 case READ_BUFFER:
3079 cmdLen = 10;
3080 dir = MPI_SCSIIO_CONTROL_READ;
3081 CDB[0] = cmd;
3082 if (io->flags & MPT_ICFLAG_ECHO) {
3083 CDB[1] = 0x0A;
3084 } else {
3085 CDB[1] = 0x02;
3086 }
3087
3088 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3089 CDB[1] |= 0x01;
3090 }
3091 CDB[6] = (io->size >> 16) & 0xFF;
3092 CDB[7] = (io->size >> 8) & 0xFF;
3093 CDB[8] = io->size & 0xFF;
3094 cmdTimeout = 10;
3095 break;
3096
3097 case WRITE_BUFFER:
3098 cmdLen = 10;
3099 dir = MPI_SCSIIO_CONTROL_WRITE;
3100 CDB[0] = cmd;
3101 if (io->flags & MPT_ICFLAG_ECHO) {
3102 CDB[1] = 0x0A;
3103 } else {
3104 CDB[1] = 0x02;
3105 }
3106 CDB[6] = (io->size >> 16) & 0xFF;
3107 CDB[7] = (io->size >> 8) & 0xFF;
3108 CDB[8] = io->size & 0xFF;
3109 cmdTimeout = 10;
3110 break;
3111
3112 case RESERVE:
3113 cmdLen = 6;
3114 dir = MPI_SCSIIO_CONTROL_READ;
3115 CDB[0] = cmd;
3116 cmdTimeout = 10;
3117 break;
3118
3119 case RELEASE:
3120 cmdLen = 6;
3121 dir = MPI_SCSIIO_CONTROL_READ;
3122 CDB[0] = cmd;
3123 cmdTimeout = 10;
3124 break;
3125
3126 case SYNCHRONIZE_CACHE:
3127 cmdLen = 10;
3128 dir = MPI_SCSIIO_CONTROL_READ;
3129 CDB[0] = cmd;
3130// CDB[1] = 0x02; /* set immediate bit */
3131 cmdTimeout = 10;
3132 break;
3133
3134 default:
3135 /* Error Case */
3136 return -EFAULT;
3137 }
3138
3139 /* Get and Populate a free Frame
3140 */
e80b002b
EM
3141 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
3142 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
3143 ioc->name));
1da177e4
LT
3144 return -EBUSY;
3145 }
3146
3147 pScsiReq = (SCSIIORequest_t *) mf;
3148
3149 /* Get the request index */
3150 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3151 ADD_INDEX_LOG(my_idx); /* for debug */
3152
3153 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3154 pScsiReq->TargetID = io->physDiskNum;
3155 pScsiReq->Bus = 0;
3156 pScsiReq->ChainOffset = 0;
3157 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3158 } else {
3159 pScsiReq->TargetID = io->id;
793955f5 3160 pScsiReq->Bus = io->channel;
1da177e4
LT
3161 pScsiReq->ChainOffset = 0;
3162 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3163 }
3164
3165 pScsiReq->CDBLength = cmdLen;
3166 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3167
3168 pScsiReq->Reserved = 0;
3169
3170 pScsiReq->MsgFlags = mpt_msg_flags();
3171 /* MsgContext set in mpt_get_msg_fram call */
3172
793955f5 3173 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
1da177e4
LT
3174
3175 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3176 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3177 else
3178 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3179
3180 if (cmd == REQUEST_SENSE) {
3181 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
e80b002b
EM
3182 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
3183 ioc->name, cmd));
1da177e4
LT
3184 }
3185
3186 for (ii=0; ii < 16; ii++)
3187 pScsiReq->CDB[ii] = CDB[ii];
3188
3189 pScsiReq->DataLength = cpu_to_le32(io->size);
e80b002b 3190 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
1da177e4
LT
3191 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3192
e80b002b
EM
3193 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3194 ioc->name, cmd, io->channel, io->id, io->lun));
1da177e4
LT
3195
3196 if (dir == MPI_SCSIIO_CONTROL_READ) {
3197 mpt_add_sge((char *) &pScsiReq->SGL,
3198 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3199 io->data_dma);
3200 } else {
3201 mpt_add_sge((char *) &pScsiReq->SGL,
3202 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3203 io->data_dma);
3204 }
3205
3206 /* The ISR will free the request frame, but we need
3207 * the information to initialize the target. Duplicate.
3208 */
3209 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3210
3211 /* Issue this command after:
3212 * finish init
3213 * add timer
3214 * Wait until the reply has been received
3215 * ScsiScanDvCtx callback function will
3216 * set hd->pLocal;
3217 * set scandv_wait_done and call wake_up
3218 */
3219 hd->pLocal = NULL;
3220 hd->timer.expires = jiffies + HZ*cmdTimeout;
0d0c7974 3221 hd->scandv_wait_done = 0;
1da177e4
LT
3222
3223 /* Save cmd pointer, for resource free if timeout or
3224 * FW reload occurs
3225 */
3226 hd->cmdPtr = mf;
3227
3228 add_timer(&hd->timer);
e80b002b 3229 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
0d0c7974 3230 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
1da177e4
LT
3231
3232 if (hd->pLocal) {
3233 rc = hd->pLocal->completion;
3234 hd->pLocal->skip = 0;
3235
3236 /* Always set fatal error codes in some cases.
3237 */
3238 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3239 rc = -ENXIO;
3240 else if (rc == MPT_SCANDV_SOME_ERROR)
3241 rc = -rc;
3242 } else {
3243 rc = -EFAULT;
3244 /* This should never happen. */
e80b002b
EM
3245 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
3246 ioc->name));
1da177e4
LT
3247 }
3248
3249 return rc;
3250}
3251
c7c82987
MED
3252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3253/**
3254 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3255 * @hd: Pointer to a SCSI HOST structure
d9489fb6 3256 * @vdevice: virtual target device
c7c82987
MED
3257 *
3258 * Uses the ISR, but with special processing.
3259 * MUST be single-threaded.
3260 *
3261 */
3262static void
3263mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3264{
3265 INTERNAL_CMD iocmd;
1da177e4 3266
cc78d30a
EM
3267 /* Ignore hidden raid components, this is handled when the command
3268 * is sent to the volume
3269 */
3270 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3271 return;
3272
3273 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3274 !vdevice->configured_lun)
3275 return;
3276
c7c82987
MED
3277 /* Following parameters will not change
3278 * in this routine.
3279 */
3280 iocmd.cmd = SYNCHRONIZE_CACHE;
3281 iocmd.flags = 0;
3282 iocmd.physDiskNum = -1;
3283 iocmd.data = NULL;
3284 iocmd.data_dma = -1;
3285 iocmd.size = 0;
3286 iocmd.rsvd = iocmd.rsvd2 = 0;
793955f5
EM
3287 iocmd.channel = vdevice->vtarget->channel;
3288 iocmd.id = vdevice->vtarget->id;
3289 iocmd.lun = vdevice->lun;
1da177e4 3290
cc78d30a 3291 mptscsih_do_cmd(hd, &iocmd);
1da177e4
LT
3292}
3293
edb9068d 3294static ssize_t
ee959b00
TJ
3295mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3296 char *buf)
edb9068d 3297{
ee959b00 3298 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3299 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3300 MPT_ADAPTER *ioc = hd->ioc;
3301
3302 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3303 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3304 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3305 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3306 ioc->facts.FWVersion.Word & 0x000000FF);
3307}
ee959b00 3308static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
edb9068d
PS
3309
3310static ssize_t
ee959b00
TJ
3311mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3312 char *buf)
edb9068d 3313{
ee959b00 3314 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3315 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3316 MPT_ADAPTER *ioc = hd->ioc;
3317
3318 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3319 (ioc->biosVersion & 0xFF000000) >> 24,
3320 (ioc->biosVersion & 0x00FF0000) >> 16,
3321 (ioc->biosVersion & 0x0000FF00) >> 8,
3322 ioc->biosVersion & 0x000000FF);
3323}
ee959b00 3324static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
edb9068d
PS
3325
3326static ssize_t
ee959b00
TJ
3327mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3328 char *buf)
edb9068d 3329{
ee959b00 3330 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3331 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3332 MPT_ADAPTER *ioc = hd->ioc;
3333
3334 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3335}
ee959b00 3336static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
edb9068d
PS
3337
3338static ssize_t
ee959b00
TJ
3339mptscsih_version_product_show(struct device *dev,
3340 struct device_attribute *attr,
3341char *buf)
edb9068d 3342{
ee959b00 3343 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3344 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3345 MPT_ADAPTER *ioc = hd->ioc;
3346
3347 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3348}
ee959b00 3349static DEVICE_ATTR(version_product, S_IRUGO,
edb9068d
PS
3350 mptscsih_version_product_show, NULL);
3351
3352static ssize_t
ee959b00
TJ
3353mptscsih_version_nvdata_persistent_show(struct device *dev,
3354 struct device_attribute *attr,
3355 char *buf)
edb9068d 3356{
ee959b00 3357 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3358 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3359 MPT_ADAPTER *ioc = hd->ioc;
3360
3361 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3362 ioc->nvdata_version_persistent);
3363}
ee959b00 3364static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
edb9068d
PS
3365 mptscsih_version_nvdata_persistent_show, NULL);
3366
3367static ssize_t
ee959b00
TJ
3368mptscsih_version_nvdata_default_show(struct device *dev,
3369 struct device_attribute *attr, char *buf)
edb9068d 3370{
ee959b00 3371 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3372 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3373 MPT_ADAPTER *ioc = hd->ioc;
3374
3375 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3376}
ee959b00 3377static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
edb9068d
PS
3378 mptscsih_version_nvdata_default_show, NULL);
3379
3380static ssize_t
ee959b00
TJ
3381mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3382 char *buf)
edb9068d 3383{
ee959b00 3384 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3385 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3386 MPT_ADAPTER *ioc = hd->ioc;
3387
3388 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3389}
ee959b00 3390static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
edb9068d
PS
3391
3392static ssize_t
ee959b00
TJ
3393mptscsih_board_assembly_show(struct device *dev,
3394 struct device_attribute *attr, char *buf)
edb9068d 3395{
ee959b00 3396 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3397 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3398 MPT_ADAPTER *ioc = hd->ioc;
3399
3400 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3401}
ee959b00 3402static DEVICE_ATTR(board_assembly, S_IRUGO,
edb9068d
PS
3403 mptscsih_board_assembly_show, NULL);
3404
3405static ssize_t
ee959b00
TJ
3406mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3407 char *buf)
edb9068d 3408{
ee959b00 3409 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3410 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3411 MPT_ADAPTER *ioc = hd->ioc;
3412
3413 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3414}
ee959b00 3415static DEVICE_ATTR(board_tracer, S_IRUGO,
edb9068d
PS
3416 mptscsih_board_tracer_show, NULL);
3417
3418static ssize_t
ee959b00
TJ
3419mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3420 char *buf)
edb9068d 3421{
ee959b00 3422 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3423 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3424 MPT_ADAPTER *ioc = hd->ioc;
3425
3426 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3427}
ee959b00 3428static DEVICE_ATTR(io_delay, S_IRUGO,
edb9068d
PS
3429 mptscsih_io_delay_show, NULL);
3430
3431static ssize_t
ee959b00
TJ
3432mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3433 char *buf)
edb9068d 3434{
ee959b00 3435 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3436 MPT_SCSI_HOST *hd = shost_priv(host);
edb9068d
PS
3437 MPT_ADAPTER *ioc = hd->ioc;
3438
3439 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3440}
ee959b00 3441static DEVICE_ATTR(device_delay, S_IRUGO,
edb9068d
PS
3442 mptscsih_device_delay_show, NULL);
3443
6757d6b4 3444static ssize_t
ee959b00
TJ
3445mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3446 char *buf)
6757d6b4 3447{
ee959b00 3448 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3449 MPT_SCSI_HOST *hd = shost_priv(host);
6757d6b4
PS
3450 MPT_ADAPTER *ioc = hd->ioc;
3451
3452 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3453}
3454static ssize_t
ee959b00
TJ
3455mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3456 const char *buf, size_t count)
6757d6b4 3457{
ee959b00 3458 struct Scsi_Host *host = class_to_shost(dev);
e7eae9f6 3459 MPT_SCSI_HOST *hd = shost_priv(host);
6757d6b4
PS
3460 MPT_ADAPTER *ioc = hd->ioc;
3461 int val = 0;
3462
3463 if (sscanf(buf, "%x", &val) != 1)
3464 return -EINVAL;
3465
3466 ioc->debug_level = val;
3467 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3468 ioc->name, ioc->debug_level);
3469 return strlen(buf);
3470}
ee959b00
TJ
3471static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3472 mptscsih_debug_level_show, mptscsih_debug_level_store);
3473
3474struct device_attribute *mptscsih_host_attrs[] = {
3475 &dev_attr_version_fw,
3476 &dev_attr_version_bios,
3477 &dev_attr_version_mpi,
3478 &dev_attr_version_product,
3479 &dev_attr_version_nvdata_persistent,
3480 &dev_attr_version_nvdata_default,
3481 &dev_attr_board_name,
3482 &dev_attr_board_assembly,
3483 &dev_attr_board_tracer,
3484 &dev_attr_io_delay,
3485 &dev_attr_device_delay,
3486 &dev_attr_debug_level,
edb9068d
PS
3487 NULL,
3488};
3489EXPORT_SYMBOL(mptscsih_host_attrs);
3490
0d0c7974
MED
3491EXPORT_SYMBOL(mptscsih_remove);
3492EXPORT_SYMBOL(mptscsih_shutdown);
3493#ifdef CONFIG_PM
3494EXPORT_SYMBOL(mptscsih_suspend);
3495EXPORT_SYMBOL(mptscsih_resume);
3496#endif
3497EXPORT_SYMBOL(mptscsih_proc_info);
3498EXPORT_SYMBOL(mptscsih_info);
3499EXPORT_SYMBOL(mptscsih_qcmd);
0d0c7974
MED
3500EXPORT_SYMBOL(mptscsih_slave_destroy);
3501EXPORT_SYMBOL(mptscsih_slave_configure);
3502EXPORT_SYMBOL(mptscsih_abort);
3503EXPORT_SYMBOL(mptscsih_dev_reset);
3504EXPORT_SYMBOL(mptscsih_bus_reset);
3505EXPORT_SYMBOL(mptscsih_host_reset);
3506EXPORT_SYMBOL(mptscsih_bios_param);
3507EXPORT_SYMBOL(mptscsih_io_done);
3508EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3509EXPORT_SYMBOL(mptscsih_scandv_complete);
3510EXPORT_SYMBOL(mptscsih_event_process);
3511EXPORT_SYMBOL(mptscsih_ioc_reset);
6e3815ba 3512EXPORT_SYMBOL(mptscsih_change_queue_depth);
0d0c7974 3513EXPORT_SYMBOL(mptscsih_timer_expired);
663e1aa1 3514EXPORT_SYMBOL(mptscsih_TMHandler);
1da177e4 3515
0d0c7974 3516/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/