blob: fd3aa2619f427317c5d7afb1e73d472887bd2c7a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/workqueue.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060063#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "mptbase.h"
66#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060067#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*
81 * Other private/forward protos...
82 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040083int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040085int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
88 SCSIIORequest_t *pReq, int req_idx);
89static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040090static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
92static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -060093static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Eric Moore793955f2007-01-29 09:42:20 -070095static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040097int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
98int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400100int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700102static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400104void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700105void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400107int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
108int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#endif
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
114/**
115 * mptscsih_add_sge - Place a simple SGE at address pAddr.
116 * @pAddr: virtual address for SGE
117 * @flagslength: SGE flags and data transfer length
118 * @dma_addr: Physical address
119 *
120 * This routine places a MPT request frame back on the MPT adapter's
121 * FreeQ.
122 */
123static inline void
124mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
125{
126 if (sizeof(dma_addr_t) == sizeof(u64)) {
127 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
128 u32 tmp = dma_addr & 0xFFFFFFFF;
129
130 pSge->FlagsLength = cpu_to_le32(flagslength);
131 pSge->Address.Low = cpu_to_le32(tmp);
132 tmp = (u32) ((u64)dma_addr >> 32);
133 pSge->Address.High = cpu_to_le32(tmp);
134
135 } else {
136 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
137 pSge->FlagsLength = cpu_to_le32(flagslength);
138 pSge->Address = cpu_to_le32(dma_addr);
139 }
140} /* mptscsih_add_sge() */
141
142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
143/**
144 * mptscsih_add_chain - Place a chain SGE at address pAddr.
145 * @pAddr: virtual address for SGE
146 * @next: nextChainOffset value (u32's)
147 * @length: length of next SGL segment
148 * @dma_addr: Physical address
149 *
150 * This routine places a MPT request frame back on the MPT adapter's
151 * FreeQ.
152 */
153static inline void
154mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
155{
156 if (sizeof(dma_addr_t) == sizeof(u64)) {
157 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
158 u32 tmp = dma_addr & 0xFFFFFFFF;
159
160 pChain->Length = cpu_to_le16(length);
161 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
162
163 pChain->NextChainOffset = next;
164
165 pChain->Address.Low = cpu_to_le32(tmp);
166 tmp = (u32) ((u64)dma_addr >> 32);
167 pChain->Address.High = cpu_to_le32(tmp);
168 } else {
169 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
170 pChain->Length = cpu_to_le16(length);
171 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
172 pChain->NextChainOffset = next;
173 pChain->Address = cpu_to_le32(dma_addr);
174 }
175} /* mptscsih_add_chain() */
176
177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
178/*
179 * mptscsih_getFreeChainBuffer - Function to get a free chain
180 * from the MPT_SCSI_HOST FreeChainQ.
181 * @ioc: Pointer to MPT_ADAPTER structure
182 * @req_idx: Index of the SCSI IO request frame. (output)
183 *
184 * return SUCCESS or FAILED
185 */
186static inline int
187mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
188{
189 MPT_FRAME_HDR *chainBuf;
190 unsigned long flags;
191 int rc;
192 int chain_idx;
193
194 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
195 ioc->name));
196 spin_lock_irqsave(&ioc->FreeQlock, flags);
197 if (!list_empty(&ioc->FreeChainQ)) {
198 int offset;
199
200 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
201 u.frame.linkage.list);
202 list_del(&chainBuf->u.frame.linkage.list);
203 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
204 chain_idx = offset / ioc->req_sz;
205 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200206 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
207 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 } else {
209 rc = FAILED;
210 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200211 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 ioc->name));
213 }
214 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
215
216 *retIndex = chain_idx;
217 return rc;
218} /* mptscsih_getFreeChainBuffer() */
219
220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
221/*
222 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
223 * SCSIIORequest_t Message Frame.
224 * @ioc: Pointer to MPT_ADAPTER structure
225 * @SCpnt: Pointer to scsi_cmnd structure
226 * @pReq: Pointer to SCSIIORequest_t structure
227 *
228 * Returns ...
229 */
230static int
231mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
232 SCSIIORequest_t *pReq, int req_idx)
233{
234 char *psge;
235 char *chainSge;
236 struct scatterlist *sg;
237 int frm_sz;
238 int sges_left, sg_done;
239 int chain_idx = MPT_HOST_NO_CHAIN;
240 int sgeOffset;
241 int numSgeSlots, numSgeThisFrame;
242 u32 sgflags, sgdir, thisxfer = 0;
243 int chain_dma_off = 0;
244 int newIndex;
245 int ii;
246 dma_addr_t v2;
247 u32 RequestNB;
248
249 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
250 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
251 sgdir = MPT_TRANSFER_HOST_TO_IOC;
252 } else {
253 sgdir = MPT_TRANSFER_IOC_TO_HOST;
254 }
255
256 psge = (char *) &pReq->SGL;
257 frm_sz = ioc->req_sz;
258
259 /* Map the data portion, if any.
260 * sges_left = 0 if no data transfer.
261 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900262 sges_left = scsi_dma_map(SCpnt);
263 if (sges_left < 0)
264 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 /* Handle the SG case.
267 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900268 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sg_done = 0;
270 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
271 chainSge = NULL;
272
273 /* Prior to entering this loop - the following must be set
274 * current MF: sgeOffset (bytes)
275 * chainSge (Null if original MF is not a chain buffer)
276 * sg_done (num SGE done for this MF)
277 */
278
279nextSGEset:
280 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
281 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
282
283 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
284
285 /* Get first (num - 1) SG elements
286 * Skip any SG entries with a length of 0
287 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
288 */
289 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
290 thisxfer = sg_dma_len(sg);
291 if (thisxfer == 0) {
292 sg ++; /* Get next SG element from the OS */
293 sg_done++;
294 continue;
295 }
296
297 v2 = sg_dma_address(sg);
298 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
299
300 sg++; /* Get next SG element from the OS */
301 psge += (sizeof(u32) + sizeof(dma_addr_t));
302 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
303 sg_done++;
304 }
305
306 if (numSgeThisFrame == sges_left) {
307 /* Add last element, end of buffer and end of list flags.
308 */
309 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
310 MPT_SGE_FLAGS_END_OF_BUFFER |
311 MPT_SGE_FLAGS_END_OF_LIST;
312
313 /* Add last SGE and set termination flags.
314 * Note: Last SGE may have a length of 0 - which should be ok.
315 */
316 thisxfer = sg_dma_len(sg);
317
318 v2 = sg_dma_address(sg);
319 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
320 /*
321 sg++;
322 psge += (sizeof(u32) + sizeof(dma_addr_t));
323 */
324 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
325 sg_done++;
326
327 if (chainSge) {
328 /* The current buffer is a chain buffer,
329 * but there is not another one.
330 * Update the chain element
331 * Offset and Length fields.
332 */
333 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
334 } else {
335 /* The current buffer is the original MF
336 * and there is no Chain buffer.
337 */
338 pReq->ChainOffset = 0;
339 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200340 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
342 ioc->RequestNB[req_idx] = RequestNB;
343 }
344 } else {
345 /* At least one chain buffer is needed.
346 * Complete the first MF
347 * - last SGE element, set the LastElement bit
348 * - set ChainOffset (words) for orig MF
349 * (OR finish previous MF chain buffer)
350 * - update MFStructPtr ChainIndex
351 * - Populate chain element
352 * Also
353 * Loop until done.
354 */
355
356 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
357 ioc->name, sg_done));
358
359 /* Set LAST_ELEMENT flag for last non-chain element
360 * in the buffer. Since psge points at the NEXT
361 * SGE element, go back one SGE element, update the flags
362 * and reset the pointer. (Note: sgflags & thisxfer are already
363 * set properly).
364 */
365 if (sg_done) {
366 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
367 sgflags = le32_to_cpu(*ptmp);
368 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
369 *ptmp = cpu_to_le32(sgflags);
370 }
371
372 if (chainSge) {
373 /* The current buffer is a chain buffer.
374 * chainSge points to the previous Chain Element.
375 * Update its chain element Offset and Length (must
376 * include chain element size) fields.
377 * Old chain element is now complete.
378 */
379 u8 nextChain = (u8) (sgeOffset >> 2);
380 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
381 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
382 } else {
383 /* The original MF buffer requires a chain buffer -
384 * set the offset.
385 * Last element in this MF is a chain element.
386 */
387 pReq->ChainOffset = (u8) (sgeOffset >> 2);
388 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
389 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
390 ioc->RequestNB[req_idx] = RequestNB;
391 }
392
393 sges_left -= sg_done;
394
395
396 /* NOTE: psge points to the beginning of the chain element
397 * in current buffer. Get a chain buffer.
398 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200399 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
400 dfailprintk((MYIOC_s_INFO_FMT
401 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
402 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* Update the tracking arrays.
407 * If chainSge == NULL, update ReqToChain, else ChainToChain
408 */
409 if (chainSge) {
410 ioc->ChainToChain[chain_idx] = newIndex;
411 } else {
412 ioc->ReqToChain[req_idx] = newIndex;
413 }
414 chain_idx = newIndex;
415 chain_dma_off = ioc->req_sz * chain_idx;
416
417 /* Populate the chainSGE for the current buffer.
418 * - Set chain buffer pointer to psge and fill
419 * out the Address and Flags fields.
420 */
421 chainSge = (char *) psge;
422 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
423 psge, req_idx));
424
425 /* Start the SGE for the next buffer
426 */
427 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
428 sgeOffset = 0;
429 sg_done = 0;
430
431 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
432 psge, chain_idx));
433
434 /* Start the SGE for the next buffer
435 */
436
437 goto nextSGEset;
438 }
439
440 return SUCCESS;
441} /* mptscsih_AddSGE() */
442
Eric Moore786899b2006-07-11 17:22:22 -0600443static void
444mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
445 U32 SlotStatus)
446{
447 MPT_FRAME_HDR *mf;
448 SEPRequest_t *SEPMsg;
449
Eric Moorecc78d302007-06-15 17:27:21 -0600450 if (ioc->bus_type != SAS)
451 return;
452
453 /* Not supported for hidden raid components
454 */
455 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600456 return;
457
458 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
459 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
460 ioc->name,__FUNCTION__));
461 return;
462 }
463
464 SEPMsg = (SEPRequest_t *)mf;
465 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700466 SEPMsg->Bus = vtarget->channel;
467 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600468 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
469 SEPMsg->SlotStatus = SlotStatus;
470 devtverboseprintk((MYIOC_s_WARN_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700471 "Sending SEP cmd=%x channel=%d id=%d\n",
472 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600473 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
474}
475
Eric Moorec6c727a2007-01-29 09:44:54 -0700476#ifdef MPT_DEBUG_REPLY
477/**
478 * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
479 * @ioc: Pointer to MPT_ADAPTER structure
480 * @ioc_status: U32 IOCStatus word from IOC
481 * @scsi_status: U8 sam status from target
482 * @scsi_state: U8 scsi state
483 * @sc: original scsi cmnd pointer
484 * @mf: Pointer to MPT request frame
485 *
486 * Refer to lsi/mpi.h.
487 **/
488static void
489mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
490 u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
491{
492 char extend_desc[EVENT_DESCR_STR_SZ];
493 char *desc = NULL;
494
495 switch (ioc_status) {
496
497 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
498 desc = "SCSI Invalid Bus";
499 break;
500
501 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
502 desc = "SCSI Invalid TargetID";
503 break;
504
505 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
506 /*
507 * Inquiry is issued for device scanning
508 */
509 if (sc->cmnd[0] != 0x12)
510 desc = "SCSI Device Not There";
511 break;
512
513 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
514 desc = "SCSI Data Overrun";
515 break;
516
517 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
518 desc = "SCSI I/O Data Error";
519 break;
520
521 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
522 desc = "SCSI Protocol Error";
523 break;
524
525 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
526 desc = "SCSI Task Terminated";
527 break;
528
529 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
530 desc = "SCSI Residual Mismatch";
531 break;
532
533 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
534 desc = "SCSI Task Management Failed";
535 break;
536
537 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
538 desc = "SCSI IOC Terminated";
539 break;
540
541 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
542 desc = "SCSI Ext Terminated";
543 break;
544 }
545
546 if (!desc)
547 return;
548
549 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
550 "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
551 sc->device->host->host_no,
552 sc->device->channel, sc->device->id, sc->device->lun,
553 sc->cmnd[0], scsi_status, scsi_state);
554
555 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
556 ioc->name, ioc_status, desc, extend_desc);
557}
558#endif
559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
561/*
562 * mptscsih_io_done - Main SCSI IO callback routine registered to
563 * Fusion MPT (base) driver
564 * @ioc: Pointer to MPT_ADAPTER structure
565 * @mf: Pointer to original MPT request frame
566 * @r: Pointer to MPT reply frame (NULL if TurboReply)
567 *
568 * This routine is called from mpt.c::mpt_interrupt() at the completion
569 * of any SCSI IO request.
570 * This routine is registered with the Fusion MPT (base) driver at driver
571 * load/init time via the mpt_register() API call.
572 *
573 * Returns 1 indicating alloc'd request frame ptr should be freed.
574 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400575int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
577{
578 struct scsi_cmnd *sc;
579 MPT_SCSI_HOST *hd;
580 SCSIIORequest_t *pScsiReq;
581 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700582 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600583 VirtDevice *vdev;
584 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
587
588 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700589 req_idx_MR = (mr != NULL) ?
590 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
591 if ((req_idx != req_idx_MR) ||
592 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
593 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
594 ioc->name);
595 printk (MYIOC_s_ERR_FMT
596 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
597 ioc->name, req_idx, req_idx_MR, mf, mr,
598 hd->ScsiLookup[req_idx_MR]);
599 return 0;
600 }
601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600603 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (sc == NULL) {
605 MPIHeader_t *hdr = (MPIHeader_t *)mf;
606
607 /* Remark: writeSDP1 will use the ScsiDoneCtx
608 * If a SCSI I/O cmd, device disabled by OS and
609 * completion done. Cannot touch sc struct. Just free mem.
610 */
611 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
612 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
613 ioc->name);
614
615 mptscsih_freeChainBuffers(ioc, req_idx);
616 return 1;
617 }
618
Eric Moore3dc0b032006-07-11 17:32:33 -0600619 if ((unsigned char *)mf != sc->host_scribble) {
620 mptscsih_freeChainBuffers(ioc, req_idx);
621 return 1;
622 }
623
624 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 sc->result = DID_OK << 16; /* Set default reply as OK */
626 pScsiReq = (SCSIIORequest_t *) mf;
627 pScsiReply = (SCSIIOReply_t *) mr;
628
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200629 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
630 dmfprintk((MYIOC_s_INFO_FMT
631 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
632 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
633 }else{
634 dmfprintk((MYIOC_s_INFO_FMT
635 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
636 ioc->name, mf, mr, sc, req_idx));
637 }
638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (pScsiReply == NULL) {
640 /* special context reply handling */
641 ;
642 } else {
643 u32 xfer_cnt;
644 u16 status;
645 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700646 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
649 scsi_state = pScsiReply->SCSIState;
650 scsi_status = pScsiReply->SCSIStatus;
651 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900652 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700653 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600655 /*
656 * if we get a data underrun indication, yet no data was
657 * transferred and the SCSI status indicates that the
658 * command was never started, change the data underrun
659 * to success
660 */
661 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
662 (scsi_status == MPI_SCSI_STATUS_BUSY ||
663 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
664 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
665 status = MPI_IOCSTATUS_SUCCESS;
666 }
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400669 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 /*
672 * Look for + dump FCP ResponseInfo[]!
673 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600674 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
675 pScsiReply->ResponseInfo) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700676 printk(KERN_NOTICE "[%d:%d:%d:%d] "
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600677 "FCP_ResponseInfo=%08xh\n",
Eric Moorec6c727a2007-01-29 09:44:54 -0700678 sc->device->host->host_no, sc->device->channel,
679 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 le32_to_cpu(pScsiReply->ResponseInfo));
681 }
682
683 switch(status) {
684 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
685 /* CHECKME!
686 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
687 * But not: DID_BUS_BUSY lest one risk
688 * killing interrupt handler:-(
689 */
690 sc->result = SAM_STAT_BUSY;
691 break;
692
693 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
694 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
695 sc->result = DID_BAD_TARGET << 16;
696 break;
697
698 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
699 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600700 if (ioc->bus_type != FC)
701 sc->result = DID_NO_CONNECT << 16;
702 /* else fibre, just stall until rescan event */
703 else
704 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
707 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600708
709 vdev = sc->device->hostdata;
710 if (!vdev)
711 break;
712 vtarget = vdev->vtarget;
713 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
714 mptscsih_issue_sep_command(ioc, vtarget,
715 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
716 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 break;
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600721 if ( ioc->bus_type == SAS ) {
722 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
723 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700724 if ((log_info & SAS_LOGINFO_MASK)
725 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600726 sc->result = (DID_BUS_BUSY << 16);
727 break;
728 }
729 }
Eric Moore86dd4242007-01-04 20:44:01 -0700730 } else if (ioc->bus_type == FC) {
731 /*
732 * The FC IOC may kill a request for variety of
733 * reasons, some of which may be recovered by a
734 * retry, some which are unlikely to be
735 * recovered. Return DID_ERROR instead of
736 * DID_RESET to permit retry of the command,
737 * just not an infinite number of them
738 */
739 sc->result = DID_ERROR << 16;
740 break;
Eric Moorebf451522006-07-11 17:25:35 -0600741 }
742
743 /*
744 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
745 */
746
747 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
749 /* Linux handles an unsolicited DID_RESET better
750 * than an unsolicited DID_ABORT.
751 */
752 sc->result = DID_RESET << 16;
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 break;
755
756 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900757 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600758 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
759 sc->result=DID_SOFT_ERROR << 16;
760 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600762 dreplyprintk((KERN_NOTICE
Eric Moorec6c727a2007-01-29 09:44:54 -0700763 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
764 sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
768 /*
769 * Do upfront check for valid SenseData and give it
770 * precedence!
771 */
772 sc->result = (DID_OK << 16) | scsi_status;
773 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
774 /* Have already saved the status and sense data
775 */
776 ;
777 } else {
778 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600779 if (scsi_status == SAM_STAT_BUSY)
780 sc->result = SAM_STAT_BUSY;
781 else
782 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
785 /* What to do?
786 */
787 sc->result = DID_SOFT_ERROR << 16;
788 }
789 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
790 /* Not real sure here either... */
791 sc->result = DID_RESET << 16;
792 }
793 }
794
795 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
796 sc->underflow));
797 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
798 /* Report Queue Full
799 */
800 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
801 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 break;
804
Moore, Eric7e551472006-01-16 18:53:21 -0700805 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900806 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
808 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600809 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (scsi_state == 0) {
811 ;
812 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
813 /*
814 * If running against circa 200003dd 909 MPT f/w,
815 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
816 * (QUEUE_FULL) returned from device! --> get 0x0000?128
817 * and with SenseBytes set to 0.
818 */
819 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
820 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
821
822 }
823 else if (scsi_state &
824 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
825 ) {
826 /*
827 * What to do?
828 */
829 sc->result = DID_SOFT_ERROR << 16;
830 }
831 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
832 /* Not real sure here either... */
833 sc->result = DID_RESET << 16;
834 }
835 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
836 /* Device Inq. data indicates that it supports
837 * QTags, but rejects QTag messages.
838 * This command completed OK.
839 *
840 * Not real sure here either so do nothing... */
841 }
842
843 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
844 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
845
846 /* Add handling of:
847 * Reservation Conflict, Busy,
848 * Command Terminated, CHECK
849 */
850 break;
851
852 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
853 sc->result = DID_SOFT_ERROR << 16;
854 break;
855
856 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
857 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
858 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
859 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
860 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
861 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
862 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
864 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
865 default:
866 /*
867 * What to do?
868 */
869 sc->result = DID_SOFT_ERROR << 16;
870 break;
871
872 } /* switch(status) */
873
Eric Moorec6c727a2007-01-29 09:44:54 -0700874#ifdef MPT_DEBUG_REPLY
875 if (sc->result) {
876
877 mptscsih_iocstatus_info_scsiio(ioc, status,
878 scsi_status, scsi_state, sc);
879
880 dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
881 "result=0x%08x\n\tiocstatus=0x%04X "
882 "scsi_state=0x%02X scsi_status=0x%02X "
883 "loginfo=0x%08X\n", __FUNCTION__,
884 sc->device->host->host_no, sc->device->channel, sc->device->id,
885 sc->device->lun, sc->cmnd[0], sc->result, status,
886 scsi_state, scsi_status, log_info));
887
888 dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900889 "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
890 sc->device->host->host_no,
891 sc->device->channel, sc->device->id,
892 sc->device->lun, scsi_get_resid(sc),
893 scsi_bufflen(sc), xfer_cnt));
Eric Moorec6c727a2007-01-29 09:44:54 -0700894 }
895#endif
896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 } /* end of address reply case */
898
899 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900900 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 sc->scsi_done(sc); /* Issue the command callback */
903
904 /* Free Chain buffers */
905 mptscsih_freeChainBuffers(ioc, req_idx);
906 return 1;
907}
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909/*
910 * mptscsih_flush_running_cmds - For each command found, search
911 * Scsi_Host instance taskQ and reply to OS.
912 * Called only if recovering from a FW reload.
913 * @hd: Pointer to a SCSI HOST structure
914 *
915 * Returns: None.
916 *
917 * Must be called while new I/Os are being queued.
918 */
919static void
920mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
921{
922 MPT_ADAPTER *ioc = hd->ioc;
923 struct scsi_cmnd *SCpnt;
924 MPT_FRAME_HDR *mf;
925 int ii;
926 int max = ioc->req_depth;
927
928 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
929 for (ii= 0; ii < max; ii++) {
930 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
931
932 /* Command found.
933 */
934
935 /* Null ScsiLookup index
936 */
937 hd->ScsiLookup[ii] = NULL;
938
939 mf = MPT_INDEX_2_MFPTR(ioc, ii);
940 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
941 mf, SCpnt));
942
Eric Moore3dc0b032006-07-11 17:32:33 -0600943 /* Free Chain buffers */
944 mptscsih_freeChainBuffers(ioc, ii);
945
946 /* Free Message frames */
947 mpt_free_msg_frame(ioc, mf);
948
949 if ((unsigned char *)mf != SCpnt->host_scribble)
950 continue;
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 /* Set status, free OS resources (SG DMA buffers)
953 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900955 scsi_dma_unmap(SCpnt);
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 SCpnt->result = DID_RESET << 16;
958 SCpnt->host_scribble = NULL;
959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
961 }
962 }
963
964 return;
965}
966
967/*
968 * mptscsih_search_running_cmds - Delete any commands associated
969 * with the specified target and lun. Function called only
970 * when a lun is disable by mid-layer.
971 * Do NOT access the referenced scsi_cmnd structure or
972 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600973 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700974 * @hd: Pointer to a SCSI HOST structure
975 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 *
977 * Returns: None.
978 *
979 * Called from slave_destroy.
980 */
981static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700982mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
984 SCSIIORequest_t *mf = NULL;
985 int ii;
986 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600987 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700988 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Eric Moore793955f2007-01-29 09:42:20 -0700990 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
991 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600994 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600997 if (mf == NULL)
998 continue;
Eric Moorecc78d302007-06-15 17:27:21 -0600999 /* If the device is a hidden raid component, then its
1000 * expected that the mf->function will be RAID_SCSI_IO
1001 */
1002 if (vdevice->vtarget->tflags &
1003 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1004 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1005 continue;
1006
Eric Moore793955f2007-01-29 09:42:20 -07001007 int_to_scsilun(vdevice->lun, &lun);
1008 if ((mf->Bus != vdevice->vtarget->channel) ||
1009 (mf->TargetID != vdevice->vtarget->id) ||
1010 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 continue;
1012
1013 /* Cleanup
1014 */
1015 hd->ScsiLookup[ii] = NULL;
1016 mptscsih_freeChainBuffers(hd->ioc, ii);
1017 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001018 if ((unsigned char *)mf != sc->host_scribble)
1019 continue;
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001020 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001021 sc->host_scribble = NULL;
1022 sc->result = DID_NO_CONNECT << 16;
Eric Moorecc78d302007-06-15 17:27:21 -06001023 dsprintk(( "search_running: found (sc=%p, mf = %p) "
1024 "channel %d id %d, lun %d \n", sc, mf,
1025 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001026 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 }
1028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return;
1030}
1031
1032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1035/*
1036 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1037 * from a SCSI target device.
1038 * @sc: Pointer to scsi_cmnd structure
1039 * @pScsiReply: Pointer to SCSIIOReply_t
1040 * @pScsiReq: Pointer to original SCSI request
1041 *
1042 * This routine periodically reports QUEUE_FULL status returned from a
1043 * SCSI target device. It reports this to the console via kernel
1044 * printk() API call, not more than once every 10 seconds.
1045 */
1046static void
1047mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1048{
1049 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001052 if (sc->device == NULL)
1053 return;
1054 if (sc->device->host == NULL)
1055 return;
1056 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1057 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001059 if (time - hd->last_queue_full > 10 * HZ) {
1060 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1061 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1062 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064}
1065
1066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1067/*
1068 * mptscsih_remove - Removed scsi devices
1069 * @pdev: Pointer to pci_dev structure
1070 *
1071 *
1072 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001073void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074mptscsih_remove(struct pci_dev *pdev)
1075{
1076 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1077 struct Scsi_Host *host = ioc->sh;
1078 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001079 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001081 if(!host) {
1082 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 scsi_remove_host(host);
1087
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001088 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1089 return;
1090
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001091 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001093 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001095 if (hd->ScsiLookup != NULL) {
1096 sz1 = hd->ioc->req_depth * sizeof(void *);
1097 kfree(hd->ScsiLookup);
1098 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
1100
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001101 dprintk((MYIOC_s_INFO_FMT
1102 "Free'd ScsiLookup (%d) memory\n",
1103 hd->ioc->name, sz1));
1104
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001105 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001106
1107 /* NULL the Scsi_Host pointer
1108 */
1109 hd->ioc->sh = NULL;
1110
1111 scsi_host_put(host);
1112
1113 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115}
1116
1117/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1118/*
1119 * mptscsih_shutdown - reboot notifier
1120 *
1121 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001122void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001123mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001125 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 struct Scsi_Host *host = ioc->sh;
1127 MPT_SCSI_HOST *hd;
1128
1129 if(!host)
1130 return;
1131
1132 hd = (MPT_SCSI_HOST *)host->hostdata;
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
1136#ifdef CONFIG_PM
1137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1138/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001139 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 *
1141 *
1142 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001143int
Pavel Machek8d189f72005-04-16 15:25:28 -07001144mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001146 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001147 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148}
1149
1150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1151/*
1152 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1153 *
1154 *
1155 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157mptscsih_resume(struct pci_dev *pdev)
1158{
Hormsb364fd52007-03-19 15:06:44 +09001159 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160}
1161
1162#endif
1163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1165/**
1166 * mptscsih_info - Return information about MPT adapter
1167 * @SChost: Pointer to Scsi_Host structure
1168 *
1169 * (linux scsi_host_template.info routine)
1170 *
1171 * Returns pointer to buffer where information was written.
1172 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001173const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174mptscsih_info(struct Scsi_Host *SChost)
1175{
1176 MPT_SCSI_HOST *h;
1177 int size = 0;
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001182 if (h->info_kbuf == NULL)
1183 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1184 return h->info_kbuf;
1185 h->info_kbuf[0] = '\0';
1186
1187 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1188 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001191 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192}
1193
1194struct info_str {
1195 char *buffer;
1196 int length;
1197 int offset;
1198 int pos;
1199};
1200
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001201static void
1202mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203{
1204 if (info->pos + len > info->length)
1205 len = info->length - info->pos;
1206
1207 if (info->pos + len < info->offset) {
1208 info->pos += len;
1209 return;
1210 }
1211
1212 if (info->pos < info->offset) {
1213 data += (info->offset - info->pos);
1214 len -= (info->offset - info->pos);
1215 }
1216
1217 if (len > 0) {
1218 memcpy(info->buffer + info->pos, data, len);
1219 info->pos += len;
1220 }
1221}
1222
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001223static int
1224mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225{
1226 va_list args;
1227 char buf[81];
1228 int len;
1229
1230 va_start(args, fmt);
1231 len = vsprintf(buf, fmt, args);
1232 va_end(args);
1233
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 return len;
1236}
1237
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001238static int
1239mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240{
1241 struct info_str info;
1242
1243 info.buffer = pbuf;
1244 info.length = len;
1245 info.offset = offset;
1246 info.pos = 0;
1247
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001248 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1249 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1250 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1251 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1254}
1255
1256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1257/**
1258 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001259 * @host: scsi host struct
1260 * @buffer: if write, user data; if read, buffer for user
1261 * @start: returns the buffer address
1262 * @offset: if write, 0; if read, the current offset into the buffer from
1263 * the previous read.
1264 * @length: if write, return length;
1265 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 *
1267 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001269int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1271 int length, int func)
1272{
1273 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1274 MPT_ADAPTER *ioc = hd->ioc;
1275 int size = 0;
1276
1277 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001278 /*
1279 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 */
1281 } else {
1282 if (start)
1283 *start = buffer;
1284
1285 size = mptscsih_host_info(ioc, buffer, offset, length);
1286 }
1287
1288 return size;
1289}
1290
1291/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1292#define ADD_INDEX_LOG(req_ent) do { } while(0)
1293
1294/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1295/**
1296 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1297 * @SCpnt: Pointer to scsi_cmnd structure
1298 * @done: Pointer SCSI mid-layer IO completion function
1299 *
1300 * (linux scsi_host_template.queuecommand routine)
1301 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1302 * from a linux scsi_cmnd request and send it to the IOC.
1303 *
1304 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1305 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001306int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1308{
1309 MPT_SCSI_HOST *hd;
1310 MPT_FRAME_HDR *mf;
1311 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001312 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 int lun;
1314 u32 datalen;
1315 u32 scsictl;
1316 u32 scsidir;
1317 u32 cmd_len;
1318 int my_idx;
1319 int ii;
1320
1321 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 lun = SCpnt->device->lun;
1323 SCpnt->scsi_done = done;
1324
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1326 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1327
1328 if (hd->resetPending) {
1329 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1330 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1331 return SCSI_MLQUEUE_HOST_BUSY;
1332 }
1333
1334 /*
1335 * Put together a MPT SCSI request...
1336 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001337 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1339 hd->ioc->name));
1340 return SCSI_MLQUEUE_HOST_BUSY;
1341 }
1342
1343 pScsiReq = (SCSIIORequest_t *) mf;
1344
1345 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1346
1347 ADD_INDEX_LOG(my_idx);
1348
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001349 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 * Seems we may receive a buffer (datalen>0) even when there
1351 * will be no data transfer! GRRRRR...
1352 */
1353 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001354 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1356 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001357 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1359 } else {
1360 datalen = 0;
1361 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1362 }
1363
1364 /* Default to untagged. Once a target structure has been allocated,
1365 * use the Inquiry data to determine if device supports tagged.
1366 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001367 if (vdev
1368 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 && (SCpnt->device->tagged_supported)) {
1370 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1371 } else {
1372 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1373 }
1374
1375 /* Use the above information to set up the message frame
1376 */
Eric Moore793955f2007-01-29 09:42:20 -07001377 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1378 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001380 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1381 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1382 else
1383 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 pScsiReq->CDBLength = SCpnt->cmd_len;
1385 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1386 pScsiReq->Reserved = 0;
1387 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001388 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 pScsiReq->Control = cpu_to_le32(scsictl);
1390
1391 /*
1392 * Write SCSI CDB into the message
1393 */
1394 cmd_len = SCpnt->cmd_len;
1395 for (ii=0; ii < cmd_len; ii++)
1396 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1397
1398 for (ii=cmd_len; ii < 16; ii++)
1399 pScsiReq->CDB[ii] = 0;
1400
1401 /* DataLength */
1402 pScsiReq->DataLength = cpu_to_le32(datalen);
1403
1404 /* SenseBuffer low address */
1405 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1406 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1407
1408 /* Now add the SG list
1409 * Always have a SGE even if null length.
1410 */
1411 if (datalen == 0) {
1412 /* Add a NULL SGE */
1413 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1414 (dma_addr_t) -1);
1415 } else {
1416 /* Add a 32 or 64 bit SGE */
1417 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1418 goto fail;
1419 }
1420
Eric Moore3dc0b032006-07-11 17:32:33 -06001421 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001424 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1426 hd->ioc->name, SCpnt, mf, my_idx));
1427 DBG_DUMP_REQUEST_FRAME(mf)
1428 return 0;
1429
1430 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001431 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1433 mpt_free_msg_frame(hd->ioc, mf);
1434 return SCSI_MLQUEUE_HOST_BUSY;
1435}
1436
1437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1438/*
1439 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1440 * with a SCSI IO request
1441 * @hd: Pointer to the MPT_SCSI_HOST instance
1442 * @req_idx: Index of the SCSI IO request frame.
1443 *
1444 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1445 * No return.
1446 */
1447static void
1448mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1449{
1450 MPT_FRAME_HDR *chain;
1451 unsigned long flags;
1452 int chain_idx;
1453 int next;
1454
1455 /* Get the first chain index and reset
1456 * tracker state.
1457 */
1458 chain_idx = ioc->ReqToChain[req_idx];
1459 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1460
1461 while (chain_idx != MPT_HOST_NO_CHAIN) {
1462
1463 /* Save the next chain buffer index */
1464 next = ioc->ChainToChain[chain_idx];
1465
1466 /* Free this chain buffer and reset
1467 * tracker
1468 */
1469 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1470
1471 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1472 + (chain_idx * ioc->req_sz));
1473
1474 spin_lock_irqsave(&ioc->FreeQlock, flags);
1475 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1476 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1477
1478 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1479 ioc->name, chain_idx));
1480
1481 /* handle next */
1482 chain_idx = next;
1483 }
1484 return;
1485}
1486
1487/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1488/*
1489 * Reset Handling
1490 */
1491
1492/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001493/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001495 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001497 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001498 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 * @lun: Logical Unit for reset (if appropriate)
1500 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001501 * @timeout: timeout for task management control
1502 *
1503 * Fall through to mpt_HardResetHandler if: not operational, too many
1504 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 *
1506 * Remark: Currently invoked from a non-interrupt thread (_bh).
1507 *
1508 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1509 * will be active.
1510 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001511 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001512 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001513int
Eric Moore793955f2007-01-29 09:42:20 -07001514mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
1516 MPT_ADAPTER *ioc;
1517 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 u32 ioc_raw_state;
1519 unsigned long flags;
1520
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1523
1524 // SJR - CHECKME - Can we avoid this here?
1525 // (mpt_HardResetHandler has this check...)
1526 spin_lock_irqsave(&ioc->diagLock, flags);
1527 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1528 spin_unlock_irqrestore(&ioc->diagLock, flags);
1529 return FAILED;
1530 }
1531 spin_unlock_irqrestore(&ioc->diagLock, flags);
1532
1533 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001534 * If we time out and not bus reset, then we return a FAILED status
1535 * to the caller.
1536 * The call to mptscsih_tm_pending_wait() will set the pending flag
1537 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 * successful. Otherwise, reload the FW.
1539 */
1540 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1541 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001542 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 "Timed out waiting for last TM (%d) to complete! \n",
1544 hd->ioc->name, hd->tmPending));
1545 return FAILED;
1546 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001547 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1548 "reset: Timed out waiting for last TM (%d) "
1549 "to complete! \n", hd->ioc->name,
1550 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return FAILED;
1552 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001553 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 "Timed out waiting for last TM (%d) to complete! \n",
1555 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001556 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 } else {
1559 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1560 hd->tmPending |= (1 << type);
1561 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1562 }
1563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1567 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001568 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1569 ioc->name, type, ioc_raw_state);
1570 printk(KERN_WARNING " Issuing HardReset!!\n");
1571 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1572 printk((KERN_WARNING "TMHandler: HardReset "
1573 "FAILED!!\n"));
1574 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
1576
Eric Moorecd2c6192007-01-29 09:47:47 -07001577 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1578 printk(MYIOC_s_WARN_FMT
1579 "TM Handler for type=%x: ioc_state: "
1580 "DOORBELL_ACTIVE (0x%x)!\n",
1581 ioc->name, type, ioc_raw_state);
1582 return FAILED;
1583 }
1584
1585 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001587 if (hd->hard_resets < -1)
1588 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
Eric Moorecd2c6192007-01-29 09:47:47 -07001590 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1591 ctx2abort, timeout);
1592 if (rc)
1593 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1594 hd->ioc->name);
1595 else
1596 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1597 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1600
1601 return rc;
1602}
1603
1604
1605/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001606/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1608 * @hd: Pointer to MPT_SCSI_HOST structure
1609 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001610 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001611 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 * @lun: Logical Unit for reset (if appropriate)
1613 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001614 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 *
1616 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1617 * or a non-interrupt thread. In the former, must not call schedule().
1618 *
1619 * Not all fields are meaningfull for all task types.
1620 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001621 * Returns 0 for SUCCESS, or FAILED.
1622 *
1623 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624static int
Eric Moore793955f2007-01-29 09:42:20 -07001625mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626{
1627 MPT_FRAME_HDR *mf;
1628 SCSITaskMgmt_t *pScsiTm;
1629 int ii;
1630 int retval;
1631
1632 /* Return Fail to calling function if no message frames available.
1633 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001634 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1636 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001637 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 }
1639 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1640 hd->ioc->name, mf));
1641
1642 /* Format the Request
1643 */
1644 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001645 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 pScsiTm->Bus = channel;
1647 pScsiTm->ChainOffset = 0;
1648 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1649
1650 pScsiTm->Reserved = 0;
1651 pScsiTm->TaskType = type;
1652 pScsiTm->Reserved1 = 0;
1653 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1654 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1655
Eric Moore793955f2007-01-29 09:42:20 -07001656 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
1658 for (ii=0; ii < 7; ii++)
1659 pScsiTm->Reserved2[ii] = 0;
1660
1661 pScsiTm->TaskMsgContext = ctx2abort;
1662
Eric Moorecd2c6192007-01-29 09:47:47 -07001663 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1664 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1667
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001668 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001669 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1670 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1671 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1672 hd->ioc, mf, retval));
1673 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
1675
1676 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001677 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1679 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1681 hd->ioc->name));
1682 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001683 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1684 hd->ioc->name, retval));
1685 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
1687
Eric Moorecd2c6192007-01-29 09:47:47 -07001688 /*
1689 * Handle success case, see if theres a non-zero ioc_status.
1690 */
1691 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1692 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1693 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1694 retval = 0;
1695 else
1696 retval = FAILED;
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001699
1700 fail_out:
1701
1702 /*
1703 * Free task managment mf, and corresponding tm flags
1704 */
1705 mpt_free_msg_frame(hd->ioc, mf);
1706 hd->tmPending = 0;
1707 hd->tmState = TM_STATE_NONE;
1708 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709}
1710
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001711static int
1712mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1713{
1714 switch (ioc->bus_type) {
1715 case FC:
1716 return 40;
1717 case SAS:
1718 return 10;
1719 case SPI:
1720 default:
1721 return 2;
1722 }
1723}
1724
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1726/**
1727 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1728 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1729 *
1730 * (linux scsi_host_template.eh_abort_handler routine)
1731 *
1732 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001733 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001734int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735mptscsih_abort(struct scsi_cmnd * SCpnt)
1736{
1737 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 MPT_FRAME_HDR *mf;
1739 u32 ctx2abort;
1740 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001741 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001742 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001743 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001744 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
1746 /* If we can't locate our host adapter structure, return FAILED status.
1747 */
1748 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1749 SCpnt->result = DID_RESET << 16;
1750 SCpnt->scsi_done(SCpnt);
Eric Moore958d4a32007-06-15 17:24:14 -06001751 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
1752 "host! (sc=%p)\n", SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 return FAILED;
1754 }
1755
Eric Moore958d4a32007-06-15 17:24:14 -06001756 ioc = hd->ioc;
1757 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1758 ioc->name, SCpnt);
1759 scsi_print_command(SCpnt);
1760
1761 vdevice = SCpnt->device->hostdata;
1762 if (!vdevice || !vdevice->vtarget) {
1763 dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
1764 "deleted (sc=%p)\n", ioc->name, SCpnt));
1765 SCpnt->result = DID_NO_CONNECT << 16;
1766 SCpnt->scsi_done(SCpnt);
1767 retval = 0;
1768 goto out;
1769 }
1770
Eric Moorecc78d302007-06-15 17:27:21 -06001771 /* Task aborts are not supported for hidden raid components.
1772 */
1773 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1774 dtmprintk((MYIOC_s_DEBUG_FMT "task abort: hidden raid "
1775 "component (sc=%p)\n", ioc->name, SCpnt));
1776 SCpnt->result = DID_RESET << 16;
1777 retval = FAILED;
1778 goto out;
1779 }
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 /* Find this command
1782 */
1783 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001784 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 * Do OS callback.
1786 */
1787 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001788 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001789 "Command not in the active list! (sc=%p)\n", ioc->name,
1790 SCpnt));
1791 retval = 0;
1792 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 }
1794
Eric Moore958d4a32007-06-15 17:24:14 -06001795 if (hd->resetPending) {
1796 retval = FAILED;
1797 goto out;
1798 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001799
1800 if (hd->timeouts < -1)
1801 hd->timeouts++;
1802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1804 * (the IO to be ABORT'd)
1805 *
1806 * NOTE: Since we do not byteswap MsgContext, we do not
1807 * swap it here either. It is an opaque cookie to
1808 * the controller, so it does not matter. -DaveM
1809 */
1810 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1811 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1812
1813 hd->abortSCpnt = SCpnt;
1814
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001815 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001816 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1817 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
Eric Moore3dc0b032006-07-11 17:32:33 -06001819 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001820 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001821 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001822
Eric Moore958d4a32007-06-15 17:24:14 -06001823 out:
1824 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1825 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001827 if (retval == 0)
1828 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001829 else
1830 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831}
1832
1833/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1834/**
1835 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1836 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1837 *
1838 * (linux scsi_host_template.eh_dev_reset_handler routine)
1839 *
1840 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001841 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001842int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1844{
1845 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001846 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001847 VirtDevice *vdevice;
1848 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850 /* If we can't locate our host adapter structure, return FAILED status.
1851 */
1852 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore958d4a32007-06-15 17:24:14 -06001853 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
1854 "locate host! (sc=%p)\n", SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 return FAILED;
1856 }
1857
Eric Moore958d4a32007-06-15 17:24:14 -06001858 ioc = hd->ioc;
1859 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1860 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001861 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
Eric Moore958d4a32007-06-15 17:24:14 -06001863 if (hd->resetPending) {
1864 retval = FAILED;
1865 goto out;
1866 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001867
Eric Moore958d4a32007-06-15 17:24:14 -06001868 vdevice = SCpnt->device->hostdata;
1869 if (!vdevice || !vdevice->vtarget) {
1870 retval = 0;
1871 goto out;
1872 }
1873
Eric Moorecc78d302007-06-15 17:27:21 -06001874 /* Target reset to hidden raid component is not supported
1875 */
1876 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1877 retval = FAILED;
1878 goto out;
1879 }
1880
Eric Moore958d4a32007-06-15 17:24:14 -06001881 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1882 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1883 mptscsih_get_tm_timeout(ioc));
1884
1885 out:
1886 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1887 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001888
1889 if (retval == 0)
1890 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001891 else
1892 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893}
1894
Eric Moorecd2c6192007-01-29 09:47:47 -07001895
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1897/**
1898 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1899 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1900 *
1901 * (linux scsi_host_template.eh_bus_reset_handler routine)
1902 *
1903 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001904 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001905int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1907{
1908 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001909 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001910 VirtDevice *vdev;
Eric Moore958d4a32007-06-15 17:24:14 -06001911 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 /* If we can't locate our host adapter structure, return FAILED status.
1914 */
1915 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore958d4a32007-06-15 17:24:14 -06001916 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
1917 "locate host! (sc=%p)\n", SCpnt ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 return FAILED;
1919 }
1920
Eric Moore958d4a32007-06-15 17:24:14 -06001921 ioc = hd->ioc;
1922 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1923 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001924 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
1926 if (hd->timeouts < -1)
1927 hd->timeouts++;
1928
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001929 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001930 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore958d4a32007-06-15 17:24:14 -06001931 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Eric Moore958d4a32007-06-15 17:24:14 -06001933 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1934 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001935
1936 if (retval == 0)
1937 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001938 else
1939 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940}
1941
1942/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1943/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001944 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1946 *
1947 * (linux scsi_host_template.eh_host_reset_handler routine)
1948 *
1949 * Returns SUCCESS or FAILED.
1950 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001951int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1953{
1954 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001955 int retval;
1956 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
1958 /* If we can't locate the host to reset, then we failed. */
1959 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore958d4a32007-06-15 17:24:14 -06001960 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
1961 "locate host! (sc=%p)\n", SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 return FAILED;
1963 }
1964
Eric Moore958d4a32007-06-15 17:24:14 -06001965 ioc = hd->ioc;
1966 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1967 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
1969 /* If our attempts to reset the host failed, then return a failed
1970 * status. The host will be taken off line by the SCSI mid-layer.
1971 */
Eric Moore958d4a32007-06-15 17:24:14 -06001972 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
1973 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 } else {
1975 /* Make sure TM pending is cleared and TM state is set to
1976 * NONE.
1977 */
Eric Moore958d4a32007-06-15 17:24:14 -06001978 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 hd->tmPending = 0;
1980 hd->tmState = TM_STATE_NONE;
1981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982
Eric Moore958d4a32007-06-15 17:24:14 -06001983 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1984 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
Eric Moore958d4a32007-06-15 17:24:14 -06001986 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987}
1988
1989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1990/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001991 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 * @hd: Pointer to MPT host structure.
1993 *
1994 * Returns {SUCCESS,FAILED}.
1995 */
1996static int
1997mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1998{
1999 unsigned long flags;
2000 int loop_count = 4 * 10; /* Wait 10 seconds */
2001 int status = FAILED;
2002
2003 do {
2004 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2005 if (hd->tmState == TM_STATE_NONE) {
2006 hd->tmState = TM_STATE_IN_PROGRESS;
2007 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002009 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 break;
2011 }
2012 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2013 msleep(250);
2014 } while (--loop_count);
2015
2016 return status;
2017}
2018
2019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2020/**
2021 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2022 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002023 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 *
2025 * Returns {SUCCESS,FAILED}.
2026 */
2027static int
2028mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2029{
2030 unsigned long flags;
2031 int loop_count = 4 * timeout;
2032 int status = FAILED;
2033
2034 do {
2035 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2036 if(hd->tmPending == 0) {
2037 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002038 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 break;
2040 }
2041 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002042 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 } while (--loop_count);
2044
2045 return status;
2046}
2047
2048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002049static void
2050mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2051{
2052 char *desc;
2053
2054 switch (response_code) {
2055 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2056 desc = "The task completed.";
2057 break;
2058 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2059 desc = "The IOC received an invalid frame status.";
2060 break;
2061 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2062 desc = "The task type is not supported.";
2063 break;
2064 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2065 desc = "The requested task failed.";
2066 break;
2067 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2068 desc = "The task completed successfully.";
2069 break;
2070 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2071 desc = "The LUN request is invalid.";
2072 break;
2073 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2074 desc = "The task is in the IOC queue and has not been sent to target.";
2075 break;
2076 default:
2077 desc = "unknown";
2078 break;
2079 }
2080 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2081 ioc->name, response_code, desc);
2082}
2083
2084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085/**
2086 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2087 * @ioc: Pointer to MPT_ADAPTER structure
2088 * @mf: Pointer to SCSI task mgmt request frame
2089 * @mr: Pointer to SCSI task mgmt reply frame
2090 *
2091 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2092 * of any SCSI task management request.
2093 * This routine is registered with the MPT (base) driver at driver
2094 * load/init time via the mpt_register() API call.
2095 *
2096 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002097 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002098int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2100{
2101 SCSITaskMgmtReply_t *pScsiTmReply;
2102 SCSITaskMgmt_t *pScsiTmReq;
2103 MPT_SCSI_HOST *hd;
2104 unsigned long flags;
2105 u16 iocstatus;
2106 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002107 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
2109 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002110 ioc->name, mf, mr));
2111 if (!ioc->sh) {
2112 dtmprintk((MYIOC_s_WARN_FMT
2113 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 return 1;
2115 }
2116
2117 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002118 dtmprintk((MYIOC_s_WARN_FMT
2119 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 }
2122
Eric Moorecd2c6192007-01-29 09:47:47 -07002123 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2124 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2125 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2126 tmType = pScsiTmReq->TaskType;
2127 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2128 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2129
2130 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2131 pScsiTmReply->ResponseCode)
2132 mptscsih_taskmgmt_response_code(ioc,
2133 pScsiTmReply->ResponseCode);
2134 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2135
2136#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2137 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2138 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2139 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2140 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2141 le16_to_cpu(pScsiTmReply->IOCStatus),
2142 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2143 le32_to_cpu(pScsiTmReply->TerminationCount));
2144#endif
2145 if (!iocstatus) {
2146 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2147 hd->abortSCpnt = NULL;
2148 goto out;
2149 }
2150
2151 /* Error? (anything non-zero?) */
2152
2153 /* clear flags and continue.
2154 */
2155 switch (tmType) {
2156
2157 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2158 if (termination_count == 1)
2159 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2160 hd->abortSCpnt = NULL;
2161 break;
2162
2163 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2164
2165 /* If an internal command is present
2166 * or the TM failed - reload the FW.
2167 * FC FW may respond FAILED to an ABORT
2168 */
2169 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2170 hd->cmdPtr)
2171 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2172 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2173 break;
2174
2175 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2176 default:
2177 break;
2178 }
2179
2180 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 spin_lock_irqsave(&ioc->FreeQlock, flags);
2182 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002184 hd->tm_iocstatus = iocstatus;
2185 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
2187 return 1;
2188}
2189
2190/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2191/*
2192 * This is anyones guess quite frankly.
2193 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002194int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2196 sector_t capacity, int geom[])
2197{
2198 int heads;
2199 int sectors;
2200 sector_t cylinders;
2201 ulong dummy;
2202
2203 heads = 64;
2204 sectors = 32;
2205
2206 dummy = heads * sectors;
2207 cylinders = capacity;
2208 sector_div(cylinders,dummy);
2209
2210 /*
2211 * Handle extended translation size for logical drives
2212 * > 1Gb
2213 */
2214 if ((ulong)capacity >= 0x200000) {
2215 heads = 255;
2216 sectors = 63;
2217 dummy = heads * sectors;
2218 cylinders = capacity;
2219 sector_div(cylinders,dummy);
2220 }
2221
2222 /* return result */
2223 geom[0] = heads;
2224 geom[1] = sectors;
2225 geom[2] = cylinders;
2226
2227 dprintk((KERN_NOTICE
2228 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002229 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 return 0;
2232}
2233
Moore, Ericf44e5462006-03-14 09:14:21 -07002234/* Search IOC page 3 to determine if this is hidden physical disk
2235 *
2236 */
2237int
Eric Moore793955f2007-01-29 09:42:20 -07002238mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002239{
Eric Mooreb506ade2007-01-29 09:45:37 -07002240 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002241 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002242 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002243
Eric Moore793955f2007-01-29 09:42:20 -07002244 if (!ioc->raid_data.pIocPg3)
2245 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002246 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002247 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2248 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2249 rc = 1;
2250 goto out;
2251 }
2252 }
2253
Eric Mooreb506ade2007-01-29 09:45:37 -07002254 /*
2255 * Check inactive list for matching phys disks
2256 */
2257 if (list_empty(&ioc->raid_data.inactive_list))
2258 goto out;
2259
2260 down(&ioc->raid_data.inactive_list_mutex);
2261 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2262 list) {
2263 if ((component_info->d.PhysDiskID == id) &&
2264 (component_info->d.PhysDiskBus == channel))
2265 rc = 1;
2266 }
2267 up(&ioc->raid_data.inactive_list_mutex);
2268
Eric Moore793955f2007-01-29 09:42:20 -07002269 out:
2270 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002271}
2272EXPORT_SYMBOL(mptscsih_is_phys_disk);
2273
Eric Moore793955f2007-01-29 09:42:20 -07002274u8
2275mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002276{
Eric Mooreb506ade2007-01-29 09:45:37 -07002277 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002278 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002279 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002280
Eric Moore793955f2007-01-29 09:42:20 -07002281 if (!ioc->raid_data.pIocPg3)
2282 goto out;
2283 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2284 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2285 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2286 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2287 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002288 }
2289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Eric Mooreb506ade2007-01-29 09:45:37 -07002291 /*
2292 * Check inactive list for matching phys disks
2293 */
2294 if (list_empty(&ioc->raid_data.inactive_list))
2295 goto out;
2296
2297 down(&ioc->raid_data.inactive_list_mutex);
2298 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2299 list) {
2300 if ((component_info->d.PhysDiskID == id) &&
2301 (component_info->d.PhysDiskBus == channel))
2302 rc = component_info->d.PhysDiskNum;
2303 }
2304 up(&ioc->raid_data.inactive_list_mutex);
2305
Eric Moore793955f2007-01-29 09:42:20 -07002306 out:
2307 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002308}
Eric Moore793955f2007-01-29 09:42:20 -07002309EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002310
2311/*
2312 * OS entry point to allow for host driver to free allocated memory
2313 * Called if no device present or device being unloaded
2314 */
2315void
2316mptscsih_slave_destroy(struct scsi_device *sdev)
2317{
2318 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002320 VirtTarget *vtarget;
2321 VirtDevice *vdevice;
2322 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 starget = scsi_target(sdev);
2325 vtarget = starget->hostdata;
2326 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002328 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002329 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002330 mptscsih_synchronize_cache(hd, vdevice);
2331 kfree(vdevice);
2332 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333}
2334
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002335/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2336/*
2337 * mptscsih_change_queue_depth - This function will set a devices queue depth
2338 * @sdev: per scsi_device pointer
2339 * @qdepth: requested queue depth
2340 *
2341 * Adding support for new 'change_queue_depth' api.
2342*/
2343int
2344mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002346 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2347 VirtTarget *vtarget;
2348 struct scsi_target *starget;
2349 int max_depth;
2350 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002352 starget = scsi_target(sdev);
2353 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002354
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002355 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002356 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002358 else if (sdev->type == TYPE_DISK &&
2359 vtarget->minSyncFactor <= MPT_ULTRA160)
2360 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2361 else
2362 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 } else
2364 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2365
2366 if (qdepth > max_depth)
2367 qdepth = max_depth;
2368 if (qdepth == 1)
2369 tagged = 0;
2370 else
2371 tagged = MSG_SIMPLE_TAG;
2372
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002373 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2374 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375}
2376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377/*
2378 * OS entry point to adjust the queue_depths on a per-device basis.
2379 * Called once per device the bus scan. Use it to force the queue_depth
2380 * member to 1 if a device does not support Q tags.
2381 * Return non-zero if fails.
2382 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002383int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002384mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002386 struct Scsi_Host *sh = sdev->host;
2387 VirtTarget *vtarget;
2388 VirtDevice *vdevice;
2389 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2391
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 starget = scsi_target(sdev);
2393 vtarget = starget->hostdata;
2394 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
2396 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002397 "device @ %p, channel=%d, id=%d, lun=%d\n",
2398 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002399 if (hd->ioc->bus_type == SPI)
2400 dsprintk((MYIOC_s_INFO_FMT
2401 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2402 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2403 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 goto slave_configure_exit;
2409 }
2410
Eric Moore793955f2007-01-29 09:42:20 -07002411 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002412 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 dsprintk((MYIOC_s_INFO_FMT
2415 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002416 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 if (hd->ioc->bus_type == SPI)
2419 dsprintk((MYIOC_s_INFO_FMT
2420 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2421 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2422 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424slave_configure_exit:
2425
2426 dsprintk((MYIOC_s_INFO_FMT
2427 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002428 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2429 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431 return 0;
2432}
2433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2435/*
2436 * Private routines...
2437 */
2438
2439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2440/* Utility function to copy sense data from the scsi_cmnd buffer
2441 * to the FC and SCSI target structures.
2442 *
2443 */
2444static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002445mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002447 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 SCSIIORequest_t *pReq;
2449 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 /* Get target structure
2452 */
2453 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002454 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 if (sense_count) {
2457 u8 *sense_data;
2458 int req_index;
2459
2460 /* Copy the sense received into the scsi command block. */
2461 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2462 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2463 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2464
2465 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2466 */
2467 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002468 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 int idx;
2470 MPT_ADAPTER *ioc = hd->ioc;
2471
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002472 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2474 ioc->events[idx].eventContext = ioc->eventContext;
2475
Dave Jones3d9780b2007-05-21 20:59:47 -04002476 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2477 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2478 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
Dave Jones3d9780b2007-05-21 20:59:47 -04002480 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002483 if (hd->ioc->pcidev->vendor ==
2484 PCI_VENDOR_ID_IBM) {
2485 mptscsih_issue_sep_command(hd->ioc,
2486 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2487 vdev->vtarget->tflags |=
2488 MPT_TARGET_FLAGS_LED_ON;
2489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 }
2491 }
2492 } else {
2493 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2494 hd->ioc->name));
2495 }
2496}
2497
Eric Moore3dc0b032006-07-11 17:32:33 -06002498static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2500{
2501 MPT_SCSI_HOST *hd;
2502 int i;
2503
2504 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2505
2506 for (i = 0; i < hd->ioc->req_depth; i++) {
2507 if (hd->ScsiLookup[i] == sc) {
2508 return i;
2509 }
2510 }
2511
2512 return -1;
2513}
2514
2515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002516int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2518{
2519 MPT_SCSI_HOST *hd;
2520 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002521 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 dtmprintk((KERN_WARNING MYNAM
2524 ": IOC %s_reset routed to SCSI host driver!\n",
2525 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2526 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2527
2528 /* If a FW reload request arrives after base installed but
2529 * before all scsi hosts have been attached, then an alt_ioc
2530 * may have a NULL sh pointer.
2531 */
2532 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2533 return 0;
2534 else
2535 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2536
2537 if (reset_phase == MPT_IOC_SETUP_RESET) {
2538 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2539
2540 /* Clean Up:
2541 * 1. Set Hard Reset Pending Flag
2542 * All new commands go to doneQ
2543 */
2544 hd->resetPending = 1;
2545
2546 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2547 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2548
2549 /* 2. Flush running commands
2550 * Clean ScsiLookup (and associated memory)
2551 * AND clean mytaskQ
2552 */
2553
2554 /* 2b. Reply to OS all known outstanding I/O commands.
2555 */
2556 mptscsih_flush_running_cmds(hd);
2557
2558 /* 2c. If there was an internal command that
2559 * has not completed, configuration or io request,
2560 * free these resources.
2561 */
2562 if (hd->cmdPtr) {
2563 del_timer(&hd->timer);
2564 mpt_free_msg_frame(ioc, hd->cmdPtr);
2565 }
2566
2567 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2568
2569 } else {
2570 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2571
2572 /* Once a FW reload begins, all new OS commands are
2573 * redirected to the doneQ w/ a reset status.
2574 * Init all control structures.
2575 */
2576
2577 /* ScsiLookup initialization
2578 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002579 for (ii=0; ii < hd->ioc->req_depth; ii++)
2580 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582 /* 2. Chain Buffer initialization
2583 */
2584
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002585 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588 /* 5. Enable new commands to be posted
2589 */
2590 spin_lock_irqsave(&ioc->FreeQlock, flags);
2591 hd->tmPending = 0;
2592 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2593 hd->resetPending = 0;
2594 hd->tmState = TM_STATE_NONE;
2595
2596 /* 6. If there was an internal command,
2597 * wake this process up.
2598 */
2599 if (hd->cmdPtr) {
2600 /*
2601 * Wake up the original calling thread
2602 */
2603 hd->pLocal = &hd->localReply;
2604 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002605 hd->scandv_wait_done = 1;
2606 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 hd->cmdPtr = NULL;
2608 }
2609
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2611
2612 }
2613
2614 return 1; /* currently means nothing really */
2615}
2616
2617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002618int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2620{
2621 MPT_SCSI_HOST *hd;
2622 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2623
Moore, Eric3a892be2006-03-14 09:14:03 -07002624 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 ioc->name, event));
2626
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002627 if (ioc->sh == NULL ||
2628 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2629 return 1;
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 switch (event) {
2632 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2633 /* FIXME! */
2634 break;
2635 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2636 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002637 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002638 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 break;
2640 case MPI_EVENT_LOGOUT: /* 09 */
2641 /* FIXME! */
2642 break;
2643
Michael Reed05e8ec12006-01-13 14:31:54 -06002644 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002645 break;
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 /*
2648 * CHECKME! Don't think we need to do
2649 * anything for these, but...
2650 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2652 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2653 /*
2654 * CHECKME! Falling thru...
2655 */
2656 break;
2657
2658 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002659 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 case MPI_EVENT_NONE: /* 00 */
2662 case MPI_EVENT_LOG_DATA: /* 01 */
2663 case MPI_EVENT_STATE_CHANGE: /* 02 */
2664 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2665 default:
2666 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2667 break;
2668 }
2669
2670 return 1; /* currently means nothing really */
2671}
2672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2674/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 * Bus Scan and Domain Validation functionality ...
2676 */
2677
2678/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2679/*
2680 * mptscsih_scandv_complete - Scan and DV callback routine registered
2681 * to Fustion MPT (base) driver.
2682 *
2683 * @ioc: Pointer to MPT_ADAPTER structure
2684 * @mf: Pointer to original MPT request frame
2685 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2686 *
2687 * This routine is called from mpt.c::mpt_interrupt() at the completion
2688 * of any SCSI IO request.
2689 * This routine is registered with the Fusion MPT (base) driver at driver
2690 * load/init time via the mpt_register() API call.
2691 *
2692 * Returns 1 indicating alloc'd request frame ptr should be freed.
2693 *
2694 * Remark: Sets a completion code and (possibly) saves sense data
2695 * in the IOC member localReply structure.
2696 * Used ONLY for DV and other internal commands.
2697 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002698int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2700{
2701 MPT_SCSI_HOST *hd;
2702 SCSIIORequest_t *pReq;
2703 int completionCode;
2704 u16 req_idx;
2705
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002706 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2707
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 if ((mf == NULL) ||
2709 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2710 printk(MYIOC_s_ERR_FMT
2711 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2712 ioc->name, mf?"BAD":"NULL", (void *) mf);
2713 goto wakeup;
2714 }
2715
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 del_timer(&hd->timer);
2717 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2718 hd->ScsiLookup[req_idx] = NULL;
2719 pReq = (SCSIIORequest_t *) mf;
2720
2721 if (mf != hd->cmdPtr) {
2722 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2723 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2724 }
2725 hd->cmdPtr = NULL;
2726
2727 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2728 hd->ioc->name, mf, mr, req_idx));
2729
2730 hd->pLocal = &hd->localReply;
2731 hd->pLocal->scsiStatus = 0;
2732
2733 /* If target struct exists, clear sense valid flag.
2734 */
2735 if (mr == NULL) {
2736 completionCode = MPT_SCANDV_GOOD;
2737 } else {
2738 SCSIIOReply_t *pReply;
2739 u16 status;
2740 u8 scsi_status;
2741
2742 pReply = (SCSIIOReply_t *) mr;
2743
2744 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2745 scsi_status = pReply->SCSIStatus;
2746
2747 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2748 status, pReply->SCSIState, scsi_status,
2749 le32_to_cpu(pReply->IOCLogInfo)));
2750
2751 switch(status) {
2752
2753 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2754 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2755 break;
2756
2757 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2758 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2759 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2760 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2761 completionCode = MPT_SCANDV_DID_RESET;
2762 break;
2763
2764 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2765 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2766 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2767 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2768 ConfigReply_t *pr = (ConfigReply_t *)mr;
2769 completionCode = MPT_SCANDV_GOOD;
2770 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2771 hd->pLocal->header.PageLength = pr->Header.PageLength;
2772 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2773 hd->pLocal->header.PageType = pr->Header.PageType;
2774
2775 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2776 /* If the RAID Volume request is successful,
2777 * return GOOD, else indicate that
2778 * some type of error occurred.
2779 */
2780 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002781 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 completionCode = MPT_SCANDV_GOOD;
2783 else
2784 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002785 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
2787 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2788 u8 *sense_data;
2789 int sz;
2790
2791 /* save sense data in global structure
2792 */
2793 completionCode = MPT_SCANDV_SENSE;
2794 hd->pLocal->scsiStatus = scsi_status;
2795 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2796 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2797
2798 sz = min_t(int, pReq->SenseBufferLength,
2799 SCSI_STD_SENSE_BYTES);
2800 memcpy(hd->pLocal->sense, sense_data, sz);
2801
2802 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2803 sense_data));
2804 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2805 if (pReq->CDB[0] == INQUIRY)
2806 completionCode = MPT_SCANDV_ISSUE_SENSE;
2807 else
2808 completionCode = MPT_SCANDV_DID_RESET;
2809 }
2810 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2811 completionCode = MPT_SCANDV_DID_RESET;
2812 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2813 completionCode = MPT_SCANDV_DID_RESET;
2814 else {
2815 completionCode = MPT_SCANDV_GOOD;
2816 hd->pLocal->scsiStatus = scsi_status;
2817 }
2818 break;
2819
2820 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2821 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2822 completionCode = MPT_SCANDV_DID_RESET;
2823 else
2824 completionCode = MPT_SCANDV_SOME_ERROR;
2825 break;
2826
2827 default:
2828 completionCode = MPT_SCANDV_SOME_ERROR;
2829 break;
2830
2831 } /* switch(status) */
2832
2833 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2834 completionCode));
2835 } /* end of address reply case */
2836
2837 hd->pLocal->completion = completionCode;
2838
2839 /* MF and RF are freed in mpt_interrupt
2840 */
2841wakeup:
2842 /* Free Chain buffers (will never chain) in scan or dv */
2843 //mptscsih_freeChainBuffers(ioc, req_idx);
2844
2845 /*
2846 * Wake up the original calling thread
2847 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002848 hd->scandv_wait_done = 1;
2849 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
2851 return 1;
2852}
2853
2854/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2855/* mptscsih_timer_expired - Call back for timer process.
2856 * Used only for dv functionality.
2857 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2858 *
2859 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002860void
2861mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
2863 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2864
2865 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2866
2867 if (hd->cmdPtr) {
2868 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2869
2870 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2871 /* Desire to issue a task management request here.
2872 * TM requests MUST be single threaded.
2873 * If old eh code and no TM current, issue request.
2874 * If new eh code, do nothing. Wait for OS cmd timeout
2875 * for bus reset.
2876 */
2877 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2878 } else {
2879 /* Perform a FW reload */
2880 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2881 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2882 }
2883 }
2884 } else {
2885 /* This should NEVER happen */
2886 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2887 }
2888
2889 /* No more processing.
2890 * TM call will generate an interrupt for SCSI TM Management.
2891 * The FW will reply to all outstanding commands, callback will finish cleanup.
2892 * Hard reset clean-up will free all resources.
2893 */
2894 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2895
2896 return;
2897}
2898
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
2900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2901/**
2902 * mptscsih_do_cmd - Do internal command.
2903 * @hd: MPT_SCSI_HOST pointer
2904 * @io: INTERNAL_CMD pointer.
2905 *
2906 * Issue the specified internally generated command and do command
2907 * specific cleanup. For bus scan / DV only.
2908 * NOTES: If command is Inquiry and status is good,
2909 * initialize a target structure, save the data
2910 *
2911 * Remark: Single threaded access only.
2912 *
2913 * Return:
2914 * < 0 if an illegal command or no resources
2915 *
2916 * 0 if good
2917 *
2918 * > 0 if command complete but some type of completion error.
2919 */
2920static int
2921mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2922{
2923 MPT_FRAME_HDR *mf;
2924 SCSIIORequest_t *pScsiReq;
2925 SCSIIORequest_t ReqCopy;
2926 int my_idx, ii, dir;
2927 int rc, cmdTimeout;
2928 int in_isr;
2929 char cmdLen;
2930 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2931 char cmd = io->cmd;
2932
2933 in_isr = in_interrupt();
2934 if (in_isr) {
2935 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2936 hd->ioc->name));
2937 return -EPERM;
2938 }
2939
2940
2941 /* Set command specific information
2942 */
2943 switch (cmd) {
2944 case INQUIRY:
2945 cmdLen = 6;
2946 dir = MPI_SCSIIO_CONTROL_READ;
2947 CDB[0] = cmd;
2948 CDB[4] = io->size;
2949 cmdTimeout = 10;
2950 break;
2951
2952 case TEST_UNIT_READY:
2953 cmdLen = 6;
2954 dir = MPI_SCSIIO_CONTROL_READ;
2955 cmdTimeout = 10;
2956 break;
2957
2958 case START_STOP:
2959 cmdLen = 6;
2960 dir = MPI_SCSIIO_CONTROL_READ;
2961 CDB[0] = cmd;
2962 CDB[4] = 1; /*Spin up the disk */
2963 cmdTimeout = 15;
2964 break;
2965
2966 case REQUEST_SENSE:
2967 cmdLen = 6;
2968 CDB[0] = cmd;
2969 CDB[4] = io->size;
2970 dir = MPI_SCSIIO_CONTROL_READ;
2971 cmdTimeout = 10;
2972 break;
2973
2974 case READ_BUFFER:
2975 cmdLen = 10;
2976 dir = MPI_SCSIIO_CONTROL_READ;
2977 CDB[0] = cmd;
2978 if (io->flags & MPT_ICFLAG_ECHO) {
2979 CDB[1] = 0x0A;
2980 } else {
2981 CDB[1] = 0x02;
2982 }
2983
2984 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2985 CDB[1] |= 0x01;
2986 }
2987 CDB[6] = (io->size >> 16) & 0xFF;
2988 CDB[7] = (io->size >> 8) & 0xFF;
2989 CDB[8] = io->size & 0xFF;
2990 cmdTimeout = 10;
2991 break;
2992
2993 case WRITE_BUFFER:
2994 cmdLen = 10;
2995 dir = MPI_SCSIIO_CONTROL_WRITE;
2996 CDB[0] = cmd;
2997 if (io->flags & MPT_ICFLAG_ECHO) {
2998 CDB[1] = 0x0A;
2999 } else {
3000 CDB[1] = 0x02;
3001 }
3002 CDB[6] = (io->size >> 16) & 0xFF;
3003 CDB[7] = (io->size >> 8) & 0xFF;
3004 CDB[8] = io->size & 0xFF;
3005 cmdTimeout = 10;
3006 break;
3007
3008 case RESERVE:
3009 cmdLen = 6;
3010 dir = MPI_SCSIIO_CONTROL_READ;
3011 CDB[0] = cmd;
3012 cmdTimeout = 10;
3013 break;
3014
3015 case RELEASE:
3016 cmdLen = 6;
3017 dir = MPI_SCSIIO_CONTROL_READ;
3018 CDB[0] = cmd;
3019 cmdTimeout = 10;
3020 break;
3021
3022 case SYNCHRONIZE_CACHE:
3023 cmdLen = 10;
3024 dir = MPI_SCSIIO_CONTROL_READ;
3025 CDB[0] = cmd;
3026// CDB[1] = 0x02; /* set immediate bit */
3027 cmdTimeout = 10;
3028 break;
3029
3030 default:
3031 /* Error Case */
3032 return -EFAULT;
3033 }
3034
3035 /* Get and Populate a free Frame
3036 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003037 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3039 hd->ioc->name));
3040 return -EBUSY;
3041 }
3042
3043 pScsiReq = (SCSIIORequest_t *) mf;
3044
3045 /* Get the request index */
3046 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3047 ADD_INDEX_LOG(my_idx); /* for debug */
3048
3049 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3050 pScsiReq->TargetID = io->physDiskNum;
3051 pScsiReq->Bus = 0;
3052 pScsiReq->ChainOffset = 0;
3053 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3054 } else {
3055 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003056 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 pScsiReq->ChainOffset = 0;
3058 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3059 }
3060
3061 pScsiReq->CDBLength = cmdLen;
3062 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3063
3064 pScsiReq->Reserved = 0;
3065
3066 pScsiReq->MsgFlags = mpt_msg_flags();
3067 /* MsgContext set in mpt_get_msg_fram call */
3068
Eric Moore793955f2007-01-29 09:42:20 -07003069 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
3071 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3072 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3073 else
3074 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3075
3076 if (cmd == REQUEST_SENSE) {
3077 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3078 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3079 hd->ioc->name, cmd));
3080 }
3081
3082 for (ii=0; ii < 16; ii++)
3083 pScsiReq->CDB[ii] = CDB[ii];
3084
3085 pScsiReq->DataLength = cpu_to_le32(io->size);
3086 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3087 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3088
3089 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003090 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
3092 if (dir == MPI_SCSIIO_CONTROL_READ) {
3093 mpt_add_sge((char *) &pScsiReq->SGL,
3094 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3095 io->data_dma);
3096 } else {
3097 mpt_add_sge((char *) &pScsiReq->SGL,
3098 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3099 io->data_dma);
3100 }
3101
3102 /* The ISR will free the request frame, but we need
3103 * the information to initialize the target. Duplicate.
3104 */
3105 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3106
3107 /* Issue this command after:
3108 * finish init
3109 * add timer
3110 * Wait until the reply has been received
3111 * ScsiScanDvCtx callback function will
3112 * set hd->pLocal;
3113 * set scandv_wait_done and call wake_up
3114 */
3115 hd->pLocal = NULL;
3116 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003117 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118
3119 /* Save cmd pointer, for resource free if timeout or
3120 * FW reload occurs
3121 */
3122 hd->cmdPtr = mf;
3123
3124 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003125 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3126 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127
3128 if (hd->pLocal) {
3129 rc = hd->pLocal->completion;
3130 hd->pLocal->skip = 0;
3131
3132 /* Always set fatal error codes in some cases.
3133 */
3134 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3135 rc = -ENXIO;
3136 else if (rc == MPT_SCANDV_SOME_ERROR)
3137 rc = -rc;
3138 } else {
3139 rc = -EFAULT;
3140 /* This should never happen. */
3141 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3142 hd->ioc->name));
3143 }
3144
3145 return rc;
3146}
3147
3148/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3149/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003150 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3151 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003152 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003153 *
3154 * Uses the ISR, but with special processing.
3155 * MUST be single-threaded.
3156 *
3157 */
3158static void
3159mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3160{
3161 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Eric Moorecc78d302007-06-15 17:27:21 -06003163 /* Ignore hidden raid components, this is handled when the command
3164 * is sent to the volume
3165 */
3166 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3167 return;
3168
3169 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3170 !vdevice->configured_lun)
3171 return;
3172
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 /* Following parameters will not change
3174 * in this routine.
3175 */
3176 iocmd.cmd = SYNCHRONIZE_CACHE;
3177 iocmd.flags = 0;
3178 iocmd.physDiskNum = -1;
3179 iocmd.data = NULL;
3180 iocmd.data_dma = -1;
3181 iocmd.size = 0;
3182 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003183 iocmd.channel = vdevice->vtarget->channel;
3184 iocmd.id = vdevice->vtarget->id;
3185 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Eric Moorecc78d302007-06-15 17:27:21 -06003187 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188}
3189
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303190static ssize_t
3191mptscsih_version_fw_show(struct class_device *cdev, char *buf)
3192{
3193 struct Scsi_Host *host = class_to_shost(cdev);
3194 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3195 MPT_ADAPTER *ioc = hd->ioc;
3196
3197 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3198 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3199 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3200 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3201 ioc->facts.FWVersion.Word & 0x000000FF);
3202}
3203static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3204
3205static ssize_t
3206mptscsih_version_bios_show(struct class_device *cdev, char *buf)
3207{
3208 struct Scsi_Host *host = class_to_shost(cdev);
3209 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3210 MPT_ADAPTER *ioc = hd->ioc;
3211
3212 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3213 (ioc->biosVersion & 0xFF000000) >> 24,
3214 (ioc->biosVersion & 0x00FF0000) >> 16,
3215 (ioc->biosVersion & 0x0000FF00) >> 8,
3216 ioc->biosVersion & 0x000000FF);
3217}
3218static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3219
3220static ssize_t
3221mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
3222{
3223 struct Scsi_Host *host = class_to_shost(cdev);
3224 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3225 MPT_ADAPTER *ioc = hd->ioc;
3226
3227 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3228}
3229static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3230
3231static ssize_t
3232mptscsih_version_product_show(struct class_device *cdev, char *buf)
3233{
3234 struct Scsi_Host *host = class_to_shost(cdev);
3235 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3236 MPT_ADAPTER *ioc = hd->ioc;
3237
3238 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3239}
3240static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
3241 mptscsih_version_product_show, NULL);
3242
3243static ssize_t
3244mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
3245{
3246 struct Scsi_Host *host = class_to_shost(cdev);
3247 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3248 MPT_ADAPTER *ioc = hd->ioc;
3249
3250 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3251 ioc->nvdata_version_persistent);
3252}
3253static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3254 mptscsih_version_nvdata_persistent_show, NULL);
3255
3256static ssize_t
3257mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
3258{
3259 struct Scsi_Host *host = class_to_shost(cdev);
3260 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3261 MPT_ADAPTER *ioc = hd->ioc;
3262
3263 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3264}
3265static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3266 mptscsih_version_nvdata_default_show, NULL);
3267
3268static ssize_t
3269mptscsih_board_name_show(struct class_device *cdev, char *buf)
3270{
3271 struct Scsi_Host *host = class_to_shost(cdev);
3272 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3273 MPT_ADAPTER *ioc = hd->ioc;
3274
3275 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3276}
3277static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3278
3279static ssize_t
3280mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
3281{
3282 struct Scsi_Host *host = class_to_shost(cdev);
3283 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3284 MPT_ADAPTER *ioc = hd->ioc;
3285
3286 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3287}
3288static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
3289 mptscsih_board_assembly_show, NULL);
3290
3291static ssize_t
3292mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
3293{
3294 struct Scsi_Host *host = class_to_shost(cdev);
3295 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3296 MPT_ADAPTER *ioc = hd->ioc;
3297
3298 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3299}
3300static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
3301 mptscsih_board_tracer_show, NULL);
3302
3303static ssize_t
3304mptscsih_io_delay_show(struct class_device *cdev, char *buf)
3305{
3306 struct Scsi_Host *host = class_to_shost(cdev);
3307 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3308 MPT_ADAPTER *ioc = hd->ioc;
3309
3310 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3311}
3312static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
3313 mptscsih_io_delay_show, NULL);
3314
3315static ssize_t
3316mptscsih_device_delay_show(struct class_device *cdev, char *buf)
3317{
3318 struct Scsi_Host *host = class_to_shost(cdev);
3319 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3320 MPT_ADAPTER *ioc = hd->ioc;
3321
3322 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3323}
3324static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
3325 mptscsih_device_delay_show, NULL);
3326
3327struct class_device_attribute *mptscsih_host_attrs[] = {
3328 &class_device_attr_version_fw,
3329 &class_device_attr_version_bios,
3330 &class_device_attr_version_mpi,
3331 &class_device_attr_version_product,
3332 &class_device_attr_version_nvdata_persistent,
3333 &class_device_attr_version_nvdata_default,
3334 &class_device_attr_board_name,
3335 &class_device_attr_board_assembly,
3336 &class_device_attr_board_tracer,
3337 &class_device_attr_io_delay,
3338 &class_device_attr_device_delay,
3339 NULL,
3340};
3341EXPORT_SYMBOL(mptscsih_host_attrs);
3342
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003343EXPORT_SYMBOL(mptscsih_remove);
3344EXPORT_SYMBOL(mptscsih_shutdown);
3345#ifdef CONFIG_PM
3346EXPORT_SYMBOL(mptscsih_suspend);
3347EXPORT_SYMBOL(mptscsih_resume);
3348#endif
3349EXPORT_SYMBOL(mptscsih_proc_info);
3350EXPORT_SYMBOL(mptscsih_info);
3351EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003352EXPORT_SYMBOL(mptscsih_slave_destroy);
3353EXPORT_SYMBOL(mptscsih_slave_configure);
3354EXPORT_SYMBOL(mptscsih_abort);
3355EXPORT_SYMBOL(mptscsih_dev_reset);
3356EXPORT_SYMBOL(mptscsih_bus_reset);
3357EXPORT_SYMBOL(mptscsih_host_reset);
3358EXPORT_SYMBOL(mptscsih_bios_param);
3359EXPORT_SYMBOL(mptscsih_io_done);
3360EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3361EXPORT_SYMBOL(mptscsih_scandv_complete);
3362EXPORT_SYMBOL(mptscsih_event_process);
3363EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003364EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003365EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003366EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003368/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/