blob: 561074a04b03ce83b381c68201986b78763e46ea [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 Moore07c861d2007-01-29 09:48:50 -07007 * (mailto:mpt_linux_developer@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
47#include "linux_compat.h" /* linux-2.6 tweaks */
48#include <linux/module.h>
49#include <linux/kernel.h>
50#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/workqueue.h>
58
59#include <scsi/scsi.h>
60#include <scsi/scsi_cmnd.h>
61#include <scsi/scsi_device.h>
62#include <scsi/scsi_host.h>
63#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060064#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
67#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060068#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT SCSI Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptscsih"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*
82 * Other private/forward protos...
83 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040084int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040086int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
89 SCSIIORequest_t *pReq, int req_idx);
90static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040091static 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 -070092static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
93static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -060094static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Eric Moore793955f2007-01-29 09:42:20 -070096static 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 -070097
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040098int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
99int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400101int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700103static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400105void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700106void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400108int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
109int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#endif
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
115/**
116 * mptscsih_add_sge - Place a simple SGE at address pAddr.
117 * @pAddr: virtual address for SGE
118 * @flagslength: SGE flags and data transfer length
119 * @dma_addr: Physical address
120 *
121 * This routine places a MPT request frame back on the MPT adapter's
122 * FreeQ.
123 */
124static inline void
125mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
126{
127 if (sizeof(dma_addr_t) == sizeof(u64)) {
128 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
129 u32 tmp = dma_addr & 0xFFFFFFFF;
130
131 pSge->FlagsLength = cpu_to_le32(flagslength);
132 pSge->Address.Low = cpu_to_le32(tmp);
133 tmp = (u32) ((u64)dma_addr >> 32);
134 pSge->Address.High = cpu_to_le32(tmp);
135
136 } else {
137 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
138 pSge->FlagsLength = cpu_to_le32(flagslength);
139 pSge->Address = cpu_to_le32(dma_addr);
140 }
141} /* mptscsih_add_sge() */
142
143/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
144/**
145 * mptscsih_add_chain - Place a chain SGE at address pAddr.
146 * @pAddr: virtual address for SGE
147 * @next: nextChainOffset value (u32's)
148 * @length: length of next SGL segment
149 * @dma_addr: Physical address
150 *
151 * This routine places a MPT request frame back on the MPT adapter's
152 * FreeQ.
153 */
154static inline void
155mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
156{
157 if (sizeof(dma_addr_t) == sizeof(u64)) {
158 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
159 u32 tmp = dma_addr & 0xFFFFFFFF;
160
161 pChain->Length = cpu_to_le16(length);
162 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
163
164 pChain->NextChainOffset = next;
165
166 pChain->Address.Low = cpu_to_le32(tmp);
167 tmp = (u32) ((u64)dma_addr >> 32);
168 pChain->Address.High = cpu_to_le32(tmp);
169 } else {
170 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
171 pChain->Length = cpu_to_le16(length);
172 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
173 pChain->NextChainOffset = next;
174 pChain->Address = cpu_to_le32(dma_addr);
175 }
176} /* mptscsih_add_chain() */
177
178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
179/*
180 * mptscsih_getFreeChainBuffer - Function to get a free chain
181 * from the MPT_SCSI_HOST FreeChainQ.
182 * @ioc: Pointer to MPT_ADAPTER structure
183 * @req_idx: Index of the SCSI IO request frame. (output)
184 *
185 * return SUCCESS or FAILED
186 */
187static inline int
188mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
189{
190 MPT_FRAME_HDR *chainBuf;
191 unsigned long flags;
192 int rc;
193 int chain_idx;
194
195 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
196 ioc->name));
197 spin_lock_irqsave(&ioc->FreeQlock, flags);
198 if (!list_empty(&ioc->FreeChainQ)) {
199 int offset;
200
201 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
202 u.frame.linkage.list);
203 list_del(&chainBuf->u.frame.linkage.list);
204 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
205 chain_idx = offset / ioc->req_sz;
206 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200207 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
208 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 } else {
210 rc = FAILED;
211 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200212 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 ioc->name));
214 }
215 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
216
217 *retIndex = chain_idx;
218 return rc;
219} /* mptscsih_getFreeChainBuffer() */
220
221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
222/*
223 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
224 * SCSIIORequest_t Message Frame.
225 * @ioc: Pointer to MPT_ADAPTER structure
226 * @SCpnt: Pointer to scsi_cmnd structure
227 * @pReq: Pointer to SCSIIORequest_t structure
228 *
229 * Returns ...
230 */
231static int
232mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
233 SCSIIORequest_t *pReq, int req_idx)
234{
235 char *psge;
236 char *chainSge;
237 struct scatterlist *sg;
238 int frm_sz;
239 int sges_left, sg_done;
240 int chain_idx = MPT_HOST_NO_CHAIN;
241 int sgeOffset;
242 int numSgeSlots, numSgeThisFrame;
243 u32 sgflags, sgdir, thisxfer = 0;
244 int chain_dma_off = 0;
245 int newIndex;
246 int ii;
247 dma_addr_t v2;
248 u32 RequestNB;
249
250 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
251 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
252 sgdir = MPT_TRANSFER_HOST_TO_IOC;
253 } else {
254 sgdir = MPT_TRANSFER_IOC_TO_HOST;
255 }
256
257 psge = (char *) &pReq->SGL;
258 frm_sz = ioc->req_sz;
259
260 /* Map the data portion, if any.
261 * sges_left = 0 if no data transfer.
262 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900263 sges_left = scsi_dma_map(SCpnt);
264 if (sges_left < 0)
265 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 /* Handle the SG case.
268 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900269 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sg_done = 0;
271 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
272 chainSge = NULL;
273
274 /* Prior to entering this loop - the following must be set
275 * current MF: sgeOffset (bytes)
276 * chainSge (Null if original MF is not a chain buffer)
277 * sg_done (num SGE done for this MF)
278 */
279
280nextSGEset:
281 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
282 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
283
284 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
285
286 /* Get first (num - 1) SG elements
287 * Skip any SG entries with a length of 0
288 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
289 */
290 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
291 thisxfer = sg_dma_len(sg);
292 if (thisxfer == 0) {
293 sg ++; /* Get next SG element from the OS */
294 sg_done++;
295 continue;
296 }
297
298 v2 = sg_dma_address(sg);
299 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
300
301 sg++; /* Get next SG element from the OS */
302 psge += (sizeof(u32) + sizeof(dma_addr_t));
303 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
304 sg_done++;
305 }
306
307 if (numSgeThisFrame == sges_left) {
308 /* Add last element, end of buffer and end of list flags.
309 */
310 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
311 MPT_SGE_FLAGS_END_OF_BUFFER |
312 MPT_SGE_FLAGS_END_OF_LIST;
313
314 /* Add last SGE and set termination flags.
315 * Note: Last SGE may have a length of 0 - which should be ok.
316 */
317 thisxfer = sg_dma_len(sg);
318
319 v2 = sg_dma_address(sg);
320 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
321 /*
322 sg++;
323 psge += (sizeof(u32) + sizeof(dma_addr_t));
324 */
325 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
326 sg_done++;
327
328 if (chainSge) {
329 /* The current buffer is a chain buffer,
330 * but there is not another one.
331 * Update the chain element
332 * Offset and Length fields.
333 */
334 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
335 } else {
336 /* The current buffer is the original MF
337 * and there is no Chain buffer.
338 */
339 pReq->ChainOffset = 0;
340 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200341 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
343 ioc->RequestNB[req_idx] = RequestNB;
344 }
345 } else {
346 /* At least one chain buffer is needed.
347 * Complete the first MF
348 * - last SGE element, set the LastElement bit
349 * - set ChainOffset (words) for orig MF
350 * (OR finish previous MF chain buffer)
351 * - update MFStructPtr ChainIndex
352 * - Populate chain element
353 * Also
354 * Loop until done.
355 */
356
357 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
358 ioc->name, sg_done));
359
360 /* Set LAST_ELEMENT flag for last non-chain element
361 * in the buffer. Since psge points at the NEXT
362 * SGE element, go back one SGE element, update the flags
363 * and reset the pointer. (Note: sgflags & thisxfer are already
364 * set properly).
365 */
366 if (sg_done) {
367 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
368 sgflags = le32_to_cpu(*ptmp);
369 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
370 *ptmp = cpu_to_le32(sgflags);
371 }
372
373 if (chainSge) {
374 /* The current buffer is a chain buffer.
375 * chainSge points to the previous Chain Element.
376 * Update its chain element Offset and Length (must
377 * include chain element size) fields.
378 * Old chain element is now complete.
379 */
380 u8 nextChain = (u8) (sgeOffset >> 2);
381 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
382 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
383 } else {
384 /* The original MF buffer requires a chain buffer -
385 * set the offset.
386 * Last element in this MF is a chain element.
387 */
388 pReq->ChainOffset = (u8) (sgeOffset >> 2);
389 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
390 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
391 ioc->RequestNB[req_idx] = RequestNB;
392 }
393
394 sges_left -= sg_done;
395
396
397 /* NOTE: psge points to the beginning of the chain element
398 * in current buffer. Get a chain buffer.
399 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200400 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
401 dfailprintk((MYIOC_s_INFO_FMT
402 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
403 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 /* Update the tracking arrays.
408 * If chainSge == NULL, update ReqToChain, else ChainToChain
409 */
410 if (chainSge) {
411 ioc->ChainToChain[chain_idx] = newIndex;
412 } else {
413 ioc->ReqToChain[req_idx] = newIndex;
414 }
415 chain_idx = newIndex;
416 chain_dma_off = ioc->req_sz * chain_idx;
417
418 /* Populate the chainSGE for the current buffer.
419 * - Set chain buffer pointer to psge and fill
420 * out the Address and Flags fields.
421 */
422 chainSge = (char *) psge;
423 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
424 psge, req_idx));
425
426 /* Start the SGE for the next buffer
427 */
428 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
429 sgeOffset = 0;
430 sg_done = 0;
431
432 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
433 psge, chain_idx));
434
435 /* Start the SGE for the next buffer
436 */
437
438 goto nextSGEset;
439 }
440
441 return SUCCESS;
442} /* mptscsih_AddSGE() */
443
Eric Moore786899b2006-07-11 17:22:22 -0600444static void
445mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
446 U32 SlotStatus)
447{
448 MPT_FRAME_HDR *mf;
449 SEPRequest_t *SEPMsg;
450
451 if (ioc->bus_type == FC)
452 return;
453
454 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
455 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
456 ioc->name,__FUNCTION__));
457 return;
458 }
459
460 SEPMsg = (SEPRequest_t *)mf;
461 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700462 SEPMsg->Bus = vtarget->channel;
463 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600464 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
465 SEPMsg->SlotStatus = SlotStatus;
466 devtverboseprintk((MYIOC_s_WARN_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700467 "Sending SEP cmd=%x channel=%d id=%d\n",
468 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600469 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
470}
471
Eric Moorec6c727a2007-01-29 09:44:54 -0700472#ifdef MPT_DEBUG_REPLY
473/**
474 * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
475 * @ioc: Pointer to MPT_ADAPTER structure
476 * @ioc_status: U32 IOCStatus word from IOC
477 * @scsi_status: U8 sam status from target
478 * @scsi_state: U8 scsi state
479 * @sc: original scsi cmnd pointer
480 * @mf: Pointer to MPT request frame
481 *
482 * Refer to lsi/mpi.h.
483 **/
484static void
485mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
486 u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
487{
488 char extend_desc[EVENT_DESCR_STR_SZ];
489 char *desc = NULL;
490
491 switch (ioc_status) {
492
493 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
494 desc = "SCSI Invalid Bus";
495 break;
496
497 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
498 desc = "SCSI Invalid TargetID";
499 break;
500
501 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
502 /*
503 * Inquiry is issued for device scanning
504 */
505 if (sc->cmnd[0] != 0x12)
506 desc = "SCSI Device Not There";
507 break;
508
509 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
510 desc = "SCSI Data Overrun";
511 break;
512
513 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
514 desc = "SCSI I/O Data Error";
515 break;
516
517 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
518 desc = "SCSI Protocol Error";
519 break;
520
521 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
522 desc = "SCSI Task Terminated";
523 break;
524
525 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
526 desc = "SCSI Residual Mismatch";
527 break;
528
529 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
530 desc = "SCSI Task Management Failed";
531 break;
532
533 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
534 desc = "SCSI IOC Terminated";
535 break;
536
537 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
538 desc = "SCSI Ext Terminated";
539 break;
540 }
541
542 if (!desc)
543 return;
544
545 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
546 "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
547 sc->device->host->host_no,
548 sc->device->channel, sc->device->id, sc->device->lun,
549 sc->cmnd[0], scsi_status, scsi_state);
550
551 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
552 ioc->name, ioc_status, desc, extend_desc);
553}
554#endif
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
557/*
558 * mptscsih_io_done - Main SCSI IO callback routine registered to
559 * Fusion MPT (base) driver
560 * @ioc: Pointer to MPT_ADAPTER structure
561 * @mf: Pointer to original MPT request frame
562 * @r: Pointer to MPT reply frame (NULL if TurboReply)
563 *
564 * This routine is called from mpt.c::mpt_interrupt() at the completion
565 * of any SCSI IO request.
566 * This routine is registered with the Fusion MPT (base) driver at driver
567 * load/init time via the mpt_register() API call.
568 *
569 * Returns 1 indicating alloc'd request frame ptr should be freed.
570 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400571int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
573{
574 struct scsi_cmnd *sc;
575 MPT_SCSI_HOST *hd;
576 SCSIIORequest_t *pScsiReq;
577 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700578 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600579 VirtDevice *vdev;
580 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
583
584 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700585 req_idx_MR = (mr != NULL) ?
586 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
587 if ((req_idx != req_idx_MR) ||
588 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
589 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
590 ioc->name);
591 printk (MYIOC_s_ERR_FMT
592 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
593 ioc->name, req_idx, req_idx_MR, mf, mr,
594 hd->ScsiLookup[req_idx_MR]);
595 return 0;
596 }
597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600599 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (sc == NULL) {
601 MPIHeader_t *hdr = (MPIHeader_t *)mf;
602
603 /* Remark: writeSDP1 will use the ScsiDoneCtx
604 * If a SCSI I/O cmd, device disabled by OS and
605 * completion done. Cannot touch sc struct. Just free mem.
606 */
607 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
608 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
609 ioc->name);
610
611 mptscsih_freeChainBuffers(ioc, req_idx);
612 return 1;
613 }
614
Eric Moore3dc0b032006-07-11 17:32:33 -0600615 if ((unsigned char *)mf != sc->host_scribble) {
616 mptscsih_freeChainBuffers(ioc, req_idx);
617 return 1;
618 }
619
620 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 sc->result = DID_OK << 16; /* Set default reply as OK */
622 pScsiReq = (SCSIIORequest_t *) mf;
623 pScsiReply = (SCSIIOReply_t *) mr;
624
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200625 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
626 dmfprintk((MYIOC_s_INFO_FMT
627 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
628 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
629 }else{
630 dmfprintk((MYIOC_s_INFO_FMT
631 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
632 ioc->name, mf, mr, sc, req_idx));
633 }
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (pScsiReply == NULL) {
636 /* special context reply handling */
637 ;
638 } else {
639 u32 xfer_cnt;
640 u16 status;
641 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700642 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
645 scsi_state = pScsiReply->SCSIState;
646 scsi_status = pScsiReply->SCSIStatus;
647 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900648 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700649 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600651 /*
652 * if we get a data underrun indication, yet no data was
653 * transferred and the SCSI status indicates that the
654 * command was never started, change the data underrun
655 * to success
656 */
657 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
658 (scsi_status == MPI_SCSI_STATUS_BUSY ||
659 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
660 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
661 status = MPI_IOCSTATUS_SUCCESS;
662 }
663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400665 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 /*
668 * Look for + dump FCP ResponseInfo[]!
669 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600670 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
671 pScsiReply->ResponseInfo) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700672 printk(KERN_NOTICE "[%d:%d:%d:%d] "
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600673 "FCP_ResponseInfo=%08xh\n",
Eric Moorec6c727a2007-01-29 09:44:54 -0700674 sc->device->host->host_no, sc->device->channel,
675 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 le32_to_cpu(pScsiReply->ResponseInfo));
677 }
678
679 switch(status) {
680 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
681 /* CHECKME!
682 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
683 * But not: DID_BUS_BUSY lest one risk
684 * killing interrupt handler:-(
685 */
686 sc->result = SAM_STAT_BUSY;
687 break;
688
689 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
690 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
691 sc->result = DID_BAD_TARGET << 16;
692 break;
693
694 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
695 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600696 if (ioc->bus_type != FC)
697 sc->result = DID_NO_CONNECT << 16;
698 /* else fibre, just stall until rescan event */
699 else
700 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
703 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600704
705 vdev = sc->device->hostdata;
706 if (!vdev)
707 break;
708 vtarget = vdev->vtarget;
709 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
710 mptscsih_issue_sep_command(ioc, vtarget,
711 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
712 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 break;
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600717 if ( ioc->bus_type == SAS ) {
718 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
719 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700720 if ((log_info & SAS_LOGINFO_MASK)
721 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600722 sc->result = (DID_BUS_BUSY << 16);
723 break;
724 }
725 }
Eric Moore86dd4242007-01-04 20:44:01 -0700726 } else if (ioc->bus_type == FC) {
727 /*
728 * The FC IOC may kill a request for variety of
729 * reasons, some of which may be recovered by a
730 * retry, some which are unlikely to be
731 * recovered. Return DID_ERROR instead of
732 * DID_RESET to permit retry of the command,
733 * just not an infinite number of them
734 */
735 sc->result = DID_ERROR << 16;
736 break;
Eric Moorebf451522006-07-11 17:25:35 -0600737 }
738
739 /*
740 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
741 */
742
743 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
745 /* Linux handles an unsolicited DID_RESET better
746 * than an unsolicited DID_ABORT.
747 */
748 sc->result = DID_RESET << 16;
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 break;
751
752 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900753 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600754 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
755 sc->result=DID_SOFT_ERROR << 16;
756 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600758 dreplyprintk((KERN_NOTICE
Eric Moorec6c727a2007-01-29 09:44:54 -0700759 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
760 sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
764 /*
765 * Do upfront check for valid SenseData and give it
766 * precedence!
767 */
768 sc->result = (DID_OK << 16) | scsi_status;
769 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
770 /* Have already saved the status and sense data
771 */
772 ;
773 } else {
774 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600775 if (scsi_status == SAM_STAT_BUSY)
776 sc->result = SAM_STAT_BUSY;
777 else
778 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
781 /* What to do?
782 */
783 sc->result = DID_SOFT_ERROR << 16;
784 }
785 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
786 /* Not real sure here either... */
787 sc->result = DID_RESET << 16;
788 }
789 }
790
791 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
792 sc->underflow));
793 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
794 /* Report Queue Full
795 */
796 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
797 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 break;
800
Moore, Eric7e551472006-01-16 18:53:21 -0700801 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900802 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
804 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600805 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (scsi_state == 0) {
807 ;
808 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
809 /*
810 * If running against circa 200003dd 909 MPT f/w,
811 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
812 * (QUEUE_FULL) returned from device! --> get 0x0000?128
813 * and with SenseBytes set to 0.
814 */
815 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
816 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
817
818 }
819 else if (scsi_state &
820 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
821 ) {
822 /*
823 * What to do?
824 */
825 sc->result = DID_SOFT_ERROR << 16;
826 }
827 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
828 /* Not real sure here either... */
829 sc->result = DID_RESET << 16;
830 }
831 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
832 /* Device Inq. data indicates that it supports
833 * QTags, but rejects QTag messages.
834 * This command completed OK.
835 *
836 * Not real sure here either so do nothing... */
837 }
838
839 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
840 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
841
842 /* Add handling of:
843 * Reservation Conflict, Busy,
844 * Command Terminated, CHECK
845 */
846 break;
847
848 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
849 sc->result = DID_SOFT_ERROR << 16;
850 break;
851
852 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
853 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
854 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
855 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
856 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
857 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
858 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
860 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
861 default:
862 /*
863 * What to do?
864 */
865 sc->result = DID_SOFT_ERROR << 16;
866 break;
867
868 } /* switch(status) */
869
Eric Moorec6c727a2007-01-29 09:44:54 -0700870#ifdef MPT_DEBUG_REPLY
871 if (sc->result) {
872
873 mptscsih_iocstatus_info_scsiio(ioc, status,
874 scsi_status, scsi_state, sc);
875
876 dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
877 "result=0x%08x\n\tiocstatus=0x%04X "
878 "scsi_state=0x%02X scsi_status=0x%02X "
879 "loginfo=0x%08X\n", __FUNCTION__,
880 sc->device->host->host_no, sc->device->channel, sc->device->id,
881 sc->device->lun, sc->cmnd[0], sc->result, status,
882 scsi_state, scsi_status, log_info));
883
884 dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900885 "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
886 sc->device->host->host_no,
887 sc->device->channel, sc->device->id,
888 sc->device->lun, scsi_get_resid(sc),
889 scsi_bufflen(sc), xfer_cnt));
Eric Moorec6c727a2007-01-29 09:44:54 -0700890 }
891#endif
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 } /* end of address reply case */
894
895 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900896 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 sc->scsi_done(sc); /* Issue the command callback */
899
900 /* Free Chain buffers */
901 mptscsih_freeChainBuffers(ioc, req_idx);
902 return 1;
903}
904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905/*
906 * mptscsih_flush_running_cmds - For each command found, search
907 * Scsi_Host instance taskQ and reply to OS.
908 * Called only if recovering from a FW reload.
909 * @hd: Pointer to a SCSI HOST structure
910 *
911 * Returns: None.
912 *
913 * Must be called while new I/Os are being queued.
914 */
915static void
916mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
917{
918 MPT_ADAPTER *ioc = hd->ioc;
919 struct scsi_cmnd *SCpnt;
920 MPT_FRAME_HDR *mf;
921 int ii;
922 int max = ioc->req_depth;
923
924 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
925 for (ii= 0; ii < max; ii++) {
926 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
927
928 /* Command found.
929 */
930
931 /* Null ScsiLookup index
932 */
933 hd->ScsiLookup[ii] = NULL;
934
935 mf = MPT_INDEX_2_MFPTR(ioc, ii);
936 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
937 mf, SCpnt));
938
Eric Moore3dc0b032006-07-11 17:32:33 -0600939 /* Free Chain buffers */
940 mptscsih_freeChainBuffers(ioc, ii);
941
942 /* Free Message frames */
943 mpt_free_msg_frame(ioc, mf);
944
945 if ((unsigned char *)mf != SCpnt->host_scribble)
946 continue;
947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 /* Set status, free OS resources (SG DMA buffers)
949 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900951 scsi_dma_unmap(SCpnt);
952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 SCpnt->result = DID_RESET << 16;
954 SCpnt->host_scribble = NULL;
955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
957 }
958 }
959
960 return;
961}
962
963/*
964 * mptscsih_search_running_cmds - Delete any commands associated
965 * with the specified target and lun. Function called only
966 * when a lun is disable by mid-layer.
967 * Do NOT access the referenced scsi_cmnd structure or
968 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600969 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700970 * @hd: Pointer to a SCSI HOST structure
971 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 *
973 * Returns: None.
974 *
975 * Called from slave_destroy.
976 */
977static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700978mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
980 SCSIIORequest_t *mf = NULL;
981 int ii;
982 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600983 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700984 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Eric Moore793955f2007-01-29 09:42:20 -0700986 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
987 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600990 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600993 if (mf == NULL)
994 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700995 int_to_scsilun(vdevice->lun, &lun);
996 if ((mf->Bus != vdevice->vtarget->channel) ||
997 (mf->TargetID != vdevice->vtarget->id) ||
998 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001000 dsprintk(( "search_running: found (sc=%p, mf = %p) "
1001 "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
1002 mf, mf->Bus, mf->TargetID, vdevice->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 /* Cleanup
1005 */
1006 hd->ScsiLookup[ii] = NULL;
1007 mptscsih_freeChainBuffers(hd->ioc, ii);
1008 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001009 if ((unsigned char *)mf != sc->host_scribble)
1010 continue;
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001011 scsi_dma_unmap(sc);
1012
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001013 sc->host_scribble = NULL;
1014 sc->result = DID_NO_CONNECT << 16;
1015 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
1017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return;
1019}
1020
1021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1024/*
1025 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1026 * from a SCSI target device.
1027 * @sc: Pointer to scsi_cmnd structure
1028 * @pScsiReply: Pointer to SCSIIOReply_t
1029 * @pScsiReq: Pointer to original SCSI request
1030 *
1031 * This routine periodically reports QUEUE_FULL status returned from a
1032 * SCSI target device. It reports this to the console via kernel
1033 * printk() API call, not more than once every 10 seconds.
1034 */
1035static void
1036mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1037{
1038 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001041 if (sc->device == NULL)
1042 return;
1043 if (sc->device->host == NULL)
1044 return;
1045 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1046 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001048 if (time - hd->last_queue_full > 10 * HZ) {
1049 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1050 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1051 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053}
1054
1055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1056/*
1057 * mptscsih_remove - Removed scsi devices
1058 * @pdev: Pointer to pci_dev structure
1059 *
1060 *
1061 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001062void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063mptscsih_remove(struct pci_dev *pdev)
1064{
1065 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1066 struct Scsi_Host *host = ioc->sh;
1067 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001068 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001070 if(!host) {
1071 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075 scsi_remove_host(host);
1076
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001077 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1078 return;
1079
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001080 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001082 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001084 if (hd->ScsiLookup != NULL) {
1085 sz1 = hd->ioc->req_depth * sizeof(void *);
1086 kfree(hd->ScsiLookup);
1087 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001090 dprintk((MYIOC_s_INFO_FMT
1091 "Free'd ScsiLookup (%d) memory\n",
1092 hd->ioc->name, sz1));
1093
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001094 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001095
1096 /* NULL the Scsi_Host pointer
1097 */
1098 hd->ioc->sh = NULL;
1099
1100 scsi_host_put(host);
1101
1102 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
1106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1107/*
1108 * mptscsih_shutdown - reboot notifier
1109 *
1110 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001111void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001112mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001114 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 struct Scsi_Host *host = ioc->sh;
1116 MPT_SCSI_HOST *hd;
1117
1118 if(!host)
1119 return;
1120
1121 hd = (MPT_SCSI_HOST *)host->hostdata;
1122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123}
1124
1125#ifdef CONFIG_PM
1126/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1127/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 *
1130 *
1131 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001132int
Pavel Machek8d189f72005-04-16 15:25:28 -07001133mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001135 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001136 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
1139/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1140/*
1141 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1142 *
1143 *
1144 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001145int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146mptscsih_resume(struct pci_dev *pdev)
1147{
Hormsb364fd52007-03-19 15:06:44 +09001148 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149}
1150
1151#endif
1152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1154/**
1155 * mptscsih_info - Return information about MPT adapter
1156 * @SChost: Pointer to Scsi_Host structure
1157 *
1158 * (linux scsi_host_template.info routine)
1159 *
1160 * Returns pointer to buffer where information was written.
1161 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001162const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163mptscsih_info(struct Scsi_Host *SChost)
1164{
1165 MPT_SCSI_HOST *h;
1166 int size = 0;
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001171 if (h->info_kbuf == NULL)
1172 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1173 return h->info_kbuf;
1174 h->info_kbuf[0] = '\0';
1175
1176 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1177 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 }
1179
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183struct info_str {
1184 char *buffer;
1185 int length;
1186 int offset;
1187 int pos;
1188};
1189
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001190static void
1191mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192{
1193 if (info->pos + len > info->length)
1194 len = info->length - info->pos;
1195
1196 if (info->pos + len < info->offset) {
1197 info->pos += len;
1198 return;
1199 }
1200
1201 if (info->pos < info->offset) {
1202 data += (info->offset - info->pos);
1203 len -= (info->offset - info->pos);
1204 }
1205
1206 if (len > 0) {
1207 memcpy(info->buffer + info->pos, data, len);
1208 info->pos += len;
1209 }
1210}
1211
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001212static int
1213mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 va_list args;
1216 char buf[81];
1217 int len;
1218
1219 va_start(args, fmt);
1220 len = vsprintf(buf, fmt, args);
1221 va_end(args);
1222
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001223 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 return len;
1225}
1226
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001227static int
1228mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
1230 struct info_str info;
1231
1232 info.buffer = pbuf;
1233 info.length = len;
1234 info.offset = offset;
1235 info.pos = 0;
1236
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001237 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1238 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1239 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1240 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1243}
1244
1245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1246/**
1247 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * @host: scsi host struct
1249 * @buffer: if write, user data; if read, buffer for user
1250 * @start: returns the buffer address
1251 * @offset: if write, 0; if read, the current offset into the buffer from
1252 * the previous read.
1253 * @length: if write, return length;
1254 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 *
1256 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001258int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1260 int length, int func)
1261{
1262 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1263 MPT_ADAPTER *ioc = hd->ioc;
1264 int size = 0;
1265
1266 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001267 /*
1268 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 */
1270 } else {
1271 if (start)
1272 *start = buffer;
1273
1274 size = mptscsih_host_info(ioc, buffer, offset, length);
1275 }
1276
1277 return size;
1278}
1279
1280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1281#define ADD_INDEX_LOG(req_ent) do { } while(0)
1282
1283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1284/**
1285 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1286 * @SCpnt: Pointer to scsi_cmnd structure
1287 * @done: Pointer SCSI mid-layer IO completion function
1288 *
1289 * (linux scsi_host_template.queuecommand routine)
1290 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1291 * from a linux scsi_cmnd request and send it to the IOC.
1292 *
1293 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1294 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001295int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1297{
1298 MPT_SCSI_HOST *hd;
1299 MPT_FRAME_HDR *mf;
1300 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001301 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 int lun;
1303 u32 datalen;
1304 u32 scsictl;
1305 u32 scsidir;
1306 u32 cmd_len;
1307 int my_idx;
1308 int ii;
1309
1310 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 lun = SCpnt->device->lun;
1312 SCpnt->scsi_done = done;
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1315 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1316
1317 if (hd->resetPending) {
1318 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1319 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1320 return SCSI_MLQUEUE_HOST_BUSY;
1321 }
1322
1323 /*
1324 * Put together a MPT SCSI request...
1325 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001326 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1328 hd->ioc->name));
1329 return SCSI_MLQUEUE_HOST_BUSY;
1330 }
1331
1332 pScsiReq = (SCSIIORequest_t *) mf;
1333
1334 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1335
1336 ADD_INDEX_LOG(my_idx);
1337
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001338 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 * Seems we may receive a buffer (datalen>0) even when there
1340 * will be no data transfer! GRRRRR...
1341 */
1342 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001343 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1345 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001346 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1348 } else {
1349 datalen = 0;
1350 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1351 }
1352
1353 /* Default to untagged. Once a target structure has been allocated,
1354 * use the Inquiry data to determine if device supports tagged.
1355 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001356 if (vdev
1357 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 && (SCpnt->device->tagged_supported)) {
1359 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1360 } else {
1361 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1362 }
1363
1364 /* Use the above information to set up the message frame
1365 */
Eric Moore793955f2007-01-29 09:42:20 -07001366 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1367 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001369 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1370 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1371 else
1372 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 pScsiReq->CDBLength = SCpnt->cmd_len;
1374 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1375 pScsiReq->Reserved = 0;
1376 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001377 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 pScsiReq->Control = cpu_to_le32(scsictl);
1379
1380 /*
1381 * Write SCSI CDB into the message
1382 */
1383 cmd_len = SCpnt->cmd_len;
1384 for (ii=0; ii < cmd_len; ii++)
1385 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1386
1387 for (ii=cmd_len; ii < 16; ii++)
1388 pScsiReq->CDB[ii] = 0;
1389
1390 /* DataLength */
1391 pScsiReq->DataLength = cpu_to_le32(datalen);
1392
1393 /* SenseBuffer low address */
1394 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1395 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1396
1397 /* Now add the SG list
1398 * Always have a SGE even if null length.
1399 */
1400 if (datalen == 0) {
1401 /* Add a NULL SGE */
1402 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1403 (dma_addr_t) -1);
1404 } else {
1405 /* Add a 32 or 64 bit SGE */
1406 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1407 goto fail;
1408 }
1409
Eric Moore3dc0b032006-07-11 17:32:33 -06001410 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001413 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1415 hd->ioc->name, SCpnt, mf, my_idx));
1416 DBG_DUMP_REQUEST_FRAME(mf)
1417 return 0;
1418
1419 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001420 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1422 mpt_free_msg_frame(hd->ioc, mf);
1423 return SCSI_MLQUEUE_HOST_BUSY;
1424}
1425
1426/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1427/*
1428 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1429 * with a SCSI IO request
1430 * @hd: Pointer to the MPT_SCSI_HOST instance
1431 * @req_idx: Index of the SCSI IO request frame.
1432 *
1433 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1434 * No return.
1435 */
1436static void
1437mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1438{
1439 MPT_FRAME_HDR *chain;
1440 unsigned long flags;
1441 int chain_idx;
1442 int next;
1443
1444 /* Get the first chain index and reset
1445 * tracker state.
1446 */
1447 chain_idx = ioc->ReqToChain[req_idx];
1448 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1449
1450 while (chain_idx != MPT_HOST_NO_CHAIN) {
1451
1452 /* Save the next chain buffer index */
1453 next = ioc->ChainToChain[chain_idx];
1454
1455 /* Free this chain buffer and reset
1456 * tracker
1457 */
1458 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1459
1460 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1461 + (chain_idx * ioc->req_sz));
1462
1463 spin_lock_irqsave(&ioc->FreeQlock, flags);
1464 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1465 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1466
1467 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1468 ioc->name, chain_idx));
1469
1470 /* handle next */
1471 chain_idx = next;
1472 }
1473 return;
1474}
1475
1476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1477/*
1478 * Reset Handling
1479 */
1480
1481/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001482/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001484 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001486 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001487 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 * @lun: Logical Unit for reset (if appropriate)
1489 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001490 * @timeout: timeout for task management control
1491 *
1492 * Fall through to mpt_HardResetHandler if: not operational, too many
1493 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 *
1495 * Remark: Currently invoked from a non-interrupt thread (_bh).
1496 *
1497 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1498 * will be active.
1499 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001500 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001501 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001502int
Eric Moore793955f2007-01-29 09:42:20 -07001503mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504{
1505 MPT_ADAPTER *ioc;
1506 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 u32 ioc_raw_state;
1508 unsigned long flags;
1509
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1512
1513 // SJR - CHECKME - Can we avoid this here?
1514 // (mpt_HardResetHandler has this check...)
1515 spin_lock_irqsave(&ioc->diagLock, flags);
1516 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1517 spin_unlock_irqrestore(&ioc->diagLock, flags);
1518 return FAILED;
1519 }
1520 spin_unlock_irqrestore(&ioc->diagLock, flags);
1521
1522 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001523 * If we time out and not bus reset, then we return a FAILED status
1524 * to the caller.
1525 * The call to mptscsih_tm_pending_wait() will set the pending flag
1526 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 * successful. Otherwise, reload the FW.
1528 */
1529 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1530 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001531 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 "Timed out waiting for last TM (%d) to complete! \n",
1533 hd->ioc->name, hd->tmPending));
1534 return FAILED;
1535 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001536 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1537 "reset: Timed out waiting for last TM (%d) "
1538 "to complete! \n", hd->ioc->name,
1539 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 return FAILED;
1541 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001542 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 "Timed out waiting for last TM (%d) to complete! \n",
1544 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001545 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547 } else {
1548 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1549 hd->tmPending |= (1 << type);
1550 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1551 }
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1556 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001557 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1558 ioc->name, type, ioc_raw_state);
1559 printk(KERN_WARNING " Issuing HardReset!!\n");
1560 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1561 printk((KERN_WARNING "TMHandler: HardReset "
1562 "FAILED!!\n"));
1563 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
1565
Eric Moorecd2c6192007-01-29 09:47:47 -07001566 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1567 printk(MYIOC_s_WARN_FMT
1568 "TM Handler for type=%x: ioc_state: "
1569 "DOORBELL_ACTIVE (0x%x)!\n",
1570 ioc->name, type, ioc_raw_state);
1571 return FAILED;
1572 }
1573
1574 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001576 if (hd->hard_resets < -1)
1577 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Eric Moorecd2c6192007-01-29 09:47:47 -07001579 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1580 ctx2abort, timeout);
1581 if (rc)
1582 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1583 hd->ioc->name);
1584 else
1585 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1586 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1589
1590 return rc;
1591}
1592
1593
1594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001595/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1597 * @hd: Pointer to MPT_SCSI_HOST structure
1598 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001599 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001600 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 * @lun: Logical Unit for reset (if appropriate)
1602 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001603 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 *
1605 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1606 * or a non-interrupt thread. In the former, must not call schedule().
1607 *
1608 * Not all fields are meaningfull for all task types.
1609 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001610 * Returns 0 for SUCCESS, or FAILED.
1611 *
1612 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613static int
Eric Moore793955f2007-01-29 09:42:20 -07001614mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
1616 MPT_FRAME_HDR *mf;
1617 SCSITaskMgmt_t *pScsiTm;
1618 int ii;
1619 int retval;
1620
1621 /* Return Fail to calling function if no message frames available.
1622 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001623 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1625 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001626 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 }
1628 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1629 hd->ioc->name, mf));
1630
1631 /* Format the Request
1632 */
1633 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001634 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 pScsiTm->Bus = channel;
1636 pScsiTm->ChainOffset = 0;
1637 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1638
1639 pScsiTm->Reserved = 0;
1640 pScsiTm->TaskType = type;
1641 pScsiTm->Reserved1 = 0;
1642 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1643 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1644
Eric Moore793955f2007-01-29 09:42:20 -07001645 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 for (ii=0; ii < 7; ii++)
1648 pScsiTm->Reserved2[ii] = 0;
1649
1650 pScsiTm->TaskMsgContext = ctx2abort;
1651
Eric Moorecd2c6192007-01-29 09:47:47 -07001652 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1653 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1656
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001657 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001658 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1659 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1660 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1661 hd->ioc, mf, retval));
1662 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 }
1664
1665 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001666 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1668 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1670 hd->ioc->name));
1671 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001672 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1673 hd->ioc->name, retval));
1674 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 }
1676
Eric Moorecd2c6192007-01-29 09:47:47 -07001677 /*
1678 * Handle success case, see if theres a non-zero ioc_status.
1679 */
1680 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1681 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1682 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1683 retval = 0;
1684 else
1685 retval = FAILED;
1686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001688
1689 fail_out:
1690
1691 /*
1692 * Free task managment mf, and corresponding tm flags
1693 */
1694 mpt_free_msg_frame(hd->ioc, mf);
1695 hd->tmPending = 0;
1696 hd->tmState = TM_STATE_NONE;
1697 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698}
1699
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001700static int
1701mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1702{
1703 switch (ioc->bus_type) {
1704 case FC:
1705 return 40;
1706 case SAS:
1707 return 10;
1708 case SPI:
1709 default:
1710 return 2;
1711 }
1712}
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1715/**
1716 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1717 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1718 *
1719 * (linux scsi_host_template.eh_abort_handler routine)
1720 *
1721 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001722 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001723int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724mptscsih_abort(struct scsi_cmnd * SCpnt)
1725{
1726 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 MPT_FRAME_HDR *mf;
1728 u32 ctx2abort;
1729 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001730 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001731 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001732 ulong sn = SCpnt->serial_number;
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);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001739 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 "Can't locate host! (sc=%p)\n",
1741 SCpnt));
1742 return FAILED;
1743 }
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /* Find this command
1746 */
1747 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001748 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 * Do OS callback.
1750 */
1751 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001752 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 "Command not in the active list! (sc=%p)\n",
1754 hd->ioc->name, SCpnt));
1755 return SUCCESS;
1756 }
1757
Eric Moorecd2c6192007-01-29 09:47:47 -07001758 if (hd->resetPending)
Moore, Eric65207fe2006-04-21 16:14:35 -06001759 return FAILED;
Moore, Eric65207fe2006-04-21 16:14:35 -06001760
1761 if (hd->timeouts < -1)
1762 hd->timeouts++;
1763
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001764 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1765 hd->ioc->name, SCpnt);
1766 scsi_print_command(SCpnt);
1767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1769 * (the IO to be ABORT'd)
1770 *
1771 * NOTE: Since we do not byteswap MsgContext, we do not
1772 * swap it here either. It is an opaque cookie to
1773 * the controller, so it does not matter. -DaveM
1774 */
1775 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1776 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1777
1778 hd->abortSCpnt = SCpnt;
1779
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001780 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001781 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore793955f2007-01-29 09:42:20 -07001782 vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001783 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Eric Moore3dc0b032006-07-11 17:32:33 -06001785 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001786 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001787 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001788
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001789 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1790 hd->ioc->name,
1791 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001793 if (retval == 0)
1794 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001795 else
1796 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797}
1798
1799/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1800/**
1801 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1802 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1803 *
1804 * (linux scsi_host_template.eh_dev_reset_handler routine)
1805 *
1806 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001807 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001808int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1810{
1811 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001812 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001813 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
1815 /* If we can't locate our host adapter structure, return FAILED status.
1816 */
1817 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001818 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 "Can't locate host! (sc=%p)\n",
1820 SCpnt));
1821 return FAILED;
1822 }
1823
1824 if (hd->resetPending)
1825 return FAILED;
1826
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001827 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001829 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001831 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001832 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -07001833 vdev->vtarget->channel, vdev->vtarget->id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001834 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001835
1836 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1837 hd->ioc->name,
1838 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1839
1840 if (retval == 0)
1841 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001842 else
1843 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844}
1845
Eric Moorecd2c6192007-01-29 09:47:47 -07001846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1848/**
1849 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1850 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1851 *
1852 * (linux scsi_host_template.eh_bus_reset_handler routine)
1853 *
1854 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001855 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001856int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1858{
1859 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001860 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001861 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863 /* If we can't locate our host adapter structure, return FAILED status.
1864 */
1865 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001866 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 "Can't locate host! (sc=%p)\n",
1868 SCpnt ) );
1869 return FAILED;
1870 }
1871
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001872 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001874 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876 if (hd->timeouts < -1)
1877 hd->timeouts++;
1878
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001879 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001880 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore793955f2007-01-29 09:42:20 -07001881 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001883 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1884 hd->ioc->name,
1885 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1886
1887 if (retval == 0)
1888 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001889 else
1890 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891}
1892
1893/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1894/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001895 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1897 *
1898 * (linux scsi_host_template.eh_host_reset_handler routine)
1899 *
1900 * Returns SUCCESS or FAILED.
1901 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001902int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1904{
1905 MPT_SCSI_HOST * hd;
1906 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
1908 /* If we can't locate the host to reset, then we failed. */
1909 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001910 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 "Can't locate host! (sc=%p)\n",
1912 SCpnt ) );
1913 return FAILED;
1914 }
1915
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001916 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 hd->ioc->name, SCpnt);
1918
1919 /* If our attempts to reset the host failed, then return a failed
1920 * status. The host will be taken off line by the SCSI mid-layer.
1921 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1923 status = FAILED;
1924 } else {
1925 /* Make sure TM pending is cleared and TM state is set to
1926 * NONE.
1927 */
1928 hd->tmPending = 0;
1929 hd->tmState = TM_STATE_NONE;
1930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001932 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 "Status = %s\n",
1934 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1935
1936 return status;
1937}
1938
1939/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1940/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001941 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 * @hd: Pointer to MPT host structure.
1943 *
1944 * Returns {SUCCESS,FAILED}.
1945 */
1946static int
1947mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1948{
1949 unsigned long flags;
1950 int loop_count = 4 * 10; /* Wait 10 seconds */
1951 int status = FAILED;
1952
1953 do {
1954 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1955 if (hd->tmState == TM_STATE_NONE) {
1956 hd->tmState = TM_STATE_IN_PROGRESS;
1957 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001959 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961 }
1962 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1963 msleep(250);
1964 } while (--loop_count);
1965
1966 return status;
1967}
1968
1969/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1970/**
1971 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1972 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08001973 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 *
1975 * Returns {SUCCESS,FAILED}.
1976 */
1977static int
1978mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1979{
1980 unsigned long flags;
1981 int loop_count = 4 * timeout;
1982 int status = FAILED;
1983
1984 do {
1985 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1986 if(hd->tmPending == 0) {
1987 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001988 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 break;
1990 }
1991 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05001992 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 } while (--loop_count);
1994
1995 return status;
1996}
1997
1998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07001999static void
2000mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2001{
2002 char *desc;
2003
2004 switch (response_code) {
2005 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2006 desc = "The task completed.";
2007 break;
2008 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2009 desc = "The IOC received an invalid frame status.";
2010 break;
2011 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2012 desc = "The task type is not supported.";
2013 break;
2014 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2015 desc = "The requested task failed.";
2016 break;
2017 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2018 desc = "The task completed successfully.";
2019 break;
2020 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2021 desc = "The LUN request is invalid.";
2022 break;
2023 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2024 desc = "The task is in the IOC queue and has not been sent to target.";
2025 break;
2026 default:
2027 desc = "unknown";
2028 break;
2029 }
2030 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2031 ioc->name, response_code, desc);
2032}
2033
2034/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035/**
2036 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2037 * @ioc: Pointer to MPT_ADAPTER structure
2038 * @mf: Pointer to SCSI task mgmt request frame
2039 * @mr: Pointer to SCSI task mgmt reply frame
2040 *
2041 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2042 * of any SCSI task management request.
2043 * This routine is registered with the MPT (base) driver at driver
2044 * load/init time via the mpt_register() API call.
2045 *
2046 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002047 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002048int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2050{
2051 SCSITaskMgmtReply_t *pScsiTmReply;
2052 SCSITaskMgmt_t *pScsiTmReq;
2053 MPT_SCSI_HOST *hd;
2054 unsigned long flags;
2055 u16 iocstatus;
2056 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002057 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058
2059 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002060 ioc->name, mf, mr));
2061 if (!ioc->sh) {
2062 dtmprintk((MYIOC_s_WARN_FMT
2063 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 return 1;
2065 }
2066
2067 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002068 dtmprintk((MYIOC_s_WARN_FMT
2069 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 }
2072
Eric Moorecd2c6192007-01-29 09:47:47 -07002073 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2074 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2075 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2076 tmType = pScsiTmReq->TaskType;
2077 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2078 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2079
2080 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2081 pScsiTmReply->ResponseCode)
2082 mptscsih_taskmgmt_response_code(ioc,
2083 pScsiTmReply->ResponseCode);
2084 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2085
2086#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2087 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2088 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2089 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2090 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2091 le16_to_cpu(pScsiTmReply->IOCStatus),
2092 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2093 le32_to_cpu(pScsiTmReply->TerminationCount));
2094#endif
2095 if (!iocstatus) {
2096 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2097 hd->abortSCpnt = NULL;
2098 goto out;
2099 }
2100
2101 /* Error? (anything non-zero?) */
2102
2103 /* clear flags and continue.
2104 */
2105 switch (tmType) {
2106
2107 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2108 if (termination_count == 1)
2109 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2110 hd->abortSCpnt = NULL;
2111 break;
2112
2113 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2114
2115 /* If an internal command is present
2116 * or the TM failed - reload the FW.
2117 * FC FW may respond FAILED to an ABORT
2118 */
2119 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2120 hd->cmdPtr)
2121 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2122 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2123 break;
2124
2125 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2126 default:
2127 break;
2128 }
2129
2130 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 spin_lock_irqsave(&ioc->FreeQlock, flags);
2132 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002134 hd->tm_iocstatus = iocstatus;
2135 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
2137 return 1;
2138}
2139
2140/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2141/*
2142 * This is anyones guess quite frankly.
2143 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002144int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2146 sector_t capacity, int geom[])
2147{
2148 int heads;
2149 int sectors;
2150 sector_t cylinders;
2151 ulong dummy;
2152
2153 heads = 64;
2154 sectors = 32;
2155
2156 dummy = heads * sectors;
2157 cylinders = capacity;
2158 sector_div(cylinders,dummy);
2159
2160 /*
2161 * Handle extended translation size for logical drives
2162 * > 1Gb
2163 */
2164 if ((ulong)capacity >= 0x200000) {
2165 heads = 255;
2166 sectors = 63;
2167 dummy = heads * sectors;
2168 cylinders = capacity;
2169 sector_div(cylinders,dummy);
2170 }
2171
2172 /* return result */
2173 geom[0] = heads;
2174 geom[1] = sectors;
2175 geom[2] = cylinders;
2176
2177 dprintk((KERN_NOTICE
2178 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002179 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
2181 return 0;
2182}
2183
Moore, Ericf44e5462006-03-14 09:14:21 -07002184/* Search IOC page 3 to determine if this is hidden physical disk
2185 *
2186 */
2187int
Eric Moore793955f2007-01-29 09:42:20 -07002188mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002189{
Eric Mooreb506ade2007-01-29 09:45:37 -07002190 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002191 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002192 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002193
Eric Moore793955f2007-01-29 09:42:20 -07002194 if (!ioc->raid_data.pIocPg3)
2195 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002196 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002197 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2198 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2199 rc = 1;
2200 goto out;
2201 }
2202 }
2203
Eric Mooreb506ade2007-01-29 09:45:37 -07002204 /*
2205 * Check inactive list for matching phys disks
2206 */
2207 if (list_empty(&ioc->raid_data.inactive_list))
2208 goto out;
2209
2210 down(&ioc->raid_data.inactive_list_mutex);
2211 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2212 list) {
2213 if ((component_info->d.PhysDiskID == id) &&
2214 (component_info->d.PhysDiskBus == channel))
2215 rc = 1;
2216 }
2217 up(&ioc->raid_data.inactive_list_mutex);
2218
Eric Moore793955f2007-01-29 09:42:20 -07002219 out:
2220 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002221}
2222EXPORT_SYMBOL(mptscsih_is_phys_disk);
2223
Eric Moore793955f2007-01-29 09:42:20 -07002224u8
2225mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002226{
Eric Mooreb506ade2007-01-29 09:45:37 -07002227 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002228 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002229 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002230
Eric Moore793955f2007-01-29 09:42:20 -07002231 if (!ioc->raid_data.pIocPg3)
2232 goto out;
2233 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2234 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2235 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2236 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2237 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002238 }
2239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
Eric Mooreb506ade2007-01-29 09:45:37 -07002241 /*
2242 * Check inactive list for matching phys disks
2243 */
2244 if (list_empty(&ioc->raid_data.inactive_list))
2245 goto out;
2246
2247 down(&ioc->raid_data.inactive_list_mutex);
2248 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2249 list) {
2250 if ((component_info->d.PhysDiskID == id) &&
2251 (component_info->d.PhysDiskBus == channel))
2252 rc = component_info->d.PhysDiskNum;
2253 }
2254 up(&ioc->raid_data.inactive_list_mutex);
2255
Eric Moore793955f2007-01-29 09:42:20 -07002256 out:
2257 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002258}
Eric Moore793955f2007-01-29 09:42:20 -07002259EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002260
2261/*
2262 * OS entry point to allow for host driver to free allocated memory
2263 * Called if no device present or device being unloaded
2264 */
2265void
2266mptscsih_slave_destroy(struct scsi_device *sdev)
2267{
2268 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002270 VirtTarget *vtarget;
2271 VirtDevice *vdevice;
2272 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002274 starget = scsi_target(sdev);
2275 vtarget = starget->hostdata;
2276 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002278 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002279 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002280 mptscsih_synchronize_cache(hd, vdevice);
2281 kfree(vdevice);
2282 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283}
2284
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002285/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2286/*
2287 * mptscsih_change_queue_depth - This function will set a devices queue depth
2288 * @sdev: per scsi_device pointer
2289 * @qdepth: requested queue depth
2290 *
2291 * Adding support for new 'change_queue_depth' api.
2292*/
2293int
2294mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002296 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2297 VirtTarget *vtarget;
2298 struct scsi_target *starget;
2299 int max_depth;
2300 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002302 starget = scsi_target(sdev);
2303 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002304
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002305 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002306 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002308 else if (sdev->type == TYPE_DISK &&
2309 vtarget->minSyncFactor <= MPT_ULTRA160)
2310 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2311 else
2312 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 } else
2314 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2315
2316 if (qdepth > max_depth)
2317 qdepth = max_depth;
2318 if (qdepth == 1)
2319 tagged = 0;
2320 else
2321 tagged = MSG_SIMPLE_TAG;
2322
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002323 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2324 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325}
2326
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327/*
2328 * OS entry point to adjust the queue_depths on a per-device basis.
2329 * Called once per device the bus scan. Use it to force the queue_depth
2330 * member to 1 if a device does not support Q tags.
2331 * Return non-zero if fails.
2332 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002333int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002334mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002336 struct Scsi_Host *sh = sdev->host;
2337 VirtTarget *vtarget;
2338 VirtDevice *vdevice;
2339 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2341
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002342 starget = scsi_target(sdev);
2343 vtarget = starget->hostdata;
2344 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
2346 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002347 "device @ %p, channel=%d, id=%d, lun=%d\n",
2348 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002349 if (hd->ioc->bus_type == SPI)
2350 dsprintk((MYIOC_s_INFO_FMT
2351 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2352 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2353 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002355 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002357 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 goto slave_configure_exit;
2359 }
2360
Eric Moore793955f2007-01-29 09:42:20 -07002361 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002362 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
2364 dsprintk((MYIOC_s_INFO_FMT
2365 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002366 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368 if (hd->ioc->bus_type == SPI)
2369 dsprintk((MYIOC_s_INFO_FMT
2370 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2371 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2372 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
2374slave_configure_exit:
2375
2376 dsprintk((MYIOC_s_INFO_FMT
2377 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002378 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2379 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
2381 return 0;
2382}
2383
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2385/*
2386 * Private routines...
2387 */
2388
2389/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2390/* Utility function to copy sense data from the scsi_cmnd buffer
2391 * to the FC and SCSI target structures.
2392 *
2393 */
2394static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002395mptscsih_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 -07002396{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002397 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 SCSIIORequest_t *pReq;
2399 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401 /* Get target structure
2402 */
2403 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002404 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406 if (sense_count) {
2407 u8 *sense_data;
2408 int req_index;
2409
2410 /* Copy the sense received into the scsi command block. */
2411 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2412 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2413 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2414
2415 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2416 */
2417 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 int idx;
2420 MPT_ADAPTER *ioc = hd->ioc;
2421
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002422 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2424 ioc->events[idx].eventContext = ioc->eventContext;
2425
2426 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2427 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002428 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
2430 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2431
2432 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002433 if (hd->ioc->pcidev->vendor ==
2434 PCI_VENDOR_ID_IBM) {
2435 mptscsih_issue_sep_command(hd->ioc,
2436 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2437 vdev->vtarget->tflags |=
2438 MPT_TARGET_FLAGS_LED_ON;
2439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 }
2441 }
2442 } else {
2443 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2444 hd->ioc->name));
2445 }
2446}
2447
Eric Moore3dc0b032006-07-11 17:32:33 -06002448static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2450{
2451 MPT_SCSI_HOST *hd;
2452 int i;
2453
2454 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2455
2456 for (i = 0; i < hd->ioc->req_depth; i++) {
2457 if (hd->ScsiLookup[i] == sc) {
2458 return i;
2459 }
2460 }
2461
2462 return -1;
2463}
2464
2465/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002466int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2468{
2469 MPT_SCSI_HOST *hd;
2470 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002471 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473 dtmprintk((KERN_WARNING MYNAM
2474 ": IOC %s_reset routed to SCSI host driver!\n",
2475 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2476 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2477
2478 /* If a FW reload request arrives after base installed but
2479 * before all scsi hosts have been attached, then an alt_ioc
2480 * may have a NULL sh pointer.
2481 */
2482 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2483 return 0;
2484 else
2485 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2486
2487 if (reset_phase == MPT_IOC_SETUP_RESET) {
2488 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2489
2490 /* Clean Up:
2491 * 1. Set Hard Reset Pending Flag
2492 * All new commands go to doneQ
2493 */
2494 hd->resetPending = 1;
2495
2496 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2497 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2498
2499 /* 2. Flush running commands
2500 * Clean ScsiLookup (and associated memory)
2501 * AND clean mytaskQ
2502 */
2503
2504 /* 2b. Reply to OS all known outstanding I/O commands.
2505 */
2506 mptscsih_flush_running_cmds(hd);
2507
2508 /* 2c. If there was an internal command that
2509 * has not completed, configuration or io request,
2510 * free these resources.
2511 */
2512 if (hd->cmdPtr) {
2513 del_timer(&hd->timer);
2514 mpt_free_msg_frame(ioc, hd->cmdPtr);
2515 }
2516
2517 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2518
2519 } else {
2520 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2521
2522 /* Once a FW reload begins, all new OS commands are
2523 * redirected to the doneQ w/ a reset status.
2524 * Init all control structures.
2525 */
2526
2527 /* ScsiLookup initialization
2528 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002529 for (ii=0; ii < hd->ioc->req_depth; ii++)
2530 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
2532 /* 2. Chain Buffer initialization
2533 */
2534
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002535 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
2538 /* 5. Enable new commands to be posted
2539 */
2540 spin_lock_irqsave(&ioc->FreeQlock, flags);
2541 hd->tmPending = 0;
2542 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2543 hd->resetPending = 0;
2544 hd->tmState = TM_STATE_NONE;
2545
2546 /* 6. If there was an internal command,
2547 * wake this process up.
2548 */
2549 if (hd->cmdPtr) {
2550 /*
2551 * Wake up the original calling thread
2552 */
2553 hd->pLocal = &hd->localReply;
2554 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002555 hd->scandv_wait_done = 1;
2556 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 hd->cmdPtr = NULL;
2558 }
2559
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2561
2562 }
2563
2564 return 1; /* currently means nothing really */
2565}
2566
2567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002568int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2570{
2571 MPT_SCSI_HOST *hd;
2572 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2573
Moore, Eric3a892be2006-03-14 09:14:03 -07002574 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 ioc->name, event));
2576
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002577 if (ioc->sh == NULL ||
2578 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2579 return 1;
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 switch (event) {
2582 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2583 /* FIXME! */
2584 break;
2585 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2586 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002587 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002588 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 break;
2590 case MPI_EVENT_LOGOUT: /* 09 */
2591 /* FIXME! */
2592 break;
2593
Michael Reed05e8ec12006-01-13 14:31:54 -06002594 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002595 break;
2596
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 /*
2598 * CHECKME! Don't think we need to do
2599 * anything for these, but...
2600 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2602 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2603 /*
2604 * CHECKME! Falling thru...
2605 */
2606 break;
2607
2608 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002609 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 case MPI_EVENT_NONE: /* 00 */
2612 case MPI_EVENT_LOG_DATA: /* 01 */
2613 case MPI_EVENT_STATE_CHANGE: /* 02 */
2614 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2615 default:
2616 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2617 break;
2618 }
2619
2620 return 1; /* currently means nothing really */
2621}
2622
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2624/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 * Bus Scan and Domain Validation functionality ...
2626 */
2627
2628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2629/*
2630 * mptscsih_scandv_complete - Scan and DV callback routine registered
2631 * to Fustion MPT (base) driver.
2632 *
2633 * @ioc: Pointer to MPT_ADAPTER structure
2634 * @mf: Pointer to original MPT request frame
2635 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2636 *
2637 * This routine is called from mpt.c::mpt_interrupt() at the completion
2638 * of any SCSI IO request.
2639 * This routine is registered with the Fusion MPT (base) driver at driver
2640 * load/init time via the mpt_register() API call.
2641 *
2642 * Returns 1 indicating alloc'd request frame ptr should be freed.
2643 *
2644 * Remark: Sets a completion code and (possibly) saves sense data
2645 * in the IOC member localReply structure.
2646 * Used ONLY for DV and other internal commands.
2647 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002648int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2650{
2651 MPT_SCSI_HOST *hd;
2652 SCSIIORequest_t *pReq;
2653 int completionCode;
2654 u16 req_idx;
2655
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002656 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 if ((mf == NULL) ||
2659 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2660 printk(MYIOC_s_ERR_FMT
2661 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2662 ioc->name, mf?"BAD":"NULL", (void *) mf);
2663 goto wakeup;
2664 }
2665
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 del_timer(&hd->timer);
2667 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2668 hd->ScsiLookup[req_idx] = NULL;
2669 pReq = (SCSIIORequest_t *) mf;
2670
2671 if (mf != hd->cmdPtr) {
2672 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2673 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2674 }
2675 hd->cmdPtr = NULL;
2676
2677 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2678 hd->ioc->name, mf, mr, req_idx));
2679
2680 hd->pLocal = &hd->localReply;
2681 hd->pLocal->scsiStatus = 0;
2682
2683 /* If target struct exists, clear sense valid flag.
2684 */
2685 if (mr == NULL) {
2686 completionCode = MPT_SCANDV_GOOD;
2687 } else {
2688 SCSIIOReply_t *pReply;
2689 u16 status;
2690 u8 scsi_status;
2691
2692 pReply = (SCSIIOReply_t *) mr;
2693
2694 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2695 scsi_status = pReply->SCSIStatus;
2696
2697 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2698 status, pReply->SCSIState, scsi_status,
2699 le32_to_cpu(pReply->IOCLogInfo)));
2700
2701 switch(status) {
2702
2703 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2704 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2705 break;
2706
2707 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2708 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2709 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2710 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2711 completionCode = MPT_SCANDV_DID_RESET;
2712 break;
2713
2714 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2715 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2716 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2717 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2718 ConfigReply_t *pr = (ConfigReply_t *)mr;
2719 completionCode = MPT_SCANDV_GOOD;
2720 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2721 hd->pLocal->header.PageLength = pr->Header.PageLength;
2722 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2723 hd->pLocal->header.PageType = pr->Header.PageType;
2724
2725 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2726 /* If the RAID Volume request is successful,
2727 * return GOOD, else indicate that
2728 * some type of error occurred.
2729 */
2730 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002731 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 completionCode = MPT_SCANDV_GOOD;
2733 else
2734 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002735 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2738 u8 *sense_data;
2739 int sz;
2740
2741 /* save sense data in global structure
2742 */
2743 completionCode = MPT_SCANDV_SENSE;
2744 hd->pLocal->scsiStatus = scsi_status;
2745 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2746 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2747
2748 sz = min_t(int, pReq->SenseBufferLength,
2749 SCSI_STD_SENSE_BYTES);
2750 memcpy(hd->pLocal->sense, sense_data, sz);
2751
2752 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2753 sense_data));
2754 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2755 if (pReq->CDB[0] == INQUIRY)
2756 completionCode = MPT_SCANDV_ISSUE_SENSE;
2757 else
2758 completionCode = MPT_SCANDV_DID_RESET;
2759 }
2760 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2761 completionCode = MPT_SCANDV_DID_RESET;
2762 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2763 completionCode = MPT_SCANDV_DID_RESET;
2764 else {
2765 completionCode = MPT_SCANDV_GOOD;
2766 hd->pLocal->scsiStatus = scsi_status;
2767 }
2768 break;
2769
2770 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2771 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2772 completionCode = MPT_SCANDV_DID_RESET;
2773 else
2774 completionCode = MPT_SCANDV_SOME_ERROR;
2775 break;
2776
2777 default:
2778 completionCode = MPT_SCANDV_SOME_ERROR;
2779 break;
2780
2781 } /* switch(status) */
2782
2783 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2784 completionCode));
2785 } /* end of address reply case */
2786
2787 hd->pLocal->completion = completionCode;
2788
2789 /* MF and RF are freed in mpt_interrupt
2790 */
2791wakeup:
2792 /* Free Chain buffers (will never chain) in scan or dv */
2793 //mptscsih_freeChainBuffers(ioc, req_idx);
2794
2795 /*
2796 * Wake up the original calling thread
2797 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002798 hd->scandv_wait_done = 1;
2799 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
2801 return 1;
2802}
2803
2804/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2805/* mptscsih_timer_expired - Call back for timer process.
2806 * Used only for dv functionality.
2807 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2808 *
2809 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002810void
2811mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812{
2813 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2814
2815 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2816
2817 if (hd->cmdPtr) {
2818 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2819
2820 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2821 /* Desire to issue a task management request here.
2822 * TM requests MUST be single threaded.
2823 * If old eh code and no TM current, issue request.
2824 * If new eh code, do nothing. Wait for OS cmd timeout
2825 * for bus reset.
2826 */
2827 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2828 } else {
2829 /* Perform a FW reload */
2830 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2831 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2832 }
2833 }
2834 } else {
2835 /* This should NEVER happen */
2836 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2837 }
2838
2839 /* No more processing.
2840 * TM call will generate an interrupt for SCSI TM Management.
2841 * The FW will reply to all outstanding commands, callback will finish cleanup.
2842 * Hard reset clean-up will free all resources.
2843 */
2844 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2845
2846 return;
2847}
2848
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
2850/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2851/**
2852 * mptscsih_do_cmd - Do internal command.
2853 * @hd: MPT_SCSI_HOST pointer
2854 * @io: INTERNAL_CMD pointer.
2855 *
2856 * Issue the specified internally generated command and do command
2857 * specific cleanup. For bus scan / DV only.
2858 * NOTES: If command is Inquiry and status is good,
2859 * initialize a target structure, save the data
2860 *
2861 * Remark: Single threaded access only.
2862 *
2863 * Return:
2864 * < 0 if an illegal command or no resources
2865 *
2866 * 0 if good
2867 *
2868 * > 0 if command complete but some type of completion error.
2869 */
2870static int
2871mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2872{
2873 MPT_FRAME_HDR *mf;
2874 SCSIIORequest_t *pScsiReq;
2875 SCSIIORequest_t ReqCopy;
2876 int my_idx, ii, dir;
2877 int rc, cmdTimeout;
2878 int in_isr;
2879 char cmdLen;
2880 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2881 char cmd = io->cmd;
2882
2883 in_isr = in_interrupt();
2884 if (in_isr) {
2885 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2886 hd->ioc->name));
2887 return -EPERM;
2888 }
2889
2890
2891 /* Set command specific information
2892 */
2893 switch (cmd) {
2894 case INQUIRY:
2895 cmdLen = 6;
2896 dir = MPI_SCSIIO_CONTROL_READ;
2897 CDB[0] = cmd;
2898 CDB[4] = io->size;
2899 cmdTimeout = 10;
2900 break;
2901
2902 case TEST_UNIT_READY:
2903 cmdLen = 6;
2904 dir = MPI_SCSIIO_CONTROL_READ;
2905 cmdTimeout = 10;
2906 break;
2907
2908 case START_STOP:
2909 cmdLen = 6;
2910 dir = MPI_SCSIIO_CONTROL_READ;
2911 CDB[0] = cmd;
2912 CDB[4] = 1; /*Spin up the disk */
2913 cmdTimeout = 15;
2914 break;
2915
2916 case REQUEST_SENSE:
2917 cmdLen = 6;
2918 CDB[0] = cmd;
2919 CDB[4] = io->size;
2920 dir = MPI_SCSIIO_CONTROL_READ;
2921 cmdTimeout = 10;
2922 break;
2923
2924 case READ_BUFFER:
2925 cmdLen = 10;
2926 dir = MPI_SCSIIO_CONTROL_READ;
2927 CDB[0] = cmd;
2928 if (io->flags & MPT_ICFLAG_ECHO) {
2929 CDB[1] = 0x0A;
2930 } else {
2931 CDB[1] = 0x02;
2932 }
2933
2934 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2935 CDB[1] |= 0x01;
2936 }
2937 CDB[6] = (io->size >> 16) & 0xFF;
2938 CDB[7] = (io->size >> 8) & 0xFF;
2939 CDB[8] = io->size & 0xFF;
2940 cmdTimeout = 10;
2941 break;
2942
2943 case WRITE_BUFFER:
2944 cmdLen = 10;
2945 dir = MPI_SCSIIO_CONTROL_WRITE;
2946 CDB[0] = cmd;
2947 if (io->flags & MPT_ICFLAG_ECHO) {
2948 CDB[1] = 0x0A;
2949 } else {
2950 CDB[1] = 0x02;
2951 }
2952 CDB[6] = (io->size >> 16) & 0xFF;
2953 CDB[7] = (io->size >> 8) & 0xFF;
2954 CDB[8] = io->size & 0xFF;
2955 cmdTimeout = 10;
2956 break;
2957
2958 case RESERVE:
2959 cmdLen = 6;
2960 dir = MPI_SCSIIO_CONTROL_READ;
2961 CDB[0] = cmd;
2962 cmdTimeout = 10;
2963 break;
2964
2965 case RELEASE:
2966 cmdLen = 6;
2967 dir = MPI_SCSIIO_CONTROL_READ;
2968 CDB[0] = cmd;
2969 cmdTimeout = 10;
2970 break;
2971
2972 case SYNCHRONIZE_CACHE:
2973 cmdLen = 10;
2974 dir = MPI_SCSIIO_CONTROL_READ;
2975 CDB[0] = cmd;
2976// CDB[1] = 0x02; /* set immediate bit */
2977 cmdTimeout = 10;
2978 break;
2979
2980 default:
2981 /* Error Case */
2982 return -EFAULT;
2983 }
2984
2985 /* Get and Populate a free Frame
2986 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002987 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
2989 hd->ioc->name));
2990 return -EBUSY;
2991 }
2992
2993 pScsiReq = (SCSIIORequest_t *) mf;
2994
2995 /* Get the request index */
2996 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2997 ADD_INDEX_LOG(my_idx); /* for debug */
2998
2999 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3000 pScsiReq->TargetID = io->physDiskNum;
3001 pScsiReq->Bus = 0;
3002 pScsiReq->ChainOffset = 0;
3003 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3004 } else {
3005 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003006 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 pScsiReq->ChainOffset = 0;
3008 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3009 }
3010
3011 pScsiReq->CDBLength = cmdLen;
3012 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3013
3014 pScsiReq->Reserved = 0;
3015
3016 pScsiReq->MsgFlags = mpt_msg_flags();
3017 /* MsgContext set in mpt_get_msg_fram call */
3018
Eric Moore793955f2007-01-29 09:42:20 -07003019 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
3021 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3022 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3023 else
3024 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3025
3026 if (cmd == REQUEST_SENSE) {
3027 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3028 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3029 hd->ioc->name, cmd));
3030 }
3031
3032 for (ii=0; ii < 16; ii++)
3033 pScsiReq->CDB[ii] = CDB[ii];
3034
3035 pScsiReq->DataLength = cpu_to_le32(io->size);
3036 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3037 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3038
3039 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003040 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
3042 if (dir == MPI_SCSIIO_CONTROL_READ) {
3043 mpt_add_sge((char *) &pScsiReq->SGL,
3044 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3045 io->data_dma);
3046 } else {
3047 mpt_add_sge((char *) &pScsiReq->SGL,
3048 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3049 io->data_dma);
3050 }
3051
3052 /* The ISR will free the request frame, but we need
3053 * the information to initialize the target. Duplicate.
3054 */
3055 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3056
3057 /* Issue this command after:
3058 * finish init
3059 * add timer
3060 * Wait until the reply has been received
3061 * ScsiScanDvCtx callback function will
3062 * set hd->pLocal;
3063 * set scandv_wait_done and call wake_up
3064 */
3065 hd->pLocal = NULL;
3066 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003067 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
3069 /* Save cmd pointer, for resource free if timeout or
3070 * FW reload occurs
3071 */
3072 hd->cmdPtr = mf;
3073
3074 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003075 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3076 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
3078 if (hd->pLocal) {
3079 rc = hd->pLocal->completion;
3080 hd->pLocal->skip = 0;
3081
3082 /* Always set fatal error codes in some cases.
3083 */
3084 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3085 rc = -ENXIO;
3086 else if (rc == MPT_SCANDV_SOME_ERROR)
3087 rc = -rc;
3088 } else {
3089 rc = -EFAULT;
3090 /* This should never happen. */
3091 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3092 hd->ioc->name));
3093 }
3094
3095 return rc;
3096}
3097
3098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3099/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003100 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3101 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003102 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003103 *
3104 * Uses the ISR, but with special processing.
3105 * MUST be single-threaded.
3106 *
3107 */
3108static void
3109mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3110{
3111 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
3113 /* Following parameters will not change
3114 * in this routine.
3115 */
3116 iocmd.cmd = SYNCHRONIZE_CACHE;
3117 iocmd.flags = 0;
3118 iocmd.physDiskNum = -1;
3119 iocmd.data = NULL;
3120 iocmd.data_dma = -1;
3121 iocmd.size = 0;
3122 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003123 iocmd.channel = vdevice->vtarget->channel;
3124 iocmd.id = vdevice->vtarget->id;
3125 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
James Bottomleyc92f2222006-03-01 09:02:49 -06003127 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003128 (vdevice->configured_lun))
3129 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130}
3131
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003132EXPORT_SYMBOL(mptscsih_remove);
3133EXPORT_SYMBOL(mptscsih_shutdown);
3134#ifdef CONFIG_PM
3135EXPORT_SYMBOL(mptscsih_suspend);
3136EXPORT_SYMBOL(mptscsih_resume);
3137#endif
3138EXPORT_SYMBOL(mptscsih_proc_info);
3139EXPORT_SYMBOL(mptscsih_info);
3140EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003141EXPORT_SYMBOL(mptscsih_slave_destroy);
3142EXPORT_SYMBOL(mptscsih_slave_configure);
3143EXPORT_SYMBOL(mptscsih_abort);
3144EXPORT_SYMBOL(mptscsih_dev_reset);
3145EXPORT_SYMBOL(mptscsih_bus_reset);
3146EXPORT_SYMBOL(mptscsih_host_reset);
3147EXPORT_SYMBOL(mptscsih_bios_param);
3148EXPORT_SYMBOL(mptscsih_io_done);
3149EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3150EXPORT_SYMBOL(mptscsih_scandv_complete);
3151EXPORT_SYMBOL(mptscsih_event_process);
3152EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003153EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003154EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003155EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/