blob: f0456d26a4af84fef92640a1b9f8462cff661843 [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
450 if (ioc->bus_type == FC)
451 return;
452
453 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
454 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
455 ioc->name,__FUNCTION__));
456 return;
457 }
458
459 SEPMsg = (SEPRequest_t *)mf;
460 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700461 SEPMsg->Bus = vtarget->channel;
462 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600463 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
464 SEPMsg->SlotStatus = SlotStatus;
465 devtverboseprintk((MYIOC_s_WARN_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700466 "Sending SEP cmd=%x channel=%d id=%d\n",
467 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600468 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
469}
470
Eric Moorec6c727a2007-01-29 09:44:54 -0700471#ifdef MPT_DEBUG_REPLY
472/**
473 * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
474 * @ioc: Pointer to MPT_ADAPTER structure
475 * @ioc_status: U32 IOCStatus word from IOC
476 * @scsi_status: U8 sam status from target
477 * @scsi_state: U8 scsi state
478 * @sc: original scsi cmnd pointer
479 * @mf: Pointer to MPT request frame
480 *
481 * Refer to lsi/mpi.h.
482 **/
483static void
484mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
485 u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
486{
487 char extend_desc[EVENT_DESCR_STR_SZ];
488 char *desc = NULL;
489
490 switch (ioc_status) {
491
492 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
493 desc = "SCSI Invalid Bus";
494 break;
495
496 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
497 desc = "SCSI Invalid TargetID";
498 break;
499
500 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
501 /*
502 * Inquiry is issued for device scanning
503 */
504 if (sc->cmnd[0] != 0x12)
505 desc = "SCSI Device Not There";
506 break;
507
508 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
509 desc = "SCSI Data Overrun";
510 break;
511
512 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
513 desc = "SCSI I/O Data Error";
514 break;
515
516 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
517 desc = "SCSI Protocol Error";
518 break;
519
520 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
521 desc = "SCSI Task Terminated";
522 break;
523
524 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
525 desc = "SCSI Residual Mismatch";
526 break;
527
528 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
529 desc = "SCSI Task Management Failed";
530 break;
531
532 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
533 desc = "SCSI IOC Terminated";
534 break;
535
536 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
537 desc = "SCSI Ext Terminated";
538 break;
539 }
540
541 if (!desc)
542 return;
543
544 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
545 "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
546 sc->device->host->host_no,
547 sc->device->channel, sc->device->id, sc->device->lun,
548 sc->cmnd[0], scsi_status, scsi_state);
549
550 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
551 ioc->name, ioc_status, desc, extend_desc);
552}
553#endif
554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
556/*
557 * mptscsih_io_done - Main SCSI IO callback routine registered to
558 * Fusion MPT (base) driver
559 * @ioc: Pointer to MPT_ADAPTER structure
560 * @mf: Pointer to original MPT request frame
561 * @r: Pointer to MPT reply frame (NULL if TurboReply)
562 *
563 * This routine is called from mpt.c::mpt_interrupt() at the completion
564 * of any SCSI IO request.
565 * This routine is registered with the Fusion MPT (base) driver at driver
566 * load/init time via the mpt_register() API call.
567 *
568 * Returns 1 indicating alloc'd request frame ptr should be freed.
569 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400570int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
572{
573 struct scsi_cmnd *sc;
574 MPT_SCSI_HOST *hd;
575 SCSIIORequest_t *pScsiReq;
576 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700577 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600578 VirtDevice *vdev;
579 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
582
583 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700584 req_idx_MR = (mr != NULL) ?
585 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
586 if ((req_idx != req_idx_MR) ||
587 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
588 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
589 ioc->name);
590 printk (MYIOC_s_ERR_FMT
591 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
592 ioc->name, req_idx, req_idx_MR, mf, mr,
593 hd->ScsiLookup[req_idx_MR]);
594 return 0;
595 }
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600598 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 if (sc == NULL) {
600 MPIHeader_t *hdr = (MPIHeader_t *)mf;
601
602 /* Remark: writeSDP1 will use the ScsiDoneCtx
603 * If a SCSI I/O cmd, device disabled by OS and
604 * completion done. Cannot touch sc struct. Just free mem.
605 */
606 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
607 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
608 ioc->name);
609
610 mptscsih_freeChainBuffers(ioc, req_idx);
611 return 1;
612 }
613
Eric Moore3dc0b032006-07-11 17:32:33 -0600614 if ((unsigned char *)mf != sc->host_scribble) {
615 mptscsih_freeChainBuffers(ioc, req_idx);
616 return 1;
617 }
618
619 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 sc->result = DID_OK << 16; /* Set default reply as OK */
621 pScsiReq = (SCSIIORequest_t *) mf;
622 pScsiReply = (SCSIIOReply_t *) mr;
623
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200624 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
625 dmfprintk((MYIOC_s_INFO_FMT
626 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
627 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
628 }else{
629 dmfprintk((MYIOC_s_INFO_FMT
630 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
631 ioc->name, mf, mr, sc, req_idx));
632 }
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 if (pScsiReply == NULL) {
635 /* special context reply handling */
636 ;
637 } else {
638 u32 xfer_cnt;
639 u16 status;
640 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700641 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
644 scsi_state = pScsiReply->SCSIState;
645 scsi_status = pScsiReply->SCSIStatus;
646 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900647 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700648 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600650 /*
651 * if we get a data underrun indication, yet no data was
652 * transferred and the SCSI status indicates that the
653 * command was never started, change the data underrun
654 * to success
655 */
656 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
657 (scsi_status == MPI_SCSI_STATUS_BUSY ||
658 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
659 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
660 status = MPI_IOCSTATUS_SUCCESS;
661 }
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400664 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /*
667 * Look for + dump FCP ResponseInfo[]!
668 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600669 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
670 pScsiReply->ResponseInfo) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700671 printk(KERN_NOTICE "[%d:%d:%d:%d] "
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600672 "FCP_ResponseInfo=%08xh\n",
Eric Moorec6c727a2007-01-29 09:44:54 -0700673 sc->device->host->host_no, sc->device->channel,
674 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 le32_to_cpu(pScsiReply->ResponseInfo));
676 }
677
678 switch(status) {
679 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
680 /* CHECKME!
681 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
682 * But not: DID_BUS_BUSY lest one risk
683 * killing interrupt handler:-(
684 */
685 sc->result = SAM_STAT_BUSY;
686 break;
687
688 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
689 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
690 sc->result = DID_BAD_TARGET << 16;
691 break;
692
693 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
694 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600695 if (ioc->bus_type != FC)
696 sc->result = DID_NO_CONNECT << 16;
697 /* else fibre, just stall until rescan event */
698 else
699 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
702 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600703
704 vdev = sc->device->hostdata;
705 if (!vdev)
706 break;
707 vtarget = vdev->vtarget;
708 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
709 mptscsih_issue_sep_command(ioc, vtarget,
710 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
711 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 break;
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600716 if ( ioc->bus_type == SAS ) {
717 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
718 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700719 if ((log_info & SAS_LOGINFO_MASK)
720 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600721 sc->result = (DID_BUS_BUSY << 16);
722 break;
723 }
724 }
Eric Moore86dd4242007-01-04 20:44:01 -0700725 } else if (ioc->bus_type == FC) {
726 /*
727 * The FC IOC may kill a request for variety of
728 * reasons, some of which may be recovered by a
729 * retry, some which are unlikely to be
730 * recovered. Return DID_ERROR instead of
731 * DID_RESET to permit retry of the command,
732 * just not an infinite number of them
733 */
734 sc->result = DID_ERROR << 16;
735 break;
Eric Moorebf451522006-07-11 17:25:35 -0600736 }
737
738 /*
739 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
740 */
741
742 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
744 /* Linux handles an unsolicited DID_RESET better
745 * than an unsolicited DID_ABORT.
746 */
747 sc->result = DID_RESET << 16;
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 break;
750
751 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900752 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600753 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
754 sc->result=DID_SOFT_ERROR << 16;
755 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600757 dreplyprintk((KERN_NOTICE
Eric Moorec6c727a2007-01-29 09:44:54 -0700758 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
759 sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
763 /*
764 * Do upfront check for valid SenseData and give it
765 * precedence!
766 */
767 sc->result = (DID_OK << 16) | scsi_status;
768 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
769 /* Have already saved the status and sense data
770 */
771 ;
772 } else {
773 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600774 if (scsi_status == SAM_STAT_BUSY)
775 sc->result = SAM_STAT_BUSY;
776 else
777 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
779 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
780 /* What to do?
781 */
782 sc->result = DID_SOFT_ERROR << 16;
783 }
784 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
785 /* Not real sure here either... */
786 sc->result = DID_RESET << 16;
787 }
788 }
789
790 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
791 sc->underflow));
792 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
793 /* Report Queue Full
794 */
795 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
796 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 break;
799
Moore, Eric7e551472006-01-16 18:53:21 -0700800 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900801 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
803 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600804 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (scsi_state == 0) {
806 ;
807 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
808 /*
809 * If running against circa 200003dd 909 MPT f/w,
810 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
811 * (QUEUE_FULL) returned from device! --> get 0x0000?128
812 * and with SenseBytes set to 0.
813 */
814 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
815 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
816
817 }
818 else if (scsi_state &
819 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
820 ) {
821 /*
822 * What to do?
823 */
824 sc->result = DID_SOFT_ERROR << 16;
825 }
826 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
827 /* Not real sure here either... */
828 sc->result = DID_RESET << 16;
829 }
830 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
831 /* Device Inq. data indicates that it supports
832 * QTags, but rejects QTag messages.
833 * This command completed OK.
834 *
835 * Not real sure here either so do nothing... */
836 }
837
838 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
839 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
840
841 /* Add handling of:
842 * Reservation Conflict, Busy,
843 * Command Terminated, CHECK
844 */
845 break;
846
847 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
848 sc->result = DID_SOFT_ERROR << 16;
849 break;
850
851 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
852 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
853 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
854 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
855 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
856 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
857 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
859 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
860 default:
861 /*
862 * What to do?
863 */
864 sc->result = DID_SOFT_ERROR << 16;
865 break;
866
867 } /* switch(status) */
868
Eric Moorec6c727a2007-01-29 09:44:54 -0700869#ifdef MPT_DEBUG_REPLY
870 if (sc->result) {
871
872 mptscsih_iocstatus_info_scsiio(ioc, status,
873 scsi_status, scsi_state, sc);
874
875 dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
876 "result=0x%08x\n\tiocstatus=0x%04X "
877 "scsi_state=0x%02X scsi_status=0x%02X "
878 "loginfo=0x%08X\n", __FUNCTION__,
879 sc->device->host->host_no, sc->device->channel, sc->device->id,
880 sc->device->lun, sc->cmnd[0], sc->result, status,
881 scsi_state, scsi_status, log_info));
882
883 dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900884 "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
885 sc->device->host->host_no,
886 sc->device->channel, sc->device->id,
887 sc->device->lun, scsi_get_resid(sc),
888 scsi_bufflen(sc), xfer_cnt));
Eric Moorec6c727a2007-01-29 09:44:54 -0700889 }
890#endif
891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 } /* end of address reply case */
893
894 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900895 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 sc->scsi_done(sc); /* Issue the command callback */
898
899 /* Free Chain buffers */
900 mptscsih_freeChainBuffers(ioc, req_idx);
901 return 1;
902}
903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904/*
905 * mptscsih_flush_running_cmds - For each command found, search
906 * Scsi_Host instance taskQ and reply to OS.
907 * Called only if recovering from a FW reload.
908 * @hd: Pointer to a SCSI HOST structure
909 *
910 * Returns: None.
911 *
912 * Must be called while new I/Os are being queued.
913 */
914static void
915mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
916{
917 MPT_ADAPTER *ioc = hd->ioc;
918 struct scsi_cmnd *SCpnt;
919 MPT_FRAME_HDR *mf;
920 int ii;
921 int max = ioc->req_depth;
922
923 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
924 for (ii= 0; ii < max; ii++) {
925 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
926
927 /* Command found.
928 */
929
930 /* Null ScsiLookup index
931 */
932 hd->ScsiLookup[ii] = NULL;
933
934 mf = MPT_INDEX_2_MFPTR(ioc, ii);
935 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
936 mf, SCpnt));
937
Eric Moore3dc0b032006-07-11 17:32:33 -0600938 /* Free Chain buffers */
939 mptscsih_freeChainBuffers(ioc, ii);
940
941 /* Free Message frames */
942 mpt_free_msg_frame(ioc, mf);
943
944 if ((unsigned char *)mf != SCpnt->host_scribble)
945 continue;
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* Set status, free OS resources (SG DMA buffers)
948 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900950 scsi_dma_unmap(SCpnt);
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 SCpnt->result = DID_RESET << 16;
953 SCpnt->host_scribble = NULL;
954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
956 }
957 }
958
959 return;
960}
961
962/*
963 * mptscsih_search_running_cmds - Delete any commands associated
964 * with the specified target and lun. Function called only
965 * when a lun is disable by mid-layer.
966 * Do NOT access the referenced scsi_cmnd structure or
967 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600968 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700969 * @hd: Pointer to a SCSI HOST structure
970 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 *
972 * Returns: None.
973 *
974 * Called from slave_destroy.
975 */
976static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700977mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978{
979 SCSIIORequest_t *mf = NULL;
980 int ii;
981 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600982 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700983 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Eric Moore793955f2007-01-29 09:42:20 -0700985 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
986 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600989 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600992 if (mf == NULL)
993 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700994 int_to_scsilun(vdevice->lun, &lun);
995 if ((mf->Bus != vdevice->vtarget->channel) ||
996 (mf->TargetID != vdevice->vtarget->id) ||
997 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700999 dsprintk(( "search_running: found (sc=%p, mf = %p) "
1000 "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
1001 mf, mf->Bus, mf->TargetID, vdevice->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 /* Cleanup
1004 */
1005 hd->ScsiLookup[ii] = NULL;
1006 mptscsih_freeChainBuffers(hd->ioc, ii);
1007 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001008 if ((unsigned char *)mf != sc->host_scribble)
1009 continue;
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001010 scsi_dma_unmap(sc);
1011
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001012 sc->host_scribble = NULL;
1013 sc->result = DID_NO_CONNECT << 16;
1014 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 }
1016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return;
1018}
1019
1020/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1023/*
1024 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1025 * from a SCSI target device.
1026 * @sc: Pointer to scsi_cmnd structure
1027 * @pScsiReply: Pointer to SCSIIOReply_t
1028 * @pScsiReq: Pointer to original SCSI request
1029 *
1030 * This routine periodically reports QUEUE_FULL status returned from a
1031 * SCSI target device. It reports this to the console via kernel
1032 * printk() API call, not more than once every 10 seconds.
1033 */
1034static void
1035mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1036{
1037 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001040 if (sc->device == NULL)
1041 return;
1042 if (sc->device->host == NULL)
1043 return;
1044 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1045 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001047 if (time - hd->last_queue_full > 10 * HZ) {
1048 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1049 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1050 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052}
1053
1054/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1055/*
1056 * mptscsih_remove - Removed scsi devices
1057 * @pdev: Pointer to pci_dev structure
1058 *
1059 *
1060 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001061void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062mptscsih_remove(struct pci_dev *pdev)
1063{
1064 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1065 struct Scsi_Host *host = ioc->sh;
1066 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001067 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001069 if(!host) {
1070 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001072 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
1074 scsi_remove_host(host);
1075
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001076 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1077 return;
1078
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001079 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001081 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001083 if (hd->ScsiLookup != NULL) {
1084 sz1 = hd->ioc->req_depth * sizeof(void *);
1085 kfree(hd->ScsiLookup);
1086 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001089 dprintk((MYIOC_s_INFO_FMT
1090 "Free'd ScsiLookup (%d) memory\n",
1091 hd->ioc->name, sz1));
1092
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001093 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001094
1095 /* NULL the Scsi_Host pointer
1096 */
1097 hd->ioc->sh = NULL;
1098
1099 scsi_host_put(host);
1100
1101 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103}
1104
1105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1106/*
1107 * mptscsih_shutdown - reboot notifier
1108 *
1109 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001110void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001111mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001113 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 struct Scsi_Host *host = ioc->sh;
1115 MPT_SCSI_HOST *hd;
1116
1117 if(!host)
1118 return;
1119
1120 hd = (MPT_SCSI_HOST *)host->hostdata;
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
1123
1124#ifdef CONFIG_PM
1125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1126/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001127 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 *
1129 *
1130 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001131int
Pavel Machek8d189f72005-04-16 15:25:28 -07001132mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001134 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001135 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136}
1137
1138/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1139/*
1140 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1141 *
1142 *
1143 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001144int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145mptscsih_resume(struct pci_dev *pdev)
1146{
Hormsb364fd52007-03-19 15:06:44 +09001147 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148}
1149
1150#endif
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1153/**
1154 * mptscsih_info - Return information about MPT adapter
1155 * @SChost: Pointer to Scsi_Host structure
1156 *
1157 * (linux scsi_host_template.info routine)
1158 *
1159 * Returns pointer to buffer where information was written.
1160 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001161const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162mptscsih_info(struct Scsi_Host *SChost)
1163{
1164 MPT_SCSI_HOST *h;
1165 int size = 0;
1166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001170 if (h->info_kbuf == NULL)
1171 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1172 return h->info_kbuf;
1173 h->info_kbuf[0] = '\0';
1174
1175 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1176 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
1178
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001179 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180}
1181
1182struct info_str {
1183 char *buffer;
1184 int length;
1185 int offset;
1186 int pos;
1187};
1188
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001189static void
1190mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191{
1192 if (info->pos + len > info->length)
1193 len = info->length - info->pos;
1194
1195 if (info->pos + len < info->offset) {
1196 info->pos += len;
1197 return;
1198 }
1199
1200 if (info->pos < info->offset) {
1201 data += (info->offset - info->pos);
1202 len -= (info->offset - info->pos);
1203 }
1204
1205 if (len > 0) {
1206 memcpy(info->buffer + info->pos, data, len);
1207 info->pos += len;
1208 }
1209}
1210
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211static int
1212mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 va_list args;
1215 char buf[81];
1216 int len;
1217
1218 va_start(args, fmt);
1219 len = vsprintf(buf, fmt, args);
1220 va_end(args);
1221
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001222 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 return len;
1224}
1225
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001226static int
1227mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
1229 struct info_str info;
1230
1231 info.buffer = pbuf;
1232 info.length = len;
1233 info.offset = offset;
1234 info.pos = 0;
1235
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001236 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1237 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1238 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1239 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1242}
1243
1244/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1245/**
1246 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001247 * @host: scsi host struct
1248 * @buffer: if write, user data; if read, buffer for user
1249 * @start: returns the buffer address
1250 * @offset: if write, 0; if read, the current offset into the buffer from
1251 * the previous read.
1252 * @length: if write, return length;
1253 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 *
1255 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001257int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1259 int length, int func)
1260{
1261 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1262 MPT_ADAPTER *ioc = hd->ioc;
1263 int size = 0;
1264
1265 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001266 /*
1267 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 */
1269 } else {
1270 if (start)
1271 *start = buffer;
1272
1273 size = mptscsih_host_info(ioc, buffer, offset, length);
1274 }
1275
1276 return size;
1277}
1278
1279/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1280#define ADD_INDEX_LOG(req_ent) do { } while(0)
1281
1282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1283/**
1284 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1285 * @SCpnt: Pointer to scsi_cmnd structure
1286 * @done: Pointer SCSI mid-layer IO completion function
1287 *
1288 * (linux scsi_host_template.queuecommand routine)
1289 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1290 * from a linux scsi_cmnd request and send it to the IOC.
1291 *
1292 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1293 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001294int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1296{
1297 MPT_SCSI_HOST *hd;
1298 MPT_FRAME_HDR *mf;
1299 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001300 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 int lun;
1302 u32 datalen;
1303 u32 scsictl;
1304 u32 scsidir;
1305 u32 cmd_len;
1306 int my_idx;
1307 int ii;
1308
1309 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 lun = SCpnt->device->lun;
1311 SCpnt->scsi_done = done;
1312
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1314 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1315
1316 if (hd->resetPending) {
1317 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1318 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1319 return SCSI_MLQUEUE_HOST_BUSY;
1320 }
1321
1322 /*
1323 * Put together a MPT SCSI request...
1324 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001325 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1327 hd->ioc->name));
1328 return SCSI_MLQUEUE_HOST_BUSY;
1329 }
1330
1331 pScsiReq = (SCSIIORequest_t *) mf;
1332
1333 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1334
1335 ADD_INDEX_LOG(my_idx);
1336
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001337 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 * Seems we may receive a buffer (datalen>0) even when there
1339 * will be no data transfer! GRRRRR...
1340 */
1341 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001342 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1344 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001345 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1347 } else {
1348 datalen = 0;
1349 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1350 }
1351
1352 /* Default to untagged. Once a target structure has been allocated,
1353 * use the Inquiry data to determine if device supports tagged.
1354 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001355 if (vdev
1356 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 && (SCpnt->device->tagged_supported)) {
1358 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1359 } else {
1360 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1361 }
1362
1363 /* Use the above information to set up the message frame
1364 */
Eric Moore793955f2007-01-29 09:42:20 -07001365 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1366 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001368 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1369 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1370 else
1371 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 pScsiReq->CDBLength = SCpnt->cmd_len;
1373 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1374 pScsiReq->Reserved = 0;
1375 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001376 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 pScsiReq->Control = cpu_to_le32(scsictl);
1378
1379 /*
1380 * Write SCSI CDB into the message
1381 */
1382 cmd_len = SCpnt->cmd_len;
1383 for (ii=0; ii < cmd_len; ii++)
1384 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1385
1386 for (ii=cmd_len; ii < 16; ii++)
1387 pScsiReq->CDB[ii] = 0;
1388
1389 /* DataLength */
1390 pScsiReq->DataLength = cpu_to_le32(datalen);
1391
1392 /* SenseBuffer low address */
1393 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1394 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1395
1396 /* Now add the SG list
1397 * Always have a SGE even if null length.
1398 */
1399 if (datalen == 0) {
1400 /* Add a NULL SGE */
1401 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1402 (dma_addr_t) -1);
1403 } else {
1404 /* Add a 32 or 64 bit SGE */
1405 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1406 goto fail;
1407 }
1408
Eric Moore3dc0b032006-07-11 17:32:33 -06001409 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001412 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1414 hd->ioc->name, SCpnt, mf, my_idx));
1415 DBG_DUMP_REQUEST_FRAME(mf)
1416 return 0;
1417
1418 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001419 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1421 mpt_free_msg_frame(hd->ioc, mf);
1422 return SCSI_MLQUEUE_HOST_BUSY;
1423}
1424
1425/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1426/*
1427 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1428 * with a SCSI IO request
1429 * @hd: Pointer to the MPT_SCSI_HOST instance
1430 * @req_idx: Index of the SCSI IO request frame.
1431 *
1432 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1433 * No return.
1434 */
1435static void
1436mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1437{
1438 MPT_FRAME_HDR *chain;
1439 unsigned long flags;
1440 int chain_idx;
1441 int next;
1442
1443 /* Get the first chain index and reset
1444 * tracker state.
1445 */
1446 chain_idx = ioc->ReqToChain[req_idx];
1447 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1448
1449 while (chain_idx != MPT_HOST_NO_CHAIN) {
1450
1451 /* Save the next chain buffer index */
1452 next = ioc->ChainToChain[chain_idx];
1453
1454 /* Free this chain buffer and reset
1455 * tracker
1456 */
1457 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1458
1459 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1460 + (chain_idx * ioc->req_sz));
1461
1462 spin_lock_irqsave(&ioc->FreeQlock, flags);
1463 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1464 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1465
1466 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1467 ioc->name, chain_idx));
1468
1469 /* handle next */
1470 chain_idx = next;
1471 }
1472 return;
1473}
1474
1475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1476/*
1477 * Reset Handling
1478 */
1479
1480/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001481/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001483 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001485 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001486 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 * @lun: Logical Unit for reset (if appropriate)
1488 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001489 * @timeout: timeout for task management control
1490 *
1491 * Fall through to mpt_HardResetHandler if: not operational, too many
1492 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 *
1494 * Remark: Currently invoked from a non-interrupt thread (_bh).
1495 *
1496 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1497 * will be active.
1498 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001499 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001500 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001501int
Eric Moore793955f2007-01-29 09:42:20 -07001502mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503{
1504 MPT_ADAPTER *ioc;
1505 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 u32 ioc_raw_state;
1507 unsigned long flags;
1508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1511
1512 // SJR - CHECKME - Can we avoid this here?
1513 // (mpt_HardResetHandler has this check...)
1514 spin_lock_irqsave(&ioc->diagLock, flags);
1515 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1516 spin_unlock_irqrestore(&ioc->diagLock, flags);
1517 return FAILED;
1518 }
1519 spin_unlock_irqrestore(&ioc->diagLock, flags);
1520
1521 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001522 * If we time out and not bus reset, then we return a FAILED status
1523 * to the caller.
1524 * The call to mptscsih_tm_pending_wait() will set the pending flag
1525 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 * successful. Otherwise, reload the FW.
1527 */
1528 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1529 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001530 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 "Timed out waiting for last TM (%d) to complete! \n",
1532 hd->ioc->name, hd->tmPending));
1533 return FAILED;
1534 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001535 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1536 "reset: Timed out waiting for last TM (%d) "
1537 "to complete! \n", hd->ioc->name,
1538 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 return FAILED;
1540 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001541 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 "Timed out waiting for last TM (%d) to complete! \n",
1543 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001544 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 }
1546 } else {
1547 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1548 hd->tmPending |= (1 << type);
1549 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1550 }
1551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1553
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1555 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001556 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1557 ioc->name, type, ioc_raw_state);
1558 printk(KERN_WARNING " Issuing HardReset!!\n");
1559 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1560 printk((KERN_WARNING "TMHandler: HardReset "
1561 "FAILED!!\n"));
1562 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 }
1564
Eric Moorecd2c6192007-01-29 09:47:47 -07001565 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1566 printk(MYIOC_s_WARN_FMT
1567 "TM Handler for type=%x: ioc_state: "
1568 "DOORBELL_ACTIVE (0x%x)!\n",
1569 ioc->name, type, ioc_raw_state);
1570 return FAILED;
1571 }
1572
1573 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001575 if (hd->hard_resets < -1)
1576 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
Eric Moorecd2c6192007-01-29 09:47:47 -07001578 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1579 ctx2abort, timeout);
1580 if (rc)
1581 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1582 hd->ioc->name);
1583 else
1584 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1585 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1588
1589 return rc;
1590}
1591
1592
1593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001594/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1596 * @hd: Pointer to MPT_SCSI_HOST structure
1597 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001598 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001599 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 * @lun: Logical Unit for reset (if appropriate)
1601 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001602 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 *
1604 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1605 * or a non-interrupt thread. In the former, must not call schedule().
1606 *
1607 * Not all fields are meaningfull for all task types.
1608 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001609 * Returns 0 for SUCCESS, or FAILED.
1610 *
1611 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612static int
Eric Moore793955f2007-01-29 09:42:20 -07001613mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614{
1615 MPT_FRAME_HDR *mf;
1616 SCSITaskMgmt_t *pScsiTm;
1617 int ii;
1618 int retval;
1619
1620 /* Return Fail to calling function if no message frames available.
1621 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001622 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1624 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001625 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
1627 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1628 hd->ioc->name, mf));
1629
1630 /* Format the Request
1631 */
1632 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001633 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 pScsiTm->Bus = channel;
1635 pScsiTm->ChainOffset = 0;
1636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1637
1638 pScsiTm->Reserved = 0;
1639 pScsiTm->TaskType = type;
1640 pScsiTm->Reserved1 = 0;
1641 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1642 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1643
Eric Moore793955f2007-01-29 09:42:20 -07001644 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 for (ii=0; ii < 7; ii++)
1647 pScsiTm->Reserved2[ii] = 0;
1648
1649 pScsiTm->TaskMsgContext = ctx2abort;
1650
Eric Moorecd2c6192007-01-29 09:47:47 -07001651 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1652 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1655
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001656 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001657 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1658 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1659 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1660 hd->ioc, mf, retval));
1661 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 }
1663
1664 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001665 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1667 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1669 hd->ioc->name));
1670 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001671 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1672 hd->ioc->name, retval));
1673 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
1675
Eric Moorecd2c6192007-01-29 09:47:47 -07001676 /*
1677 * Handle success case, see if theres a non-zero ioc_status.
1678 */
1679 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1680 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1681 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1682 retval = 0;
1683 else
1684 retval = FAILED;
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001687
1688 fail_out:
1689
1690 /*
1691 * Free task managment mf, and corresponding tm flags
1692 */
1693 mpt_free_msg_frame(hd->ioc, mf);
1694 hd->tmPending = 0;
1695 hd->tmState = TM_STATE_NONE;
1696 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697}
1698
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001699static int
1700mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1701{
1702 switch (ioc->bus_type) {
1703 case FC:
1704 return 40;
1705 case SAS:
1706 return 10;
1707 case SPI:
1708 default:
1709 return 2;
1710 }
1711}
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1714/**
1715 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1716 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1717 *
1718 * (linux scsi_host_template.eh_abort_handler routine)
1719 *
1720 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001721 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001722int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723mptscsih_abort(struct scsi_cmnd * SCpnt)
1724{
1725 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 MPT_FRAME_HDR *mf;
1727 u32 ctx2abort;
1728 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001729 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001730 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001731 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001732 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
1734 /* If we can't locate our host adapter structure, return FAILED status.
1735 */
1736 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1737 SCpnt->result = DID_RESET << 16;
1738 SCpnt->scsi_done(SCpnt);
Eric Moore958d4a32007-06-15 17:24:14 -06001739 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
1740 "host! (sc=%p)\n", SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 return FAILED;
1742 }
1743
Eric Moore958d4a32007-06-15 17:24:14 -06001744 ioc = hd->ioc;
1745 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1746 ioc->name, SCpnt);
1747 scsi_print_command(SCpnt);
1748
1749 vdevice = SCpnt->device->hostdata;
1750 if (!vdevice || !vdevice->vtarget) {
1751 dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
1752 "deleted (sc=%p)\n", ioc->name, SCpnt));
1753 SCpnt->result = DID_NO_CONNECT << 16;
1754 SCpnt->scsi_done(SCpnt);
1755 retval = 0;
1756 goto out;
1757 }
1758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 /* Find this command
1760 */
1761 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001762 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 * Do OS callback.
1764 */
1765 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001766 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001767 "Command not in the active list! (sc=%p)\n", ioc->name,
1768 SCpnt));
1769 retval = 0;
1770 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
1772
Eric Moore958d4a32007-06-15 17:24:14 -06001773 if (hd->resetPending) {
1774 retval = FAILED;
1775 goto out;
1776 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001777
1778 if (hd->timeouts < -1)
1779 hd->timeouts++;
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1782 * (the IO to be ABORT'd)
1783 *
1784 * NOTE: Since we do not byteswap MsgContext, we do not
1785 * swap it here either. It is an opaque cookie to
1786 * the controller, so it does not matter. -DaveM
1787 */
1788 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1789 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1790
1791 hd->abortSCpnt = SCpnt;
1792
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001793 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001794 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1795 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Eric Moore3dc0b032006-07-11 17:32:33 -06001797 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001798 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001799 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001800
Eric Moore958d4a32007-06-15 17:24:14 -06001801 out:
1802 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1803 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001805 if (retval == 0)
1806 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001807 else
1808 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809}
1810
1811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1812/**
1813 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1814 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1815 *
1816 * (linux scsi_host_template.eh_dev_reset_handler routine)
1817 *
1818 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001819 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001820int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1822{
1823 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001824 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001825 VirtDevice *vdevice;
1826 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
1828 /* If we can't locate our host adapter structure, return FAILED status.
1829 */
1830 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore958d4a32007-06-15 17:24:14 -06001831 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
1832 "locate host! (sc=%p)\n", SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 return FAILED;
1834 }
1835
Eric Moore958d4a32007-06-15 17:24:14 -06001836 ioc = hd->ioc;
1837 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1838 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001839 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
Eric Moore958d4a32007-06-15 17:24:14 -06001841 if (hd->resetPending) {
1842 retval = FAILED;
1843 goto out;
1844 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001845
Eric Moore958d4a32007-06-15 17:24:14 -06001846 vdevice = SCpnt->device->hostdata;
1847 if (!vdevice || !vdevice->vtarget) {
1848 retval = 0;
1849 goto out;
1850 }
1851
1852 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1853 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1854 mptscsih_get_tm_timeout(ioc));
1855
1856 out:
1857 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1858 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001859
1860 if (retval == 0)
1861 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001862 else
1863 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864}
1865
Eric Moorecd2c6192007-01-29 09:47:47 -07001866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1868/**
1869 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1870 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1871 *
1872 * (linux scsi_host_template.eh_bus_reset_handler routine)
1873 *
1874 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001875 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001876int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1878{
1879 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001880 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001881 VirtDevice *vdev;
Eric Moore958d4a32007-06-15 17:24:14 -06001882 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
1884 /* If we can't locate our host adapter structure, return FAILED status.
1885 */
1886 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore958d4a32007-06-15 17:24:14 -06001887 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
1888 "locate host! (sc=%p)\n", SCpnt ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 return FAILED;
1890 }
1891
Eric Moore958d4a32007-06-15 17:24:14 -06001892 ioc = hd->ioc;
1893 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1894 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001895 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 if (hd->timeouts < -1)
1898 hd->timeouts++;
1899
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001900 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001901 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore958d4a32007-06-15 17:24:14 -06001902 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
Eric Moore958d4a32007-06-15 17:24:14 -06001904 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1905 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001906
1907 if (retval == 0)
1908 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001909 else
1910 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911}
1912
1913/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1914/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001915 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1917 *
1918 * (linux scsi_host_template.eh_host_reset_handler routine)
1919 *
1920 * Returns SUCCESS or FAILED.
1921 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001922int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1924{
1925 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001926 int retval;
1927 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
1929 /* If we can't locate the host to reset, then we failed. */
1930 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore958d4a32007-06-15 17:24:14 -06001931 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
1932 "locate host! (sc=%p)\n", SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 return FAILED;
1934 }
1935
Eric Moore958d4a32007-06-15 17:24:14 -06001936 ioc = hd->ioc;
1937 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1938 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
1940 /* If our attempts to reset the host failed, then return a failed
1941 * status. The host will be taken off line by the SCSI mid-layer.
1942 */
Eric Moore958d4a32007-06-15 17:24:14 -06001943 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
1944 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 } else {
1946 /* Make sure TM pending is cleared and TM state is set to
1947 * NONE.
1948 */
Eric Moore958d4a32007-06-15 17:24:14 -06001949 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 hd->tmPending = 0;
1951 hd->tmState = TM_STATE_NONE;
1952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
Eric Moore958d4a32007-06-15 17:24:14 -06001954 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1955 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Eric Moore958d4a32007-06-15 17:24:14 -06001957 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958}
1959
1960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1961/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001962 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 * @hd: Pointer to MPT host structure.
1964 *
1965 * Returns {SUCCESS,FAILED}.
1966 */
1967static int
1968mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1969{
1970 unsigned long flags;
1971 int loop_count = 4 * 10; /* Wait 10 seconds */
1972 int status = FAILED;
1973
1974 do {
1975 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1976 if (hd->tmState == TM_STATE_NONE) {
1977 hd->tmState = TM_STATE_IN_PROGRESS;
1978 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001980 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 break;
1982 }
1983 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1984 msleep(250);
1985 } while (--loop_count);
1986
1987 return status;
1988}
1989
1990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1991/**
1992 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1993 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08001994 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 *
1996 * Returns {SUCCESS,FAILED}.
1997 */
1998static int
1999mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2000{
2001 unsigned long flags;
2002 int loop_count = 4 * timeout;
2003 int status = FAILED;
2004
2005 do {
2006 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2007 if(hd->tmPending == 0) {
2008 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002009 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 break;
2011 }
2012 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002013 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 } while (--loop_count);
2015
2016 return status;
2017}
2018
2019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002020static void
2021mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2022{
2023 char *desc;
2024
2025 switch (response_code) {
2026 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2027 desc = "The task completed.";
2028 break;
2029 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2030 desc = "The IOC received an invalid frame status.";
2031 break;
2032 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2033 desc = "The task type is not supported.";
2034 break;
2035 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2036 desc = "The requested task failed.";
2037 break;
2038 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2039 desc = "The task completed successfully.";
2040 break;
2041 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2042 desc = "The LUN request is invalid.";
2043 break;
2044 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2045 desc = "The task is in the IOC queue and has not been sent to target.";
2046 break;
2047 default:
2048 desc = "unknown";
2049 break;
2050 }
2051 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2052 ioc->name, response_code, desc);
2053}
2054
2055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056/**
2057 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2058 * @ioc: Pointer to MPT_ADAPTER structure
2059 * @mf: Pointer to SCSI task mgmt request frame
2060 * @mr: Pointer to SCSI task mgmt reply frame
2061 *
2062 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2063 * of any SCSI task management request.
2064 * This routine is registered with the MPT (base) driver at driver
2065 * load/init time via the mpt_register() API call.
2066 *
2067 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002068 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002069int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2071{
2072 SCSITaskMgmtReply_t *pScsiTmReply;
2073 SCSITaskMgmt_t *pScsiTmReq;
2074 MPT_SCSI_HOST *hd;
2075 unsigned long flags;
2076 u16 iocstatus;
2077 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002078 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002081 ioc->name, mf, mr));
2082 if (!ioc->sh) {
2083 dtmprintk((MYIOC_s_WARN_FMT
2084 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 return 1;
2086 }
2087
2088 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002089 dtmprintk((MYIOC_s_WARN_FMT
2090 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 }
2093
Eric Moorecd2c6192007-01-29 09:47:47 -07002094 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2095 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2096 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2097 tmType = pScsiTmReq->TaskType;
2098 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2099 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2100
2101 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2102 pScsiTmReply->ResponseCode)
2103 mptscsih_taskmgmt_response_code(ioc,
2104 pScsiTmReply->ResponseCode);
2105 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2106
2107#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2108 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2109 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2110 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2111 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2112 le16_to_cpu(pScsiTmReply->IOCStatus),
2113 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2114 le32_to_cpu(pScsiTmReply->TerminationCount));
2115#endif
2116 if (!iocstatus) {
2117 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2118 hd->abortSCpnt = NULL;
2119 goto out;
2120 }
2121
2122 /* Error? (anything non-zero?) */
2123
2124 /* clear flags and continue.
2125 */
2126 switch (tmType) {
2127
2128 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2129 if (termination_count == 1)
2130 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2131 hd->abortSCpnt = NULL;
2132 break;
2133
2134 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2135
2136 /* If an internal command is present
2137 * or the TM failed - reload the FW.
2138 * FC FW may respond FAILED to an ABORT
2139 */
2140 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2141 hd->cmdPtr)
2142 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2143 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2144 break;
2145
2146 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2147 default:
2148 break;
2149 }
2150
2151 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 spin_lock_irqsave(&ioc->FreeQlock, flags);
2153 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002155 hd->tm_iocstatus = iocstatus;
2156 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
2158 return 1;
2159}
2160
2161/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2162/*
2163 * This is anyones guess quite frankly.
2164 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002165int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2167 sector_t capacity, int geom[])
2168{
2169 int heads;
2170 int sectors;
2171 sector_t cylinders;
2172 ulong dummy;
2173
2174 heads = 64;
2175 sectors = 32;
2176
2177 dummy = heads * sectors;
2178 cylinders = capacity;
2179 sector_div(cylinders,dummy);
2180
2181 /*
2182 * Handle extended translation size for logical drives
2183 * > 1Gb
2184 */
2185 if ((ulong)capacity >= 0x200000) {
2186 heads = 255;
2187 sectors = 63;
2188 dummy = heads * sectors;
2189 cylinders = capacity;
2190 sector_div(cylinders,dummy);
2191 }
2192
2193 /* return result */
2194 geom[0] = heads;
2195 geom[1] = sectors;
2196 geom[2] = cylinders;
2197
2198 dprintk((KERN_NOTICE
2199 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002200 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 return 0;
2203}
2204
Moore, Ericf44e5462006-03-14 09:14:21 -07002205/* Search IOC page 3 to determine if this is hidden physical disk
2206 *
2207 */
2208int
Eric Moore793955f2007-01-29 09:42:20 -07002209mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002210{
Eric Mooreb506ade2007-01-29 09:45:37 -07002211 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002212 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002213 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002214
Eric Moore793955f2007-01-29 09:42:20 -07002215 if (!ioc->raid_data.pIocPg3)
2216 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002217 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002218 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2219 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2220 rc = 1;
2221 goto out;
2222 }
2223 }
2224
Eric Mooreb506ade2007-01-29 09:45:37 -07002225 /*
2226 * Check inactive list for matching phys disks
2227 */
2228 if (list_empty(&ioc->raid_data.inactive_list))
2229 goto out;
2230
2231 down(&ioc->raid_data.inactive_list_mutex);
2232 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2233 list) {
2234 if ((component_info->d.PhysDiskID == id) &&
2235 (component_info->d.PhysDiskBus == channel))
2236 rc = 1;
2237 }
2238 up(&ioc->raid_data.inactive_list_mutex);
2239
Eric Moore793955f2007-01-29 09:42:20 -07002240 out:
2241 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002242}
2243EXPORT_SYMBOL(mptscsih_is_phys_disk);
2244
Eric Moore793955f2007-01-29 09:42:20 -07002245u8
2246mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002247{
Eric Mooreb506ade2007-01-29 09:45:37 -07002248 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002249 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002250 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002251
Eric Moore793955f2007-01-29 09:42:20 -07002252 if (!ioc->raid_data.pIocPg3)
2253 goto out;
2254 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2255 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2256 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2257 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2258 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002259 }
2260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
Eric Mooreb506ade2007-01-29 09:45:37 -07002262 /*
2263 * Check inactive list for matching phys disks
2264 */
2265 if (list_empty(&ioc->raid_data.inactive_list))
2266 goto out;
2267
2268 down(&ioc->raid_data.inactive_list_mutex);
2269 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2270 list) {
2271 if ((component_info->d.PhysDiskID == id) &&
2272 (component_info->d.PhysDiskBus == channel))
2273 rc = component_info->d.PhysDiskNum;
2274 }
2275 up(&ioc->raid_data.inactive_list_mutex);
2276
Eric Moore793955f2007-01-29 09:42:20 -07002277 out:
2278 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002279}
Eric Moore793955f2007-01-29 09:42:20 -07002280EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002281
2282/*
2283 * OS entry point to allow for host driver to free allocated memory
2284 * Called if no device present or device being unloaded
2285 */
2286void
2287mptscsih_slave_destroy(struct scsi_device *sdev)
2288{
2289 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002291 VirtTarget *vtarget;
2292 VirtDevice *vdevice;
2293 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002295 starget = scsi_target(sdev);
2296 vtarget = starget->hostdata;
2297 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002299 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002300 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002301 mptscsih_synchronize_cache(hd, vdevice);
2302 kfree(vdevice);
2303 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304}
2305
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2307/*
2308 * mptscsih_change_queue_depth - This function will set a devices queue depth
2309 * @sdev: per scsi_device pointer
2310 * @qdepth: requested queue depth
2311 *
2312 * Adding support for new 'change_queue_depth' api.
2313*/
2314int
2315mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002317 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2318 VirtTarget *vtarget;
2319 struct scsi_target *starget;
2320 int max_depth;
2321 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002323 starget = scsi_target(sdev);
2324 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002325
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002326 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002327 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002329 else if (sdev->type == TYPE_DISK &&
2330 vtarget->minSyncFactor <= MPT_ULTRA160)
2331 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2332 else
2333 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 } else
2335 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2336
2337 if (qdepth > max_depth)
2338 qdepth = max_depth;
2339 if (qdepth == 1)
2340 tagged = 0;
2341 else
2342 tagged = MSG_SIMPLE_TAG;
2343
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002344 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2345 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346}
2347
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348/*
2349 * OS entry point to adjust the queue_depths on a per-device basis.
2350 * Called once per device the bus scan. Use it to force the queue_depth
2351 * member to 1 if a device does not support Q tags.
2352 * Return non-zero if fails.
2353 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002354int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002355mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002357 struct Scsi_Host *sh = sdev->host;
2358 VirtTarget *vtarget;
2359 VirtDevice *vdevice;
2360 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2362
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002363 starget = scsi_target(sdev);
2364 vtarget = starget->hostdata;
2365 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
2367 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002368 "device @ %p, channel=%d, id=%d, lun=%d\n",
2369 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002370 if (hd->ioc->bus_type == SPI)
2371 dsprintk((MYIOC_s_INFO_FMT
2372 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2373 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2374 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002376 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002378 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 goto slave_configure_exit;
2380 }
2381
Eric Moore793955f2007-01-29 09:42:20 -07002382 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002383 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
2385 dsprintk((MYIOC_s_INFO_FMT
2386 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002387 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002389 if (hd->ioc->bus_type == SPI)
2390 dsprintk((MYIOC_s_INFO_FMT
2391 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2392 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2393 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
2395slave_configure_exit:
2396
2397 dsprintk((MYIOC_s_INFO_FMT
2398 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002399 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2400 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 return 0;
2403}
2404
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2406/*
2407 * Private routines...
2408 */
2409
2410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2411/* Utility function to copy sense data from the scsi_cmnd buffer
2412 * to the FC and SCSI target structures.
2413 *
2414 */
2415static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002416mptscsih_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 -07002417{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 SCSIIORequest_t *pReq;
2420 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 /* Get target structure
2423 */
2424 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002425 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
2427 if (sense_count) {
2428 u8 *sense_data;
2429 int req_index;
2430
2431 /* Copy the sense received into the scsi command block. */
2432 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2433 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2434 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2435
2436 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2437 */
2438 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002439 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 int idx;
2441 MPT_ADAPTER *ioc = hd->ioc;
2442
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002443 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2445 ioc->events[idx].eventContext = ioc->eventContext;
2446
Dave Jones3d9780b2007-05-21 20:59:47 -04002447 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2448 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2449 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
Dave Jones3d9780b2007-05-21 20:59:47 -04002451 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
2453 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002454 if (hd->ioc->pcidev->vendor ==
2455 PCI_VENDOR_ID_IBM) {
2456 mptscsih_issue_sep_command(hd->ioc,
2457 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2458 vdev->vtarget->tflags |=
2459 MPT_TARGET_FLAGS_LED_ON;
2460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 }
2462 }
2463 } else {
2464 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2465 hd->ioc->name));
2466 }
2467}
2468
Eric Moore3dc0b032006-07-11 17:32:33 -06002469static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2471{
2472 MPT_SCSI_HOST *hd;
2473 int i;
2474
2475 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2476
2477 for (i = 0; i < hd->ioc->req_depth; i++) {
2478 if (hd->ScsiLookup[i] == sc) {
2479 return i;
2480 }
2481 }
2482
2483 return -1;
2484}
2485
2486/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002487int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2489{
2490 MPT_SCSI_HOST *hd;
2491 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002492 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
2494 dtmprintk((KERN_WARNING MYNAM
2495 ": IOC %s_reset routed to SCSI host driver!\n",
2496 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2497 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2498
2499 /* If a FW reload request arrives after base installed but
2500 * before all scsi hosts have been attached, then an alt_ioc
2501 * may have a NULL sh pointer.
2502 */
2503 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2504 return 0;
2505 else
2506 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2507
2508 if (reset_phase == MPT_IOC_SETUP_RESET) {
2509 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2510
2511 /* Clean Up:
2512 * 1. Set Hard Reset Pending Flag
2513 * All new commands go to doneQ
2514 */
2515 hd->resetPending = 1;
2516
2517 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2518 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2519
2520 /* 2. Flush running commands
2521 * Clean ScsiLookup (and associated memory)
2522 * AND clean mytaskQ
2523 */
2524
2525 /* 2b. Reply to OS all known outstanding I/O commands.
2526 */
2527 mptscsih_flush_running_cmds(hd);
2528
2529 /* 2c. If there was an internal command that
2530 * has not completed, configuration or io request,
2531 * free these resources.
2532 */
2533 if (hd->cmdPtr) {
2534 del_timer(&hd->timer);
2535 mpt_free_msg_frame(ioc, hd->cmdPtr);
2536 }
2537
2538 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2539
2540 } else {
2541 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2542
2543 /* Once a FW reload begins, all new OS commands are
2544 * redirected to the doneQ w/ a reset status.
2545 * Init all control structures.
2546 */
2547
2548 /* ScsiLookup initialization
2549 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002550 for (ii=0; ii < hd->ioc->req_depth; ii++)
2551 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
2553 /* 2. Chain Buffer initialization
2554 */
2555
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002556 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
2559 /* 5. Enable new commands to be posted
2560 */
2561 spin_lock_irqsave(&ioc->FreeQlock, flags);
2562 hd->tmPending = 0;
2563 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2564 hd->resetPending = 0;
2565 hd->tmState = TM_STATE_NONE;
2566
2567 /* 6. If there was an internal command,
2568 * wake this process up.
2569 */
2570 if (hd->cmdPtr) {
2571 /*
2572 * Wake up the original calling thread
2573 */
2574 hd->pLocal = &hd->localReply;
2575 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002576 hd->scandv_wait_done = 1;
2577 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 hd->cmdPtr = NULL;
2579 }
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2582
2583 }
2584
2585 return 1; /* currently means nothing really */
2586}
2587
2588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002589int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2591{
2592 MPT_SCSI_HOST *hd;
2593 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2594
Moore, Eric3a892be2006-03-14 09:14:03 -07002595 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 ioc->name, event));
2597
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002598 if (ioc->sh == NULL ||
2599 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2600 return 1;
2601
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 switch (event) {
2603 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2604 /* FIXME! */
2605 break;
2606 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2607 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002608 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002609 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 break;
2611 case MPI_EVENT_LOGOUT: /* 09 */
2612 /* FIXME! */
2613 break;
2614
Michael Reed05e8ec12006-01-13 14:31:54 -06002615 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002616 break;
2617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 /*
2619 * CHECKME! Don't think we need to do
2620 * anything for these, but...
2621 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2623 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2624 /*
2625 * CHECKME! Falling thru...
2626 */
2627 break;
2628
2629 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002630 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 case MPI_EVENT_NONE: /* 00 */
2633 case MPI_EVENT_LOG_DATA: /* 01 */
2634 case MPI_EVENT_STATE_CHANGE: /* 02 */
2635 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2636 default:
2637 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2638 break;
2639 }
2640
2641 return 1; /* currently means nothing really */
2642}
2643
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2645/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 * Bus Scan and Domain Validation functionality ...
2647 */
2648
2649/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2650/*
2651 * mptscsih_scandv_complete - Scan and DV callback routine registered
2652 * to Fustion MPT (base) driver.
2653 *
2654 * @ioc: Pointer to MPT_ADAPTER structure
2655 * @mf: Pointer to original MPT request frame
2656 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2657 *
2658 * This routine is called from mpt.c::mpt_interrupt() at the completion
2659 * of any SCSI IO request.
2660 * This routine is registered with the Fusion MPT (base) driver at driver
2661 * load/init time via the mpt_register() API call.
2662 *
2663 * Returns 1 indicating alloc'd request frame ptr should be freed.
2664 *
2665 * Remark: Sets a completion code and (possibly) saves sense data
2666 * in the IOC member localReply structure.
2667 * Used ONLY for DV and other internal commands.
2668 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002669int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2671{
2672 MPT_SCSI_HOST *hd;
2673 SCSIIORequest_t *pReq;
2674 int completionCode;
2675 u16 req_idx;
2676
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002677 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 if ((mf == NULL) ||
2680 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2681 printk(MYIOC_s_ERR_FMT
2682 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2683 ioc->name, mf?"BAD":"NULL", (void *) mf);
2684 goto wakeup;
2685 }
2686
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 del_timer(&hd->timer);
2688 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2689 hd->ScsiLookup[req_idx] = NULL;
2690 pReq = (SCSIIORequest_t *) mf;
2691
2692 if (mf != hd->cmdPtr) {
2693 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2694 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2695 }
2696 hd->cmdPtr = NULL;
2697
2698 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2699 hd->ioc->name, mf, mr, req_idx));
2700
2701 hd->pLocal = &hd->localReply;
2702 hd->pLocal->scsiStatus = 0;
2703
2704 /* If target struct exists, clear sense valid flag.
2705 */
2706 if (mr == NULL) {
2707 completionCode = MPT_SCANDV_GOOD;
2708 } else {
2709 SCSIIOReply_t *pReply;
2710 u16 status;
2711 u8 scsi_status;
2712
2713 pReply = (SCSIIOReply_t *) mr;
2714
2715 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2716 scsi_status = pReply->SCSIStatus;
2717
2718 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2719 status, pReply->SCSIState, scsi_status,
2720 le32_to_cpu(pReply->IOCLogInfo)));
2721
2722 switch(status) {
2723
2724 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2725 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2726 break;
2727
2728 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2729 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2730 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2731 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2732 completionCode = MPT_SCANDV_DID_RESET;
2733 break;
2734
2735 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2736 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2737 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2738 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2739 ConfigReply_t *pr = (ConfigReply_t *)mr;
2740 completionCode = MPT_SCANDV_GOOD;
2741 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2742 hd->pLocal->header.PageLength = pr->Header.PageLength;
2743 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2744 hd->pLocal->header.PageType = pr->Header.PageType;
2745
2746 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2747 /* If the RAID Volume request is successful,
2748 * return GOOD, else indicate that
2749 * some type of error occurred.
2750 */
2751 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002752 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 completionCode = MPT_SCANDV_GOOD;
2754 else
2755 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002756 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
2758 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2759 u8 *sense_data;
2760 int sz;
2761
2762 /* save sense data in global structure
2763 */
2764 completionCode = MPT_SCANDV_SENSE;
2765 hd->pLocal->scsiStatus = scsi_status;
2766 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2767 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2768
2769 sz = min_t(int, pReq->SenseBufferLength,
2770 SCSI_STD_SENSE_BYTES);
2771 memcpy(hd->pLocal->sense, sense_data, sz);
2772
2773 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2774 sense_data));
2775 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2776 if (pReq->CDB[0] == INQUIRY)
2777 completionCode = MPT_SCANDV_ISSUE_SENSE;
2778 else
2779 completionCode = MPT_SCANDV_DID_RESET;
2780 }
2781 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2782 completionCode = MPT_SCANDV_DID_RESET;
2783 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2784 completionCode = MPT_SCANDV_DID_RESET;
2785 else {
2786 completionCode = MPT_SCANDV_GOOD;
2787 hd->pLocal->scsiStatus = scsi_status;
2788 }
2789 break;
2790
2791 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2792 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2793 completionCode = MPT_SCANDV_DID_RESET;
2794 else
2795 completionCode = MPT_SCANDV_SOME_ERROR;
2796 break;
2797
2798 default:
2799 completionCode = MPT_SCANDV_SOME_ERROR;
2800 break;
2801
2802 } /* switch(status) */
2803
2804 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2805 completionCode));
2806 } /* end of address reply case */
2807
2808 hd->pLocal->completion = completionCode;
2809
2810 /* MF and RF are freed in mpt_interrupt
2811 */
2812wakeup:
2813 /* Free Chain buffers (will never chain) in scan or dv */
2814 //mptscsih_freeChainBuffers(ioc, req_idx);
2815
2816 /*
2817 * Wake up the original calling thread
2818 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002819 hd->scandv_wait_done = 1;
2820 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
2822 return 1;
2823}
2824
2825/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2826/* mptscsih_timer_expired - Call back for timer process.
2827 * Used only for dv functionality.
2828 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2829 *
2830 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002831void
2832mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833{
2834 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2835
2836 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2837
2838 if (hd->cmdPtr) {
2839 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2840
2841 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2842 /* Desire to issue a task management request here.
2843 * TM requests MUST be single threaded.
2844 * If old eh code and no TM current, issue request.
2845 * If new eh code, do nothing. Wait for OS cmd timeout
2846 * for bus reset.
2847 */
2848 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2849 } else {
2850 /* Perform a FW reload */
2851 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2852 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2853 }
2854 }
2855 } else {
2856 /* This should NEVER happen */
2857 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2858 }
2859
2860 /* No more processing.
2861 * TM call will generate an interrupt for SCSI TM Management.
2862 * The FW will reply to all outstanding commands, callback will finish cleanup.
2863 * Hard reset clean-up will free all resources.
2864 */
2865 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2866
2867 return;
2868}
2869
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870
2871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2872/**
2873 * mptscsih_do_cmd - Do internal command.
2874 * @hd: MPT_SCSI_HOST pointer
2875 * @io: INTERNAL_CMD pointer.
2876 *
2877 * Issue the specified internally generated command and do command
2878 * specific cleanup. For bus scan / DV only.
2879 * NOTES: If command is Inquiry and status is good,
2880 * initialize a target structure, save the data
2881 *
2882 * Remark: Single threaded access only.
2883 *
2884 * Return:
2885 * < 0 if an illegal command or no resources
2886 *
2887 * 0 if good
2888 *
2889 * > 0 if command complete but some type of completion error.
2890 */
2891static int
2892mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2893{
2894 MPT_FRAME_HDR *mf;
2895 SCSIIORequest_t *pScsiReq;
2896 SCSIIORequest_t ReqCopy;
2897 int my_idx, ii, dir;
2898 int rc, cmdTimeout;
2899 int in_isr;
2900 char cmdLen;
2901 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2902 char cmd = io->cmd;
2903
2904 in_isr = in_interrupt();
2905 if (in_isr) {
2906 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2907 hd->ioc->name));
2908 return -EPERM;
2909 }
2910
2911
2912 /* Set command specific information
2913 */
2914 switch (cmd) {
2915 case INQUIRY:
2916 cmdLen = 6;
2917 dir = MPI_SCSIIO_CONTROL_READ;
2918 CDB[0] = cmd;
2919 CDB[4] = io->size;
2920 cmdTimeout = 10;
2921 break;
2922
2923 case TEST_UNIT_READY:
2924 cmdLen = 6;
2925 dir = MPI_SCSIIO_CONTROL_READ;
2926 cmdTimeout = 10;
2927 break;
2928
2929 case START_STOP:
2930 cmdLen = 6;
2931 dir = MPI_SCSIIO_CONTROL_READ;
2932 CDB[0] = cmd;
2933 CDB[4] = 1; /*Spin up the disk */
2934 cmdTimeout = 15;
2935 break;
2936
2937 case REQUEST_SENSE:
2938 cmdLen = 6;
2939 CDB[0] = cmd;
2940 CDB[4] = io->size;
2941 dir = MPI_SCSIIO_CONTROL_READ;
2942 cmdTimeout = 10;
2943 break;
2944
2945 case READ_BUFFER:
2946 cmdLen = 10;
2947 dir = MPI_SCSIIO_CONTROL_READ;
2948 CDB[0] = cmd;
2949 if (io->flags & MPT_ICFLAG_ECHO) {
2950 CDB[1] = 0x0A;
2951 } else {
2952 CDB[1] = 0x02;
2953 }
2954
2955 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2956 CDB[1] |= 0x01;
2957 }
2958 CDB[6] = (io->size >> 16) & 0xFF;
2959 CDB[7] = (io->size >> 8) & 0xFF;
2960 CDB[8] = io->size & 0xFF;
2961 cmdTimeout = 10;
2962 break;
2963
2964 case WRITE_BUFFER:
2965 cmdLen = 10;
2966 dir = MPI_SCSIIO_CONTROL_WRITE;
2967 CDB[0] = cmd;
2968 if (io->flags & MPT_ICFLAG_ECHO) {
2969 CDB[1] = 0x0A;
2970 } else {
2971 CDB[1] = 0x02;
2972 }
2973 CDB[6] = (io->size >> 16) & 0xFF;
2974 CDB[7] = (io->size >> 8) & 0xFF;
2975 CDB[8] = io->size & 0xFF;
2976 cmdTimeout = 10;
2977 break;
2978
2979 case RESERVE:
2980 cmdLen = 6;
2981 dir = MPI_SCSIIO_CONTROL_READ;
2982 CDB[0] = cmd;
2983 cmdTimeout = 10;
2984 break;
2985
2986 case RELEASE:
2987 cmdLen = 6;
2988 dir = MPI_SCSIIO_CONTROL_READ;
2989 CDB[0] = cmd;
2990 cmdTimeout = 10;
2991 break;
2992
2993 case SYNCHRONIZE_CACHE:
2994 cmdLen = 10;
2995 dir = MPI_SCSIIO_CONTROL_READ;
2996 CDB[0] = cmd;
2997// CDB[1] = 0x02; /* set immediate bit */
2998 cmdTimeout = 10;
2999 break;
3000
3001 default:
3002 /* Error Case */
3003 return -EFAULT;
3004 }
3005
3006 /* Get and Populate a free Frame
3007 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003008 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3010 hd->ioc->name));
3011 return -EBUSY;
3012 }
3013
3014 pScsiReq = (SCSIIORequest_t *) mf;
3015
3016 /* Get the request index */
3017 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3018 ADD_INDEX_LOG(my_idx); /* for debug */
3019
3020 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3021 pScsiReq->TargetID = io->physDiskNum;
3022 pScsiReq->Bus = 0;
3023 pScsiReq->ChainOffset = 0;
3024 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3025 } else {
3026 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003027 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 pScsiReq->ChainOffset = 0;
3029 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3030 }
3031
3032 pScsiReq->CDBLength = cmdLen;
3033 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3034
3035 pScsiReq->Reserved = 0;
3036
3037 pScsiReq->MsgFlags = mpt_msg_flags();
3038 /* MsgContext set in mpt_get_msg_fram call */
3039
Eric Moore793955f2007-01-29 09:42:20 -07003040 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
3042 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3043 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3044 else
3045 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3046
3047 if (cmd == REQUEST_SENSE) {
3048 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3049 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3050 hd->ioc->name, cmd));
3051 }
3052
3053 for (ii=0; ii < 16; ii++)
3054 pScsiReq->CDB[ii] = CDB[ii];
3055
3056 pScsiReq->DataLength = cpu_to_le32(io->size);
3057 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3058 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3059
3060 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003061 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
3063 if (dir == MPI_SCSIIO_CONTROL_READ) {
3064 mpt_add_sge((char *) &pScsiReq->SGL,
3065 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3066 io->data_dma);
3067 } else {
3068 mpt_add_sge((char *) &pScsiReq->SGL,
3069 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3070 io->data_dma);
3071 }
3072
3073 /* The ISR will free the request frame, but we need
3074 * the information to initialize the target. Duplicate.
3075 */
3076 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3077
3078 /* Issue this command after:
3079 * finish init
3080 * add timer
3081 * Wait until the reply has been received
3082 * ScsiScanDvCtx callback function will
3083 * set hd->pLocal;
3084 * set scandv_wait_done and call wake_up
3085 */
3086 hd->pLocal = NULL;
3087 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003088 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
3090 /* Save cmd pointer, for resource free if timeout or
3091 * FW reload occurs
3092 */
3093 hd->cmdPtr = mf;
3094
3095 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003096 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3097 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
3099 if (hd->pLocal) {
3100 rc = hd->pLocal->completion;
3101 hd->pLocal->skip = 0;
3102
3103 /* Always set fatal error codes in some cases.
3104 */
3105 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3106 rc = -ENXIO;
3107 else if (rc == MPT_SCANDV_SOME_ERROR)
3108 rc = -rc;
3109 } else {
3110 rc = -EFAULT;
3111 /* This should never happen. */
3112 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3113 hd->ioc->name));
3114 }
3115
3116 return rc;
3117}
3118
3119/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3120/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003121 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3122 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003123 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003124 *
3125 * Uses the ISR, but with special processing.
3126 * MUST be single-threaded.
3127 *
3128 */
3129static void
3130mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3131{
3132 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 /* Following parameters will not change
3135 * in this routine.
3136 */
3137 iocmd.cmd = SYNCHRONIZE_CACHE;
3138 iocmd.flags = 0;
3139 iocmd.physDiskNum = -1;
3140 iocmd.data = NULL;
3141 iocmd.data_dma = -1;
3142 iocmd.size = 0;
3143 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003144 iocmd.channel = vdevice->vtarget->channel;
3145 iocmd.id = vdevice->vtarget->id;
3146 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147
James Bottomleyc92f2222006-03-01 09:02:49 -06003148 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003149 (vdevice->configured_lun))
3150 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151}
3152
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003153EXPORT_SYMBOL(mptscsih_remove);
3154EXPORT_SYMBOL(mptscsih_shutdown);
3155#ifdef CONFIG_PM
3156EXPORT_SYMBOL(mptscsih_suspend);
3157EXPORT_SYMBOL(mptscsih_resume);
3158#endif
3159EXPORT_SYMBOL(mptscsih_proc_info);
3160EXPORT_SYMBOL(mptscsih_info);
3161EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003162EXPORT_SYMBOL(mptscsih_slave_destroy);
3163EXPORT_SYMBOL(mptscsih_slave_configure);
3164EXPORT_SYMBOL(mptscsih_abort);
3165EXPORT_SYMBOL(mptscsih_dev_reset);
3166EXPORT_SYMBOL(mptscsih_bus_reset);
3167EXPORT_SYMBOL(mptscsih_host_reset);
3168EXPORT_SYMBOL(mptscsih_bios_param);
3169EXPORT_SYMBOL(mptscsih_io_done);
3170EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3171EXPORT_SYMBOL(mptscsih_scandv_complete);
3172EXPORT_SYMBOL(mptscsih_event_process);
3173EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003174EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003175EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003176EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/