blob: eef00ed139b92752f081ee1d575cc6a0b1d996b8 [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 */
263 if ( (sges_left = SCpnt->use_sg) ) {
264 sges_left = pci_map_sg(ioc->pcidev,
265 (struct scatterlist *) SCpnt->request_buffer,
266 SCpnt->use_sg,
267 SCpnt->sc_data_direction);
268 if (sges_left == 0)
269 return FAILED;
270 } else if (SCpnt->request_bufflen) {
271 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
272 SCpnt->request_buffer,
273 SCpnt->request_bufflen,
274 SCpnt->sc_data_direction);
275 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
276 ioc->name, SCpnt, SCpnt->request_bufflen));
277 mptscsih_add_sge((char *) &pReq->SGL,
278 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
279 SCpnt->SCp.dma_handle);
280
281 return SUCCESS;
282 }
283
284 /* Handle the SG case.
285 */
286 sg = (struct scatterlist *) SCpnt->request_buffer;
287 sg_done = 0;
288 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
289 chainSge = NULL;
290
291 /* Prior to entering this loop - the following must be set
292 * current MF: sgeOffset (bytes)
293 * chainSge (Null if original MF is not a chain buffer)
294 * sg_done (num SGE done for this MF)
295 */
296
297nextSGEset:
298 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
299 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
300
301 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
302
303 /* Get first (num - 1) SG elements
304 * Skip any SG entries with a length of 0
305 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
306 */
307 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
308 thisxfer = sg_dma_len(sg);
309 if (thisxfer == 0) {
310 sg ++; /* Get next SG element from the OS */
311 sg_done++;
312 continue;
313 }
314
315 v2 = sg_dma_address(sg);
316 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
317
318 sg++; /* Get next SG element from the OS */
319 psge += (sizeof(u32) + sizeof(dma_addr_t));
320 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
321 sg_done++;
322 }
323
324 if (numSgeThisFrame == sges_left) {
325 /* Add last element, end of buffer and end of list flags.
326 */
327 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
328 MPT_SGE_FLAGS_END_OF_BUFFER |
329 MPT_SGE_FLAGS_END_OF_LIST;
330
331 /* Add last SGE and set termination flags.
332 * Note: Last SGE may have a length of 0 - which should be ok.
333 */
334 thisxfer = sg_dma_len(sg);
335
336 v2 = sg_dma_address(sg);
337 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
338 /*
339 sg++;
340 psge += (sizeof(u32) + sizeof(dma_addr_t));
341 */
342 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
343 sg_done++;
344
345 if (chainSge) {
346 /* The current buffer is a chain buffer,
347 * but there is not another one.
348 * Update the chain element
349 * Offset and Length fields.
350 */
351 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
352 } else {
353 /* The current buffer is the original MF
354 * and there is no Chain buffer.
355 */
356 pReq->ChainOffset = 0;
357 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200358 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
360 ioc->RequestNB[req_idx] = RequestNB;
361 }
362 } else {
363 /* At least one chain buffer is needed.
364 * Complete the first MF
365 * - last SGE element, set the LastElement bit
366 * - set ChainOffset (words) for orig MF
367 * (OR finish previous MF chain buffer)
368 * - update MFStructPtr ChainIndex
369 * - Populate chain element
370 * Also
371 * Loop until done.
372 */
373
374 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
375 ioc->name, sg_done));
376
377 /* Set LAST_ELEMENT flag for last non-chain element
378 * in the buffer. Since psge points at the NEXT
379 * SGE element, go back one SGE element, update the flags
380 * and reset the pointer. (Note: sgflags & thisxfer are already
381 * set properly).
382 */
383 if (sg_done) {
384 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
385 sgflags = le32_to_cpu(*ptmp);
386 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
387 *ptmp = cpu_to_le32(sgflags);
388 }
389
390 if (chainSge) {
391 /* The current buffer is a chain buffer.
392 * chainSge points to the previous Chain Element.
393 * Update its chain element Offset and Length (must
394 * include chain element size) fields.
395 * Old chain element is now complete.
396 */
397 u8 nextChain = (u8) (sgeOffset >> 2);
398 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
399 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
400 } else {
401 /* The original MF buffer requires a chain buffer -
402 * set the offset.
403 * Last element in this MF is a chain element.
404 */
405 pReq->ChainOffset = (u8) (sgeOffset >> 2);
406 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
407 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
408 ioc->RequestNB[req_idx] = RequestNB;
409 }
410
411 sges_left -= sg_done;
412
413
414 /* NOTE: psge points to the beginning of the chain element
415 * in current buffer. Get a chain buffer.
416 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200417 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
418 dfailprintk((MYIOC_s_INFO_FMT
419 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
420 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 /* Update the tracking arrays.
425 * If chainSge == NULL, update ReqToChain, else ChainToChain
426 */
427 if (chainSge) {
428 ioc->ChainToChain[chain_idx] = newIndex;
429 } else {
430 ioc->ReqToChain[req_idx] = newIndex;
431 }
432 chain_idx = newIndex;
433 chain_dma_off = ioc->req_sz * chain_idx;
434
435 /* Populate the chainSGE for the current buffer.
436 * - Set chain buffer pointer to psge and fill
437 * out the Address and Flags fields.
438 */
439 chainSge = (char *) psge;
440 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
441 psge, req_idx));
442
443 /* Start the SGE for the next buffer
444 */
445 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
446 sgeOffset = 0;
447 sg_done = 0;
448
449 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
450 psge, chain_idx));
451
452 /* Start the SGE for the next buffer
453 */
454
455 goto nextSGEset;
456 }
457
458 return SUCCESS;
459} /* mptscsih_AddSGE() */
460
Eric Moore786899b2006-07-11 17:22:22 -0600461static void
462mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
463 U32 SlotStatus)
464{
465 MPT_FRAME_HDR *mf;
466 SEPRequest_t *SEPMsg;
467
468 if (ioc->bus_type == FC)
469 return;
470
471 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
472 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
473 ioc->name,__FUNCTION__));
474 return;
475 }
476
477 SEPMsg = (SEPRequest_t *)mf;
478 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700479 SEPMsg->Bus = vtarget->channel;
480 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600481 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
482 SEPMsg->SlotStatus = SlotStatus;
483 devtverboseprintk((MYIOC_s_WARN_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700484 "Sending SEP cmd=%x channel=%d id=%d\n",
485 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600486 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
487}
488
Eric Moorec6c727a2007-01-29 09:44:54 -0700489#ifdef MPT_DEBUG_REPLY
490/**
491 * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
492 * @ioc: Pointer to MPT_ADAPTER structure
493 * @ioc_status: U32 IOCStatus word from IOC
494 * @scsi_status: U8 sam status from target
495 * @scsi_state: U8 scsi state
496 * @sc: original scsi cmnd pointer
497 * @mf: Pointer to MPT request frame
498 *
499 * Refer to lsi/mpi.h.
500 **/
501static void
502mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
503 u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
504{
505 char extend_desc[EVENT_DESCR_STR_SZ];
506 char *desc = NULL;
507
508 switch (ioc_status) {
509
510 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
511 desc = "SCSI Invalid Bus";
512 break;
513
514 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
515 desc = "SCSI Invalid TargetID";
516 break;
517
518 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
519 /*
520 * Inquiry is issued for device scanning
521 */
522 if (sc->cmnd[0] != 0x12)
523 desc = "SCSI Device Not There";
524 break;
525
526 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
527 desc = "SCSI Data Overrun";
528 break;
529
530 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
531 desc = "SCSI I/O Data Error";
532 break;
533
534 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
535 desc = "SCSI Protocol Error";
536 break;
537
538 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
539 desc = "SCSI Task Terminated";
540 break;
541
542 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
543 desc = "SCSI Residual Mismatch";
544 break;
545
546 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
547 desc = "SCSI Task Management Failed";
548 break;
549
550 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
551 desc = "SCSI IOC Terminated";
552 break;
553
554 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
555 desc = "SCSI Ext Terminated";
556 break;
557 }
558
559 if (!desc)
560 return;
561
562 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
563 "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
564 sc->device->host->host_no,
565 sc->device->channel, sc->device->id, sc->device->lun,
566 sc->cmnd[0], scsi_status, scsi_state);
567
568 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
569 ioc->name, ioc_status, desc, extend_desc);
570}
571#endif
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
574/*
575 * mptscsih_io_done - Main SCSI IO callback routine registered to
576 * Fusion MPT (base) driver
577 * @ioc: Pointer to MPT_ADAPTER structure
578 * @mf: Pointer to original MPT request frame
579 * @r: Pointer to MPT reply frame (NULL if TurboReply)
580 *
581 * This routine is called from mpt.c::mpt_interrupt() at the completion
582 * of any SCSI IO request.
583 * This routine is registered with the Fusion MPT (base) driver at driver
584 * load/init time via the mpt_register() API call.
585 *
586 * Returns 1 indicating alloc'd request frame ptr should be freed.
587 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400588int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
590{
591 struct scsi_cmnd *sc;
592 MPT_SCSI_HOST *hd;
593 SCSIIORequest_t *pScsiReq;
594 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700595 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600596 VirtDevice *vdev;
597 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
600
601 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700602 req_idx_MR = (mr != NULL) ?
603 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
604 if ((req_idx != req_idx_MR) ||
605 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
606 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
607 ioc->name);
608 printk (MYIOC_s_ERR_FMT
609 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
610 ioc->name, req_idx, req_idx_MR, mf, mr,
611 hd->ScsiLookup[req_idx_MR]);
612 return 0;
613 }
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600616 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 if (sc == NULL) {
618 MPIHeader_t *hdr = (MPIHeader_t *)mf;
619
620 /* Remark: writeSDP1 will use the ScsiDoneCtx
621 * If a SCSI I/O cmd, device disabled by OS and
622 * completion done. Cannot touch sc struct. Just free mem.
623 */
624 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
625 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
626 ioc->name);
627
628 mptscsih_freeChainBuffers(ioc, req_idx);
629 return 1;
630 }
631
Eric Moore3dc0b032006-07-11 17:32:33 -0600632 if ((unsigned char *)mf != sc->host_scribble) {
633 mptscsih_freeChainBuffers(ioc, req_idx);
634 return 1;
635 }
636
637 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 sc->result = DID_OK << 16; /* Set default reply as OK */
639 pScsiReq = (SCSIIORequest_t *) mf;
640 pScsiReply = (SCSIIOReply_t *) mr;
641
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200642 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
643 dmfprintk((MYIOC_s_INFO_FMT
644 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
645 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
646 }else{
647 dmfprintk((MYIOC_s_INFO_FMT
648 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
649 ioc->name, mf, mr, sc, req_idx));
650 }
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (pScsiReply == NULL) {
653 /* special context reply handling */
654 ;
655 } else {
656 u32 xfer_cnt;
657 u16 status;
658 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700659 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
662 scsi_state = pScsiReply->SCSIState;
663 scsi_status = pScsiReply->SCSIStatus;
664 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
665 sc->resid = sc->request_bufflen - xfer_cnt;
Eric Moorec6c727a2007-01-29 09:44:54 -0700666 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600668 /*
669 * if we get a data underrun indication, yet no data was
670 * transferred and the SCSI status indicates that the
671 * command was never started, change the data underrun
672 * to success
673 */
674 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
675 (scsi_status == MPI_SCSI_STATUS_BUSY ||
676 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
677 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
678 status = MPI_IOCSTATUS_SUCCESS;
679 }
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400682 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 /*
685 * Look for + dump FCP ResponseInfo[]!
686 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600687 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
688 pScsiReply->ResponseInfo) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700689 printk(KERN_NOTICE "[%d:%d:%d:%d] "
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600690 "FCP_ResponseInfo=%08xh\n",
Eric Moorec6c727a2007-01-29 09:44:54 -0700691 sc->device->host->host_no, sc->device->channel,
692 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 le32_to_cpu(pScsiReply->ResponseInfo));
694 }
695
696 switch(status) {
697 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
698 /* CHECKME!
699 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
700 * But not: DID_BUS_BUSY lest one risk
701 * killing interrupt handler:-(
702 */
703 sc->result = SAM_STAT_BUSY;
704 break;
705
706 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
707 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
708 sc->result = DID_BAD_TARGET << 16;
709 break;
710
711 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
712 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600713 if (ioc->bus_type != FC)
714 sc->result = DID_NO_CONNECT << 16;
715 /* else fibre, just stall until rescan event */
716 else
717 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
720 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600721
722 vdev = sc->device->hostdata;
723 if (!vdev)
724 break;
725 vtarget = vdev->vtarget;
726 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
727 mptscsih_issue_sep_command(ioc, vtarget,
728 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
729 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 break;
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600734 if ( ioc->bus_type == SAS ) {
735 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
736 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700737 if ((log_info & SAS_LOGINFO_MASK)
738 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600739 sc->result = (DID_BUS_BUSY << 16);
740 break;
741 }
742 }
Eric Moore86dd4242007-01-04 20:44:01 -0700743 } else if (ioc->bus_type == FC) {
744 /*
745 * The FC IOC may kill a request for variety of
746 * reasons, some of which may be recovered by a
747 * retry, some which are unlikely to be
748 * recovered. Return DID_ERROR instead of
749 * DID_RESET to permit retry of the command,
750 * just not an infinite number of them
751 */
752 sc->result = DID_ERROR << 16;
753 break;
Eric Moorebf451522006-07-11 17:25:35 -0600754 }
755
756 /*
757 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
758 */
759
760 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
762 /* Linux handles an unsolicited DID_RESET better
763 * than an unsolicited DID_ABORT.
764 */
765 sc->result = DID_RESET << 16;
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 break;
768
769 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600770 sc->resid = sc->request_bufflen - xfer_cnt;
771 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
772 sc->result=DID_SOFT_ERROR << 16;
773 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600775 dreplyprintk((KERN_NOTICE
Eric Moorec6c727a2007-01-29 09:44:54 -0700776 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
777 sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
781 /*
782 * Do upfront check for valid SenseData and give it
783 * precedence!
784 */
785 sc->result = (DID_OK << 16) | scsi_status;
786 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
787 /* Have already saved the status and sense data
788 */
789 ;
790 } else {
791 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600792 if (scsi_status == SAM_STAT_BUSY)
793 sc->result = SAM_STAT_BUSY;
794 else
795 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
797 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
798 /* What to do?
799 */
800 sc->result = DID_SOFT_ERROR << 16;
801 }
802 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
803 /* Not real sure here either... */
804 sc->result = DID_RESET << 16;
805 }
806 }
807
808 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
809 sc->underflow));
810 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
811 /* Report Queue Full
812 */
813 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
814 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 break;
817
Moore, Eric7e551472006-01-16 18:53:21 -0700818 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
819 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
821 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600822 if (scsi_status == MPI_SCSI_STATUS_BUSY)
823 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
824 else
825 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (scsi_state == 0) {
827 ;
828 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
829 /*
830 * If running against circa 200003dd 909 MPT f/w,
831 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
832 * (QUEUE_FULL) returned from device! --> get 0x0000?128
833 * and with SenseBytes set to 0.
834 */
835 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
836 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
837
838 }
839 else if (scsi_state &
840 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
841 ) {
842 /*
843 * What to do?
844 */
845 sc->result = DID_SOFT_ERROR << 16;
846 }
847 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
848 /* Not real sure here either... */
849 sc->result = DID_RESET << 16;
850 }
851 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
852 /* Device Inq. data indicates that it supports
853 * QTags, but rejects QTag messages.
854 * This command completed OK.
855 *
856 * Not real sure here either so do nothing... */
857 }
858
859 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
860 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
861
862 /* Add handling of:
863 * Reservation Conflict, Busy,
864 * Command Terminated, CHECK
865 */
866 break;
867
868 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
869 sc->result = DID_SOFT_ERROR << 16;
870 break;
871
872 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
873 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
874 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
875 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
876 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
877 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
878 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
880 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
881 default:
882 /*
883 * What to do?
884 */
885 sc->result = DID_SOFT_ERROR << 16;
886 break;
887
888 } /* switch(status) */
889
Eric Moorec6c727a2007-01-29 09:44:54 -0700890#ifdef MPT_DEBUG_REPLY
891 if (sc->result) {
892
893 mptscsih_iocstatus_info_scsiio(ioc, status,
894 scsi_status, scsi_state, sc);
895
896 dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
897 "result=0x%08x\n\tiocstatus=0x%04X "
898 "scsi_state=0x%02X scsi_status=0x%02X "
899 "loginfo=0x%08X\n", __FUNCTION__,
900 sc->device->host->host_no, sc->device->channel, sc->device->id,
901 sc->device->lun, sc->cmnd[0], sc->result, status,
902 scsi_state, scsi_status, log_info));
903
904 dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
905 "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
906 sc->device->host->host_no, sc->device->channel, sc->device->id,
907 sc->device->lun, sc->resid, sc->request_bufflen,
908 xfer_cnt));
909 }
910#endif
911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 } /* end of address reply case */
913
914 /* Unmap the DMA buffers, if any. */
915 if (sc->use_sg) {
916 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
917 sc->use_sg, sc->sc_data_direction);
918 } else if (sc->request_bufflen) {
919 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
920 sc->request_bufflen, sc->sc_data_direction);
921 }
922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 sc->scsi_done(sc); /* Issue the command callback */
924
925 /* Free Chain buffers */
926 mptscsih_freeChainBuffers(ioc, req_idx);
927 return 1;
928}
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930/*
931 * mptscsih_flush_running_cmds - For each command found, search
932 * Scsi_Host instance taskQ and reply to OS.
933 * Called only if recovering from a FW reload.
934 * @hd: Pointer to a SCSI HOST structure
935 *
936 * Returns: None.
937 *
938 * Must be called while new I/Os are being queued.
939 */
940static void
941mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
942{
943 MPT_ADAPTER *ioc = hd->ioc;
944 struct scsi_cmnd *SCpnt;
945 MPT_FRAME_HDR *mf;
946 int ii;
947 int max = ioc->req_depth;
948
949 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
950 for (ii= 0; ii < max; ii++) {
951 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
952
953 /* Command found.
954 */
955
956 /* Null ScsiLookup index
957 */
958 hd->ScsiLookup[ii] = NULL;
959
960 mf = MPT_INDEX_2_MFPTR(ioc, ii);
961 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
962 mf, SCpnt));
963
Eric Moore3dc0b032006-07-11 17:32:33 -0600964 /* Free Chain buffers */
965 mptscsih_freeChainBuffers(ioc, ii);
966
967 /* Free Message frames */
968 mpt_free_msg_frame(ioc, mf);
969
970 if ((unsigned char *)mf != SCpnt->host_scribble)
971 continue;
972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /* Set status, free OS resources (SG DMA buffers)
974 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400976 if (SCpnt->use_sg) {
977 pci_unmap_sg(ioc->pcidev,
978 (struct scatterlist *) SCpnt->request_buffer,
979 SCpnt->use_sg,
980 SCpnt->sc_data_direction);
981 } else if (SCpnt->request_bufflen) {
982 pci_unmap_single(ioc->pcidev,
983 SCpnt->SCp.dma_handle,
984 SCpnt->request_bufflen,
985 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 }
987 SCpnt->result = DID_RESET << 16;
988 SCpnt->host_scribble = NULL;
989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
991 }
992 }
993
994 return;
995}
996
997/*
998 * mptscsih_search_running_cmds - Delete any commands associated
999 * with the specified target and lun. Function called only
1000 * when a lun is disable by mid-layer.
1001 * Do NOT access the referenced scsi_cmnd structure or
1002 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001003 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001004 * @hd: Pointer to a SCSI HOST structure
1005 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 *
1007 * Returns: None.
1008 *
1009 * Called from slave_destroy.
1010 */
1011static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001012mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013{
1014 SCSIIORequest_t *mf = NULL;
1015 int ii;
1016 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001017 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001018 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Eric Moore793955f2007-01-29 09:42:20 -07001020 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
1021 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001024 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001027 if (mf == NULL)
1028 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001029 int_to_scsilun(vdevice->lun, &lun);
1030 if ((mf->Bus != vdevice->vtarget->channel) ||
1031 (mf->TargetID != vdevice->vtarget->id) ||
1032 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001034 dsprintk(( "search_running: found (sc=%p, mf = %p) "
1035 "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
1036 mf, mf->Bus, mf->TargetID, vdevice->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 /* Cleanup
1039 */
1040 hd->ScsiLookup[ii] = NULL;
1041 mptscsih_freeChainBuffers(hd->ioc, ii);
1042 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001043 if ((unsigned char *)mf != sc->host_scribble)
1044 continue;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001045 if (sc->use_sg) {
1046 pci_unmap_sg(hd->ioc->pcidev,
1047 (struct scatterlist *) sc->request_buffer,
1048 sc->use_sg,
1049 sc->sc_data_direction);
1050 } else if (sc->request_bufflen) {
1051 pci_unmap_single(hd->ioc->pcidev,
1052 sc->SCp.dma_handle,
1053 sc->request_bufflen,
1054 sc->sc_data_direction);
1055 }
1056 sc->host_scribble = NULL;
1057 sc->result = DID_NO_CONNECT << 16;
1058 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return;
1062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1067/*
1068 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1069 * from a SCSI target device.
1070 * @sc: Pointer to scsi_cmnd structure
1071 * @pScsiReply: Pointer to SCSIIOReply_t
1072 * @pScsiReq: Pointer to original SCSI request
1073 *
1074 * This routine periodically reports QUEUE_FULL status returned from a
1075 * SCSI target device. It reports this to the console via kernel
1076 * printk() API call, not more than once every 10 seconds.
1077 */
1078static void
1079mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1080{
1081 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001084 if (sc->device == NULL)
1085 return;
1086 if (sc->device->host == NULL)
1087 return;
1088 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1089 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001091 if (time - hd->last_queue_full > 10 * HZ) {
1092 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1093 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1094 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
1098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1099/*
1100 * mptscsih_remove - Removed scsi devices
1101 * @pdev: Pointer to pci_dev structure
1102 *
1103 *
1104 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001105void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106mptscsih_remove(struct pci_dev *pdev)
1107{
1108 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1109 struct Scsi_Host *host = ioc->sh;
1110 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001111 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001113 if(!host) {
1114 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118 scsi_remove_host(host);
1119
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001120 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1121 return;
1122
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001123 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001125 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001127 if (hd->ScsiLookup != NULL) {
1128 sz1 = hd->ioc->req_depth * sizeof(void *);
1129 kfree(hd->ScsiLookup);
1130 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
1132
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001133 dprintk((MYIOC_s_INFO_FMT
1134 "Free'd ScsiLookup (%d) memory\n",
1135 hd->ioc->name, sz1));
1136
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001137 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001138
1139 /* NULL the Scsi_Host pointer
1140 */
1141 hd->ioc->sh = NULL;
1142
1143 scsi_host_put(host);
1144
1145 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147}
1148
1149/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1150/*
1151 * mptscsih_shutdown - reboot notifier
1152 *
1153 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001154void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001155mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001157 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 struct Scsi_Host *host = ioc->sh;
1159 MPT_SCSI_HOST *hd;
1160
1161 if(!host)
1162 return;
1163
1164 hd = (MPT_SCSI_HOST *)host->hostdata;
1165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
1168#ifdef CONFIG_PM
1169/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1170/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001171 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 *
1173 *
1174 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001175int
Pavel Machek8d189f72005-04-16 15:25:28 -07001176mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001178 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001179 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180}
1181
1182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1183/*
1184 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1185 *
1186 *
1187 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001188int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189mptscsih_resume(struct pci_dev *pdev)
1190{
1191 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1192 struct Scsi_Host *host = ioc->sh;
1193 MPT_SCSI_HOST *hd;
1194
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001195 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if(!host)
1198 return 0;
1199
1200 hd = (MPT_SCSI_HOST *)host->hostdata;
1201 if(!hd)
1202 return 0;
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return 0;
1205}
1206
1207#endif
1208
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1210/**
1211 * mptscsih_info - Return information about MPT adapter
1212 * @SChost: Pointer to Scsi_Host structure
1213 *
1214 * (linux scsi_host_template.info routine)
1215 *
1216 * Returns pointer to buffer where information was written.
1217 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001218const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219mptscsih_info(struct Scsi_Host *SChost)
1220{
1221 MPT_SCSI_HOST *h;
1222 int size = 0;
1223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001227 if (h->info_kbuf == NULL)
1228 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1229 return h->info_kbuf;
1230 h->info_kbuf[0] = '\0';
1231
1232 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1233 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001236 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237}
1238
1239struct info_str {
1240 char *buffer;
1241 int length;
1242 int offset;
1243 int pos;
1244};
1245
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001246static void
1247mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248{
1249 if (info->pos + len > info->length)
1250 len = info->length - info->pos;
1251
1252 if (info->pos + len < info->offset) {
1253 info->pos += len;
1254 return;
1255 }
1256
1257 if (info->pos < info->offset) {
1258 data += (info->offset - info->pos);
1259 len -= (info->offset - info->pos);
1260 }
1261
1262 if (len > 0) {
1263 memcpy(info->buffer + info->pos, data, len);
1264 info->pos += len;
1265 }
1266}
1267
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001268static int
1269mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270{
1271 va_list args;
1272 char buf[81];
1273 int len;
1274
1275 va_start(args, fmt);
1276 len = vsprintf(buf, fmt, args);
1277 va_end(args);
1278
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001279 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 return len;
1281}
1282
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283static int
1284mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
1286 struct info_str info;
1287
1288 info.buffer = pbuf;
1289 info.length = len;
1290 info.offset = offset;
1291 info.pos = 0;
1292
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001293 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1294 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1295 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1296 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
1298 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1299}
1300
1301/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1302/**
1303 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001304 * @host: scsi host struct
1305 * @buffer: if write, user data; if read, buffer for user
1306 * @start: returns the buffer address
1307 * @offset: if write, 0; if read, the current offset into the buffer from
1308 * the previous read.
1309 * @length: if write, return length;
1310 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 *
1312 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001314int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1316 int length, int func)
1317{
1318 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1319 MPT_ADAPTER *ioc = hd->ioc;
1320 int size = 0;
1321
1322 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001323 /*
1324 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 */
1326 } else {
1327 if (start)
1328 *start = buffer;
1329
1330 size = mptscsih_host_info(ioc, buffer, offset, length);
1331 }
1332
1333 return size;
1334}
1335
1336/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1337#define ADD_INDEX_LOG(req_ent) do { } while(0)
1338
1339/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1340/**
1341 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1342 * @SCpnt: Pointer to scsi_cmnd structure
1343 * @done: Pointer SCSI mid-layer IO completion function
1344 *
1345 * (linux scsi_host_template.queuecommand routine)
1346 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1347 * from a linux scsi_cmnd request and send it to the IOC.
1348 *
1349 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1350 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001351int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1353{
1354 MPT_SCSI_HOST *hd;
1355 MPT_FRAME_HDR *mf;
1356 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001357 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 int lun;
1359 u32 datalen;
1360 u32 scsictl;
1361 u32 scsidir;
1362 u32 cmd_len;
1363 int my_idx;
1364 int ii;
1365
1366 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 lun = SCpnt->device->lun;
1368 SCpnt->scsi_done = done;
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1371 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1372
1373 if (hd->resetPending) {
1374 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1375 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1376 return SCSI_MLQUEUE_HOST_BUSY;
1377 }
1378
1379 /*
1380 * Put together a MPT SCSI request...
1381 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001382 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1384 hd->ioc->name));
1385 return SCSI_MLQUEUE_HOST_BUSY;
1386 }
1387
1388 pScsiReq = (SCSIIORequest_t *) mf;
1389
1390 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1391
1392 ADD_INDEX_LOG(my_idx);
1393
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001394 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 * Seems we may receive a buffer (datalen>0) even when there
1396 * will be no data transfer! GRRRRR...
1397 */
1398 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1399 datalen = SCpnt->request_bufflen;
1400 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1401 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1402 datalen = SCpnt->request_bufflen;
1403 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1404 } else {
1405 datalen = 0;
1406 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1407 }
1408
1409 /* Default to untagged. Once a target structure has been allocated,
1410 * use the Inquiry data to determine if device supports tagged.
1411 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001412 if (vdev
1413 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 && (SCpnt->device->tagged_supported)) {
1415 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1416 } else {
1417 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1418 }
1419
1420 /* Use the above information to set up the message frame
1421 */
Eric Moore793955f2007-01-29 09:42:20 -07001422 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1423 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001425 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1426 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1427 else
1428 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 pScsiReq->CDBLength = SCpnt->cmd_len;
1430 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1431 pScsiReq->Reserved = 0;
1432 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001433 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 pScsiReq->Control = cpu_to_le32(scsictl);
1435
1436 /*
1437 * Write SCSI CDB into the message
1438 */
1439 cmd_len = SCpnt->cmd_len;
1440 for (ii=0; ii < cmd_len; ii++)
1441 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1442
1443 for (ii=cmd_len; ii < 16; ii++)
1444 pScsiReq->CDB[ii] = 0;
1445
1446 /* DataLength */
1447 pScsiReq->DataLength = cpu_to_le32(datalen);
1448
1449 /* SenseBuffer low address */
1450 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1451 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1452
1453 /* Now add the SG list
1454 * Always have a SGE even if null length.
1455 */
1456 if (datalen == 0) {
1457 /* Add a NULL SGE */
1458 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1459 (dma_addr_t) -1);
1460 } else {
1461 /* Add a 32 or 64 bit SGE */
1462 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1463 goto fail;
1464 }
1465
Eric Moore3dc0b032006-07-11 17:32:33 -06001466 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001469 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1471 hd->ioc->name, SCpnt, mf, my_idx));
1472 DBG_DUMP_REQUEST_FRAME(mf)
1473 return 0;
1474
1475 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001476 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1478 mpt_free_msg_frame(hd->ioc, mf);
1479 return SCSI_MLQUEUE_HOST_BUSY;
1480}
1481
1482/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1483/*
1484 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1485 * with a SCSI IO request
1486 * @hd: Pointer to the MPT_SCSI_HOST instance
1487 * @req_idx: Index of the SCSI IO request frame.
1488 *
1489 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1490 * No return.
1491 */
1492static void
1493mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1494{
1495 MPT_FRAME_HDR *chain;
1496 unsigned long flags;
1497 int chain_idx;
1498 int next;
1499
1500 /* Get the first chain index and reset
1501 * tracker state.
1502 */
1503 chain_idx = ioc->ReqToChain[req_idx];
1504 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1505
1506 while (chain_idx != MPT_HOST_NO_CHAIN) {
1507
1508 /* Save the next chain buffer index */
1509 next = ioc->ChainToChain[chain_idx];
1510
1511 /* Free this chain buffer and reset
1512 * tracker
1513 */
1514 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1515
1516 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1517 + (chain_idx * ioc->req_sz));
1518
1519 spin_lock_irqsave(&ioc->FreeQlock, flags);
1520 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1521 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1522
1523 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1524 ioc->name, chain_idx));
1525
1526 /* handle next */
1527 chain_idx = next;
1528 }
1529 return;
1530}
1531
1532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1533/*
1534 * Reset Handling
1535 */
1536
1537/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001538/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001540 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001542 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001543 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 * @lun: Logical Unit for reset (if appropriate)
1545 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001546 * @timeout: timeout for task management control
1547 *
1548 * Fall through to mpt_HardResetHandler if: not operational, too many
1549 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 *
1551 * Remark: Currently invoked from a non-interrupt thread (_bh).
1552 *
1553 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1554 * will be active.
1555 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001556 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001557 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001558int
Eric Moore793955f2007-01-29 09:42:20 -07001559mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
1561 MPT_ADAPTER *ioc;
1562 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 u32 ioc_raw_state;
1564 unsigned long flags;
1565
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1568
1569 // SJR - CHECKME - Can we avoid this here?
1570 // (mpt_HardResetHandler has this check...)
1571 spin_lock_irqsave(&ioc->diagLock, flags);
1572 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1573 spin_unlock_irqrestore(&ioc->diagLock, flags);
1574 return FAILED;
1575 }
1576 spin_unlock_irqrestore(&ioc->diagLock, flags);
1577
1578 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001579 * If we time out and not bus reset, then we return a FAILED status
1580 * to the caller.
1581 * The call to mptscsih_tm_pending_wait() will set the pending flag
1582 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 * successful. Otherwise, reload the FW.
1584 */
1585 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1586 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001587 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 "Timed out waiting for last TM (%d) to complete! \n",
1589 hd->ioc->name, hd->tmPending));
1590 return FAILED;
1591 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001592 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1593 "reset: Timed out waiting for last TM (%d) "
1594 "to complete! \n", hd->ioc->name,
1595 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 return FAILED;
1597 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001598 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 "Timed out waiting for last TM (%d) to complete! \n",
1600 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001601 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 }
1603 } else {
1604 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1605 hd->tmPending |= (1 << type);
1606 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1607 }
1608
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1612 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001613 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1614 ioc->name, type, ioc_raw_state);
1615 printk(KERN_WARNING " Issuing HardReset!!\n");
1616 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1617 printk((KERN_WARNING "TMHandler: HardReset "
1618 "FAILED!!\n"));
1619 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 }
1621
Eric Moorecd2c6192007-01-29 09:47:47 -07001622 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1623 printk(MYIOC_s_WARN_FMT
1624 "TM Handler for type=%x: ioc_state: "
1625 "DOORBELL_ACTIVE (0x%x)!\n",
1626 ioc->name, type, ioc_raw_state);
1627 return FAILED;
1628 }
1629
1630 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001632 if (hd->hard_resets < -1)
1633 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
Eric Moorecd2c6192007-01-29 09:47:47 -07001635 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1636 ctx2abort, timeout);
1637 if (rc)
1638 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1639 hd->ioc->name);
1640 else
1641 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1642 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1645
1646 return rc;
1647}
1648
1649
1650/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001651/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1653 * @hd: Pointer to MPT_SCSI_HOST structure
1654 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001655 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001656 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 * @lun: Logical Unit for reset (if appropriate)
1658 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001659 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 *
1661 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1662 * or a non-interrupt thread. In the former, must not call schedule().
1663 *
1664 * Not all fields are meaningfull for all task types.
1665 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001666 * Returns 0 for SUCCESS, or FAILED.
1667 *
1668 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669static int
Eric Moore793955f2007-01-29 09:42:20 -07001670mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671{
1672 MPT_FRAME_HDR *mf;
1673 SCSITaskMgmt_t *pScsiTm;
1674 int ii;
1675 int retval;
1676
1677 /* Return Fail to calling function if no message frames available.
1678 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001679 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1681 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001682 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 }
1684 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1685 hd->ioc->name, mf));
1686
1687 /* Format the Request
1688 */
1689 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001690 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 pScsiTm->Bus = channel;
1692 pScsiTm->ChainOffset = 0;
1693 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1694
1695 pScsiTm->Reserved = 0;
1696 pScsiTm->TaskType = type;
1697 pScsiTm->Reserved1 = 0;
1698 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1699 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1700
Eric Moore793955f2007-01-29 09:42:20 -07001701 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 for (ii=0; ii < 7; ii++)
1704 pScsiTm->Reserved2[ii] = 0;
1705
1706 pScsiTm->TaskMsgContext = ctx2abort;
1707
Eric Moorecd2c6192007-01-29 09:47:47 -07001708 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1709 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1712
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001713 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001714 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1715 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1716 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1717 hd->ioc, mf, retval));
1718 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 }
1720
1721 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001722 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1724 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1726 hd->ioc->name));
1727 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001728 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1729 hd->ioc->name, retval));
1730 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 }
1732
Eric Moorecd2c6192007-01-29 09:47:47 -07001733 /*
1734 * Handle success case, see if theres a non-zero ioc_status.
1735 */
1736 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1737 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1738 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1739 retval = 0;
1740 else
1741 retval = FAILED;
1742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001744
1745 fail_out:
1746
1747 /*
1748 * Free task managment mf, and corresponding tm flags
1749 */
1750 mpt_free_msg_frame(hd->ioc, mf);
1751 hd->tmPending = 0;
1752 hd->tmState = TM_STATE_NONE;
1753 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754}
1755
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001756static int
1757mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1758{
1759 switch (ioc->bus_type) {
1760 case FC:
1761 return 40;
1762 case SAS:
1763 return 10;
1764 case SPI:
1765 default:
1766 return 2;
1767 }
1768}
1769
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1771/**
1772 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1773 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1774 *
1775 * (linux scsi_host_template.eh_abort_handler routine)
1776 *
1777 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001778 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001779int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780mptscsih_abort(struct scsi_cmnd * SCpnt)
1781{
1782 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 MPT_FRAME_HDR *mf;
1784 u32 ctx2abort;
1785 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001786 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001787 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001788 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
1790 /* If we can't locate our host adapter structure, return FAILED status.
1791 */
1792 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1793 SCpnt->result = DID_RESET << 16;
1794 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001795 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 "Can't locate host! (sc=%p)\n",
1797 SCpnt));
1798 return FAILED;
1799 }
1800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 /* Find this command
1802 */
1803 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001804 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 * Do OS callback.
1806 */
1807 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001808 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 "Command not in the active list! (sc=%p)\n",
1810 hd->ioc->name, SCpnt));
1811 return SUCCESS;
1812 }
1813
Eric Moorecd2c6192007-01-29 09:47:47 -07001814 if (hd->resetPending)
Moore, Eric65207fe2006-04-21 16:14:35 -06001815 return FAILED;
Moore, Eric65207fe2006-04-21 16:14:35 -06001816
1817 if (hd->timeouts < -1)
1818 hd->timeouts++;
1819
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001820 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1821 hd->ioc->name, SCpnt);
1822 scsi_print_command(SCpnt);
1823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1825 * (the IO to be ABORT'd)
1826 *
1827 * NOTE: Since we do not byteswap MsgContext, we do not
1828 * swap it here either. It is an opaque cookie to
1829 * the controller, so it does not matter. -DaveM
1830 */
1831 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1832 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1833
1834 hd->abortSCpnt = SCpnt;
1835
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001836 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001837 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore793955f2007-01-29 09:42:20 -07001838 vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001839 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
Eric Moore3dc0b032006-07-11 17:32:33 -06001841 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001842 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001843 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001844
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001845 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1846 hd->ioc->name,
1847 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001849 if (retval == 0)
1850 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001851 else
1852 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
1855/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1856/**
1857 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1858 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1859 *
1860 * (linux scsi_host_template.eh_dev_reset_handler routine)
1861 *
1862 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001863 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001864int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1866{
1867 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001868 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001869 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 /* If we can't locate our host adapter structure, return FAILED status.
1872 */
1873 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001874 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 "Can't locate host! (sc=%p)\n",
1876 SCpnt));
1877 return FAILED;
1878 }
1879
1880 if (hd->resetPending)
1881 return FAILED;
1882
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001883 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001885 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001887 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001888 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -07001889 vdev->vtarget->channel, vdev->vtarget->id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001890 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001891
1892 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1893 hd->ioc->name,
1894 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1895
1896 if (retval == 0)
1897 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001898 else
1899 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900}
1901
Eric Moorecd2c6192007-01-29 09:47:47 -07001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1904/**
1905 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1906 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1907 *
1908 * (linux scsi_host_template.eh_bus_reset_handler routine)
1909 *
1910 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001911 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001912int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1914{
1915 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001916 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001917 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919 /* If we can't locate our host adapter structure, return FAILED status.
1920 */
1921 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001922 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 "Can't locate host! (sc=%p)\n",
1924 SCpnt ) );
1925 return FAILED;
1926 }
1927
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001928 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001930 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
1932 if (hd->timeouts < -1)
1933 hd->timeouts++;
1934
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001935 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001936 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore793955f2007-01-29 09:42:20 -07001937 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001939 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1940 hd->ioc->name,
1941 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1942
1943 if (retval == 0)
1944 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001945 else
1946 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947}
1948
1949/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1950/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001951 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1953 *
1954 * (linux scsi_host_template.eh_host_reset_handler routine)
1955 *
1956 * Returns SUCCESS or FAILED.
1957 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001958int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1960{
1961 MPT_SCSI_HOST * hd;
1962 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
1964 /* If we can't locate the host to reset, then we failed. */
1965 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001966 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 "Can't locate host! (sc=%p)\n",
1968 SCpnt ) );
1969 return FAILED;
1970 }
1971
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001972 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 hd->ioc->name, SCpnt);
1974
1975 /* If our attempts to reset the host failed, then return a failed
1976 * status. The host will be taken off line by the SCSI mid-layer.
1977 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1979 status = FAILED;
1980 } else {
1981 /* Make sure TM pending is cleared and TM state is set to
1982 * NONE.
1983 */
1984 hd->tmPending = 0;
1985 hd->tmState = TM_STATE_NONE;
1986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001988 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 "Status = %s\n",
1990 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1991
1992 return status;
1993}
1994
1995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1996/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001997 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 * @hd: Pointer to MPT host structure.
1999 *
2000 * Returns {SUCCESS,FAILED}.
2001 */
2002static int
2003mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2004{
2005 unsigned long flags;
2006 int loop_count = 4 * 10; /* Wait 10 seconds */
2007 int status = FAILED;
2008
2009 do {
2010 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2011 if (hd->tmState == TM_STATE_NONE) {
2012 hd->tmState = TM_STATE_IN_PROGRESS;
2013 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002015 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 break;
2017 }
2018 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2019 msleep(250);
2020 } while (--loop_count);
2021
2022 return status;
2023}
2024
2025/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2026/**
2027 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2028 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002029 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 *
2031 * Returns {SUCCESS,FAILED}.
2032 */
2033static int
2034mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2035{
2036 unsigned long flags;
2037 int loop_count = 4 * timeout;
2038 int status = FAILED;
2039
2040 do {
2041 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2042 if(hd->tmPending == 0) {
2043 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002044 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 break;
2046 }
2047 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002048 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 } while (--loop_count);
2050
2051 return status;
2052}
2053
2054/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002055static void
2056mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2057{
2058 char *desc;
2059
2060 switch (response_code) {
2061 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2062 desc = "The task completed.";
2063 break;
2064 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2065 desc = "The IOC received an invalid frame status.";
2066 break;
2067 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2068 desc = "The task type is not supported.";
2069 break;
2070 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2071 desc = "The requested task failed.";
2072 break;
2073 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2074 desc = "The task completed successfully.";
2075 break;
2076 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2077 desc = "The LUN request is invalid.";
2078 break;
2079 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2080 desc = "The task is in the IOC queue and has not been sent to target.";
2081 break;
2082 default:
2083 desc = "unknown";
2084 break;
2085 }
2086 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2087 ioc->name, response_code, desc);
2088}
2089
2090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091/**
2092 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2093 * @ioc: Pointer to MPT_ADAPTER structure
2094 * @mf: Pointer to SCSI task mgmt request frame
2095 * @mr: Pointer to SCSI task mgmt reply frame
2096 *
2097 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2098 * of any SCSI task management request.
2099 * This routine is registered with the MPT (base) driver at driver
2100 * load/init time via the mpt_register() API call.
2101 *
2102 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002103 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002104int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2106{
2107 SCSITaskMgmtReply_t *pScsiTmReply;
2108 SCSITaskMgmt_t *pScsiTmReq;
2109 MPT_SCSI_HOST *hd;
2110 unsigned long flags;
2111 u16 iocstatus;
2112 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002113 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002116 ioc->name, mf, mr));
2117 if (!ioc->sh) {
2118 dtmprintk((MYIOC_s_WARN_FMT
2119 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 return 1;
2121 }
2122
2123 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002124 dtmprintk((MYIOC_s_WARN_FMT
2125 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 }
2128
Eric Moorecd2c6192007-01-29 09:47:47 -07002129 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2130 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2131 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2132 tmType = pScsiTmReq->TaskType;
2133 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2134 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2135
2136 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2137 pScsiTmReply->ResponseCode)
2138 mptscsih_taskmgmt_response_code(ioc,
2139 pScsiTmReply->ResponseCode);
2140 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2141
2142#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2143 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2144 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2145 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2146 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2147 le16_to_cpu(pScsiTmReply->IOCStatus),
2148 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2149 le32_to_cpu(pScsiTmReply->TerminationCount));
2150#endif
2151 if (!iocstatus) {
2152 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2153 hd->abortSCpnt = NULL;
2154 goto out;
2155 }
2156
2157 /* Error? (anything non-zero?) */
2158
2159 /* clear flags and continue.
2160 */
2161 switch (tmType) {
2162
2163 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2164 if (termination_count == 1)
2165 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2166 hd->abortSCpnt = NULL;
2167 break;
2168
2169 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2170
2171 /* If an internal command is present
2172 * or the TM failed - reload the FW.
2173 * FC FW may respond FAILED to an ABORT
2174 */
2175 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2176 hd->cmdPtr)
2177 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2178 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2179 break;
2180
2181 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2182 default:
2183 break;
2184 }
2185
2186 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 spin_lock_irqsave(&ioc->FreeQlock, flags);
2188 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002190 hd->tm_iocstatus = iocstatus;
2191 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192
2193 return 1;
2194}
2195
2196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2197/*
2198 * This is anyones guess quite frankly.
2199 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002200int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2202 sector_t capacity, int geom[])
2203{
2204 int heads;
2205 int sectors;
2206 sector_t cylinders;
2207 ulong dummy;
2208
2209 heads = 64;
2210 sectors = 32;
2211
2212 dummy = heads * sectors;
2213 cylinders = capacity;
2214 sector_div(cylinders,dummy);
2215
2216 /*
2217 * Handle extended translation size for logical drives
2218 * > 1Gb
2219 */
2220 if ((ulong)capacity >= 0x200000) {
2221 heads = 255;
2222 sectors = 63;
2223 dummy = heads * sectors;
2224 cylinders = capacity;
2225 sector_div(cylinders,dummy);
2226 }
2227
2228 /* return result */
2229 geom[0] = heads;
2230 geom[1] = sectors;
2231 geom[2] = cylinders;
2232
2233 dprintk((KERN_NOTICE
2234 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002235 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 return 0;
2238}
2239
Moore, Ericf44e5462006-03-14 09:14:21 -07002240/* Search IOC page 3 to determine if this is hidden physical disk
2241 *
2242 */
2243int
Eric Moore793955f2007-01-29 09:42:20 -07002244mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002245{
Eric Mooreb506ade2007-01-29 09:45:37 -07002246 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002247 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002248 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002249
Eric Moore793955f2007-01-29 09:42:20 -07002250 if (!ioc->raid_data.pIocPg3)
2251 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002252 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002253 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2254 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2255 rc = 1;
2256 goto out;
2257 }
2258 }
2259
Eric Mooreb506ade2007-01-29 09:45:37 -07002260 /*
2261 * Check inactive list for matching phys disks
2262 */
2263 if (list_empty(&ioc->raid_data.inactive_list))
2264 goto out;
2265
2266 down(&ioc->raid_data.inactive_list_mutex);
2267 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2268 list) {
2269 if ((component_info->d.PhysDiskID == id) &&
2270 (component_info->d.PhysDiskBus == channel))
2271 rc = 1;
2272 }
2273 up(&ioc->raid_data.inactive_list_mutex);
2274
Eric Moore793955f2007-01-29 09:42:20 -07002275 out:
2276 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002277}
2278EXPORT_SYMBOL(mptscsih_is_phys_disk);
2279
Eric Moore793955f2007-01-29 09:42:20 -07002280u8
2281mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002282{
Eric Mooreb506ade2007-01-29 09:45:37 -07002283 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002284 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002285 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002286
Eric Moore793955f2007-01-29 09:42:20 -07002287 if (!ioc->raid_data.pIocPg3)
2288 goto out;
2289 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2290 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2291 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2292 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2293 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002294 }
2295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
Eric Mooreb506ade2007-01-29 09:45:37 -07002297 /*
2298 * Check inactive list for matching phys disks
2299 */
2300 if (list_empty(&ioc->raid_data.inactive_list))
2301 goto out;
2302
2303 down(&ioc->raid_data.inactive_list_mutex);
2304 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2305 list) {
2306 if ((component_info->d.PhysDiskID == id) &&
2307 (component_info->d.PhysDiskBus == channel))
2308 rc = component_info->d.PhysDiskNum;
2309 }
2310 up(&ioc->raid_data.inactive_list_mutex);
2311
Eric Moore793955f2007-01-29 09:42:20 -07002312 out:
2313 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002314}
Eric Moore793955f2007-01-29 09:42:20 -07002315EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002316
2317/*
2318 * OS entry point to allow for host driver to free allocated memory
2319 * Called if no device present or device being unloaded
2320 */
2321void
2322mptscsih_slave_destroy(struct scsi_device *sdev)
2323{
2324 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002326 VirtTarget *vtarget;
2327 VirtDevice *vdevice;
2328 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002330 starget = scsi_target(sdev);
2331 vtarget = starget->hostdata;
2332 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002334 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002335 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002336 mptscsih_synchronize_cache(hd, vdevice);
2337 kfree(vdevice);
2338 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339}
2340
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002341/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2342/*
2343 * mptscsih_change_queue_depth - This function will set a devices queue depth
2344 * @sdev: per scsi_device pointer
2345 * @qdepth: requested queue depth
2346 *
2347 * Adding support for new 'change_queue_depth' api.
2348*/
2349int
2350mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002352 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2353 VirtTarget *vtarget;
2354 struct scsi_target *starget;
2355 int max_depth;
2356 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002358 starget = scsi_target(sdev);
2359 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002360
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002361 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002362 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002364 else if (sdev->type == TYPE_DISK &&
2365 vtarget->minSyncFactor <= MPT_ULTRA160)
2366 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2367 else
2368 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 } else
2370 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2371
2372 if (qdepth > max_depth)
2373 qdepth = max_depth;
2374 if (qdepth == 1)
2375 tagged = 0;
2376 else
2377 tagged = MSG_SIMPLE_TAG;
2378
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002379 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2380 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381}
2382
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383/*
2384 * OS entry point to adjust the queue_depths on a per-device basis.
2385 * Called once per device the bus scan. Use it to force the queue_depth
2386 * member to 1 if a device does not support Q tags.
2387 * Return non-zero if fails.
2388 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002389int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002390mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 struct Scsi_Host *sh = sdev->host;
2393 VirtTarget *vtarget;
2394 VirtDevice *vdevice;
2395 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2397
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002398 starget = scsi_target(sdev);
2399 vtarget = starget->hostdata;
2400 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002403 "device @ %p, channel=%d, id=%d, lun=%d\n",
2404 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 if (hd->ioc->bus_type == SPI)
2406 dsprintk((MYIOC_s_INFO_FMT
2407 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2408 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2409 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002413 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 goto slave_configure_exit;
2415 }
2416
Eric Moore793955f2007-01-29 09:42:20 -07002417 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 dsprintk((MYIOC_s_INFO_FMT
2421 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002422 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002424 if (hd->ioc->bus_type == SPI)
2425 dsprintk((MYIOC_s_INFO_FMT
2426 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2427 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2428 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
2430slave_configure_exit:
2431
2432 dsprintk((MYIOC_s_INFO_FMT
2433 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002434 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2435 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
2437 return 0;
2438}
2439
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2441/*
2442 * Private routines...
2443 */
2444
2445/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2446/* Utility function to copy sense data from the scsi_cmnd buffer
2447 * to the FC and SCSI target structures.
2448 *
2449 */
2450static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002451mptscsih_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 -07002452{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002453 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 SCSIIORequest_t *pReq;
2455 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
2457 /* Get target structure
2458 */
2459 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002460 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462 if (sense_count) {
2463 u8 *sense_data;
2464 int req_index;
2465
2466 /* Copy the sense received into the scsi command block. */
2467 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2468 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2469 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2470
2471 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2472 */
2473 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002474 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 int idx;
2476 MPT_ADAPTER *ioc = hd->ioc;
2477
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002478 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2480 ioc->events[idx].eventContext = ioc->eventContext;
2481
2482 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2483 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002484 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
2486 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2487
2488 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002489 if (hd->ioc->pcidev->vendor ==
2490 PCI_VENDOR_ID_IBM) {
2491 mptscsih_issue_sep_command(hd->ioc,
2492 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2493 vdev->vtarget->tflags |=
2494 MPT_TARGET_FLAGS_LED_ON;
2495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 }
2497 }
2498 } else {
2499 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2500 hd->ioc->name));
2501 }
2502}
2503
Eric Moore3dc0b032006-07-11 17:32:33 -06002504static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2506{
2507 MPT_SCSI_HOST *hd;
2508 int i;
2509
2510 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2511
2512 for (i = 0; i < hd->ioc->req_depth; i++) {
2513 if (hd->ScsiLookup[i] == sc) {
2514 return i;
2515 }
2516 }
2517
2518 return -1;
2519}
2520
2521/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002522int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2524{
2525 MPT_SCSI_HOST *hd;
2526 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002527 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
2529 dtmprintk((KERN_WARNING MYNAM
2530 ": IOC %s_reset routed to SCSI host driver!\n",
2531 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2532 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2533
2534 /* If a FW reload request arrives after base installed but
2535 * before all scsi hosts have been attached, then an alt_ioc
2536 * may have a NULL sh pointer.
2537 */
2538 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2539 return 0;
2540 else
2541 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2542
2543 if (reset_phase == MPT_IOC_SETUP_RESET) {
2544 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2545
2546 /* Clean Up:
2547 * 1. Set Hard Reset Pending Flag
2548 * All new commands go to doneQ
2549 */
2550 hd->resetPending = 1;
2551
2552 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2553 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2554
2555 /* 2. Flush running commands
2556 * Clean ScsiLookup (and associated memory)
2557 * AND clean mytaskQ
2558 */
2559
2560 /* 2b. Reply to OS all known outstanding I/O commands.
2561 */
2562 mptscsih_flush_running_cmds(hd);
2563
2564 /* 2c. If there was an internal command that
2565 * has not completed, configuration or io request,
2566 * free these resources.
2567 */
2568 if (hd->cmdPtr) {
2569 del_timer(&hd->timer);
2570 mpt_free_msg_frame(ioc, hd->cmdPtr);
2571 }
2572
2573 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2574
2575 } else {
2576 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2577
2578 /* Once a FW reload begins, all new OS commands are
2579 * redirected to the doneQ w/ a reset status.
2580 * Init all control structures.
2581 */
2582
2583 /* ScsiLookup initialization
2584 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002585 for (ii=0; ii < hd->ioc->req_depth; ii++)
2586 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588 /* 2. Chain Buffer initialization
2589 */
2590
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002591 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 /* 5. Enable new commands to be posted
2595 */
2596 spin_lock_irqsave(&ioc->FreeQlock, flags);
2597 hd->tmPending = 0;
2598 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2599 hd->resetPending = 0;
2600 hd->tmState = TM_STATE_NONE;
2601
2602 /* 6. If there was an internal command,
2603 * wake this process up.
2604 */
2605 if (hd->cmdPtr) {
2606 /*
2607 * Wake up the original calling thread
2608 */
2609 hd->pLocal = &hd->localReply;
2610 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002611 hd->scandv_wait_done = 1;
2612 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 hd->cmdPtr = NULL;
2614 }
2615
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2617
2618 }
2619
2620 return 1; /* currently means nothing really */
2621}
2622
2623/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002624int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2626{
2627 MPT_SCSI_HOST *hd;
2628 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2629
Moore, Eric3a892be2006-03-14 09:14:03 -07002630 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 ioc->name, event));
2632
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002633 if (ioc->sh == NULL ||
2634 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2635 return 1;
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 switch (event) {
2638 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2639 /* FIXME! */
2640 break;
2641 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2642 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002643 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002644 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 break;
2646 case MPI_EVENT_LOGOUT: /* 09 */
2647 /* FIXME! */
2648 break;
2649
Michael Reed05e8ec12006-01-13 14:31:54 -06002650 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002651 break;
2652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /*
2654 * CHECKME! Don't think we need to do
2655 * anything for these, but...
2656 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2658 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2659 /*
2660 * CHECKME! Falling thru...
2661 */
2662 break;
2663
2664 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002665 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 case MPI_EVENT_NONE: /* 00 */
2668 case MPI_EVENT_LOG_DATA: /* 01 */
2669 case MPI_EVENT_STATE_CHANGE: /* 02 */
2670 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2671 default:
2672 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2673 break;
2674 }
2675
2676 return 1; /* currently means nothing really */
2677}
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2680/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 * Bus Scan and Domain Validation functionality ...
2682 */
2683
2684/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2685/*
2686 * mptscsih_scandv_complete - Scan and DV callback routine registered
2687 * to Fustion MPT (base) driver.
2688 *
2689 * @ioc: Pointer to MPT_ADAPTER structure
2690 * @mf: Pointer to original MPT request frame
2691 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2692 *
2693 * This routine is called from mpt.c::mpt_interrupt() at the completion
2694 * of any SCSI IO request.
2695 * This routine is registered with the Fusion MPT (base) driver at driver
2696 * load/init time via the mpt_register() API call.
2697 *
2698 * Returns 1 indicating alloc'd request frame ptr should be freed.
2699 *
2700 * Remark: Sets a completion code and (possibly) saves sense data
2701 * in the IOC member localReply structure.
2702 * Used ONLY for DV and other internal commands.
2703 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002704int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2706{
2707 MPT_SCSI_HOST *hd;
2708 SCSIIORequest_t *pReq;
2709 int completionCode;
2710 u16 req_idx;
2711
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002712 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2713
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 if ((mf == NULL) ||
2715 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2716 printk(MYIOC_s_ERR_FMT
2717 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2718 ioc->name, mf?"BAD":"NULL", (void *) mf);
2719 goto wakeup;
2720 }
2721
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 del_timer(&hd->timer);
2723 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2724 hd->ScsiLookup[req_idx] = NULL;
2725 pReq = (SCSIIORequest_t *) mf;
2726
2727 if (mf != hd->cmdPtr) {
2728 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2729 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2730 }
2731 hd->cmdPtr = NULL;
2732
2733 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2734 hd->ioc->name, mf, mr, req_idx));
2735
2736 hd->pLocal = &hd->localReply;
2737 hd->pLocal->scsiStatus = 0;
2738
2739 /* If target struct exists, clear sense valid flag.
2740 */
2741 if (mr == NULL) {
2742 completionCode = MPT_SCANDV_GOOD;
2743 } else {
2744 SCSIIOReply_t *pReply;
2745 u16 status;
2746 u8 scsi_status;
2747
2748 pReply = (SCSIIOReply_t *) mr;
2749
2750 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2751 scsi_status = pReply->SCSIStatus;
2752
2753 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2754 status, pReply->SCSIState, scsi_status,
2755 le32_to_cpu(pReply->IOCLogInfo)));
2756
2757 switch(status) {
2758
2759 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2760 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2761 break;
2762
2763 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2764 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2765 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2766 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2767 completionCode = MPT_SCANDV_DID_RESET;
2768 break;
2769
2770 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2771 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2772 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2773 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2774 ConfigReply_t *pr = (ConfigReply_t *)mr;
2775 completionCode = MPT_SCANDV_GOOD;
2776 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2777 hd->pLocal->header.PageLength = pr->Header.PageLength;
2778 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2779 hd->pLocal->header.PageType = pr->Header.PageType;
2780
2781 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2782 /* If the RAID Volume request is successful,
2783 * return GOOD, else indicate that
2784 * some type of error occurred.
2785 */
2786 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002787 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 completionCode = MPT_SCANDV_GOOD;
2789 else
2790 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002791 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2794 u8 *sense_data;
2795 int sz;
2796
2797 /* save sense data in global structure
2798 */
2799 completionCode = MPT_SCANDV_SENSE;
2800 hd->pLocal->scsiStatus = scsi_status;
2801 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2802 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2803
2804 sz = min_t(int, pReq->SenseBufferLength,
2805 SCSI_STD_SENSE_BYTES);
2806 memcpy(hd->pLocal->sense, sense_data, sz);
2807
2808 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2809 sense_data));
2810 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2811 if (pReq->CDB[0] == INQUIRY)
2812 completionCode = MPT_SCANDV_ISSUE_SENSE;
2813 else
2814 completionCode = MPT_SCANDV_DID_RESET;
2815 }
2816 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2817 completionCode = MPT_SCANDV_DID_RESET;
2818 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2819 completionCode = MPT_SCANDV_DID_RESET;
2820 else {
2821 completionCode = MPT_SCANDV_GOOD;
2822 hd->pLocal->scsiStatus = scsi_status;
2823 }
2824 break;
2825
2826 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2827 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2828 completionCode = MPT_SCANDV_DID_RESET;
2829 else
2830 completionCode = MPT_SCANDV_SOME_ERROR;
2831 break;
2832
2833 default:
2834 completionCode = MPT_SCANDV_SOME_ERROR;
2835 break;
2836
2837 } /* switch(status) */
2838
2839 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2840 completionCode));
2841 } /* end of address reply case */
2842
2843 hd->pLocal->completion = completionCode;
2844
2845 /* MF and RF are freed in mpt_interrupt
2846 */
2847wakeup:
2848 /* Free Chain buffers (will never chain) in scan or dv */
2849 //mptscsih_freeChainBuffers(ioc, req_idx);
2850
2851 /*
2852 * Wake up the original calling thread
2853 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002854 hd->scandv_wait_done = 1;
2855 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
2857 return 1;
2858}
2859
2860/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2861/* mptscsih_timer_expired - Call back for timer process.
2862 * Used only for dv functionality.
2863 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2864 *
2865 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002866void
2867mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868{
2869 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2870
2871 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2872
2873 if (hd->cmdPtr) {
2874 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2875
2876 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2877 /* Desire to issue a task management request here.
2878 * TM requests MUST be single threaded.
2879 * If old eh code and no TM current, issue request.
2880 * If new eh code, do nothing. Wait for OS cmd timeout
2881 * for bus reset.
2882 */
2883 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2884 } else {
2885 /* Perform a FW reload */
2886 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2887 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2888 }
2889 }
2890 } else {
2891 /* This should NEVER happen */
2892 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2893 }
2894
2895 /* No more processing.
2896 * TM call will generate an interrupt for SCSI TM Management.
2897 * The FW will reply to all outstanding commands, callback will finish cleanup.
2898 * Hard reset clean-up will free all resources.
2899 */
2900 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2901
2902 return;
2903}
2904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
2906/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2907/**
2908 * mptscsih_do_cmd - Do internal command.
2909 * @hd: MPT_SCSI_HOST pointer
2910 * @io: INTERNAL_CMD pointer.
2911 *
2912 * Issue the specified internally generated command and do command
2913 * specific cleanup. For bus scan / DV only.
2914 * NOTES: If command is Inquiry and status is good,
2915 * initialize a target structure, save the data
2916 *
2917 * Remark: Single threaded access only.
2918 *
2919 * Return:
2920 * < 0 if an illegal command or no resources
2921 *
2922 * 0 if good
2923 *
2924 * > 0 if command complete but some type of completion error.
2925 */
2926static int
2927mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2928{
2929 MPT_FRAME_HDR *mf;
2930 SCSIIORequest_t *pScsiReq;
2931 SCSIIORequest_t ReqCopy;
2932 int my_idx, ii, dir;
2933 int rc, cmdTimeout;
2934 int in_isr;
2935 char cmdLen;
2936 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2937 char cmd = io->cmd;
2938
2939 in_isr = in_interrupt();
2940 if (in_isr) {
2941 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2942 hd->ioc->name));
2943 return -EPERM;
2944 }
2945
2946
2947 /* Set command specific information
2948 */
2949 switch (cmd) {
2950 case INQUIRY:
2951 cmdLen = 6;
2952 dir = MPI_SCSIIO_CONTROL_READ;
2953 CDB[0] = cmd;
2954 CDB[4] = io->size;
2955 cmdTimeout = 10;
2956 break;
2957
2958 case TEST_UNIT_READY:
2959 cmdLen = 6;
2960 dir = MPI_SCSIIO_CONTROL_READ;
2961 cmdTimeout = 10;
2962 break;
2963
2964 case START_STOP:
2965 cmdLen = 6;
2966 dir = MPI_SCSIIO_CONTROL_READ;
2967 CDB[0] = cmd;
2968 CDB[4] = 1; /*Spin up the disk */
2969 cmdTimeout = 15;
2970 break;
2971
2972 case REQUEST_SENSE:
2973 cmdLen = 6;
2974 CDB[0] = cmd;
2975 CDB[4] = io->size;
2976 dir = MPI_SCSIIO_CONTROL_READ;
2977 cmdTimeout = 10;
2978 break;
2979
2980 case READ_BUFFER:
2981 cmdLen = 10;
2982 dir = MPI_SCSIIO_CONTROL_READ;
2983 CDB[0] = cmd;
2984 if (io->flags & MPT_ICFLAG_ECHO) {
2985 CDB[1] = 0x0A;
2986 } else {
2987 CDB[1] = 0x02;
2988 }
2989
2990 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2991 CDB[1] |= 0x01;
2992 }
2993 CDB[6] = (io->size >> 16) & 0xFF;
2994 CDB[7] = (io->size >> 8) & 0xFF;
2995 CDB[8] = io->size & 0xFF;
2996 cmdTimeout = 10;
2997 break;
2998
2999 case WRITE_BUFFER:
3000 cmdLen = 10;
3001 dir = MPI_SCSIIO_CONTROL_WRITE;
3002 CDB[0] = cmd;
3003 if (io->flags & MPT_ICFLAG_ECHO) {
3004 CDB[1] = 0x0A;
3005 } else {
3006 CDB[1] = 0x02;
3007 }
3008 CDB[6] = (io->size >> 16) & 0xFF;
3009 CDB[7] = (io->size >> 8) & 0xFF;
3010 CDB[8] = io->size & 0xFF;
3011 cmdTimeout = 10;
3012 break;
3013
3014 case RESERVE:
3015 cmdLen = 6;
3016 dir = MPI_SCSIIO_CONTROL_READ;
3017 CDB[0] = cmd;
3018 cmdTimeout = 10;
3019 break;
3020
3021 case RELEASE:
3022 cmdLen = 6;
3023 dir = MPI_SCSIIO_CONTROL_READ;
3024 CDB[0] = cmd;
3025 cmdTimeout = 10;
3026 break;
3027
3028 case SYNCHRONIZE_CACHE:
3029 cmdLen = 10;
3030 dir = MPI_SCSIIO_CONTROL_READ;
3031 CDB[0] = cmd;
3032// CDB[1] = 0x02; /* set immediate bit */
3033 cmdTimeout = 10;
3034 break;
3035
3036 default:
3037 /* Error Case */
3038 return -EFAULT;
3039 }
3040
3041 /* Get and Populate a free Frame
3042 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003043 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3045 hd->ioc->name));
3046 return -EBUSY;
3047 }
3048
3049 pScsiReq = (SCSIIORequest_t *) mf;
3050
3051 /* Get the request index */
3052 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3053 ADD_INDEX_LOG(my_idx); /* for debug */
3054
3055 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3056 pScsiReq->TargetID = io->physDiskNum;
3057 pScsiReq->Bus = 0;
3058 pScsiReq->ChainOffset = 0;
3059 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3060 } else {
3061 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003062 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 pScsiReq->ChainOffset = 0;
3064 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3065 }
3066
3067 pScsiReq->CDBLength = cmdLen;
3068 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3069
3070 pScsiReq->Reserved = 0;
3071
3072 pScsiReq->MsgFlags = mpt_msg_flags();
3073 /* MsgContext set in mpt_get_msg_fram call */
3074
Eric Moore793955f2007-01-29 09:42:20 -07003075 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076
3077 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3078 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3079 else
3080 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3081
3082 if (cmd == REQUEST_SENSE) {
3083 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3084 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3085 hd->ioc->name, cmd));
3086 }
3087
3088 for (ii=0; ii < 16; ii++)
3089 pScsiReq->CDB[ii] = CDB[ii];
3090
3091 pScsiReq->DataLength = cpu_to_le32(io->size);
3092 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3093 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3094
3095 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003096 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
3098 if (dir == MPI_SCSIIO_CONTROL_READ) {
3099 mpt_add_sge((char *) &pScsiReq->SGL,
3100 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3101 io->data_dma);
3102 } else {
3103 mpt_add_sge((char *) &pScsiReq->SGL,
3104 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3105 io->data_dma);
3106 }
3107
3108 /* The ISR will free the request frame, but we need
3109 * the information to initialize the target. Duplicate.
3110 */
3111 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3112
3113 /* Issue this command after:
3114 * finish init
3115 * add timer
3116 * Wait until the reply has been received
3117 * ScsiScanDvCtx callback function will
3118 * set hd->pLocal;
3119 * set scandv_wait_done and call wake_up
3120 */
3121 hd->pLocal = NULL;
3122 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003123 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
3125 /* Save cmd pointer, for resource free if timeout or
3126 * FW reload occurs
3127 */
3128 hd->cmdPtr = mf;
3129
3130 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003131 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3132 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 if (hd->pLocal) {
3135 rc = hd->pLocal->completion;
3136 hd->pLocal->skip = 0;
3137
3138 /* Always set fatal error codes in some cases.
3139 */
3140 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3141 rc = -ENXIO;
3142 else if (rc == MPT_SCANDV_SOME_ERROR)
3143 rc = -rc;
3144 } else {
3145 rc = -EFAULT;
3146 /* This should never happen. */
3147 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3148 hd->ioc->name));
3149 }
3150
3151 return rc;
3152}
3153
3154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3155/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003156 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3157 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003158 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003159 *
3160 * Uses the ISR, but with special processing.
3161 * MUST be single-threaded.
3162 *
3163 */
3164static void
3165mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3166{
3167 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
3169 /* Following parameters will not change
3170 * in this routine.
3171 */
3172 iocmd.cmd = SYNCHRONIZE_CACHE;
3173 iocmd.flags = 0;
3174 iocmd.physDiskNum = -1;
3175 iocmd.data = NULL;
3176 iocmd.data_dma = -1;
3177 iocmd.size = 0;
3178 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003179 iocmd.channel = vdevice->vtarget->channel;
3180 iocmd.id = vdevice->vtarget->id;
3181 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
James Bottomleyc92f2222006-03-01 09:02:49 -06003183 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003184 (vdevice->configured_lun))
3185 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186}
3187
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003188EXPORT_SYMBOL(mptscsih_remove);
3189EXPORT_SYMBOL(mptscsih_shutdown);
3190#ifdef CONFIG_PM
3191EXPORT_SYMBOL(mptscsih_suspend);
3192EXPORT_SYMBOL(mptscsih_resume);
3193#endif
3194EXPORT_SYMBOL(mptscsih_proc_info);
3195EXPORT_SYMBOL(mptscsih_info);
3196EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003197EXPORT_SYMBOL(mptscsih_slave_destroy);
3198EXPORT_SYMBOL(mptscsih_slave_configure);
3199EXPORT_SYMBOL(mptscsih_abort);
3200EXPORT_SYMBOL(mptscsih_dev_reset);
3201EXPORT_SYMBOL(mptscsih_bus_reset);
3202EXPORT_SYMBOL(mptscsih_host_reset);
3203EXPORT_SYMBOL(mptscsih_bios_param);
3204EXPORT_SYMBOL(mptscsih_io_done);
3205EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3206EXPORT_SYMBOL(mptscsih_scandv_complete);
3207EXPORT_SYMBOL(mptscsih_event_process);
3208EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003209EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003210EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003211EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003213/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/