blob: 10927e34c2b4195b11232e4a8665f44f01334d8a [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{
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001191 mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return 0;
1193}
1194
1195#endif
1196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1198/**
1199 * mptscsih_info - Return information about MPT adapter
1200 * @SChost: Pointer to Scsi_Host structure
1201 *
1202 * (linux scsi_host_template.info routine)
1203 *
1204 * Returns pointer to buffer where information was written.
1205 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001206const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207mptscsih_info(struct Scsi_Host *SChost)
1208{
1209 MPT_SCSI_HOST *h;
1210 int size = 0;
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001215 if (h->info_kbuf == NULL)
1216 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1217 return h->info_kbuf;
1218 h->info_kbuf[0] = '\0';
1219
1220 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1221 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 }
1223
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001224 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225}
1226
1227struct info_str {
1228 char *buffer;
1229 int length;
1230 int offset;
1231 int pos;
1232};
1233
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234static void
1235mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236{
1237 if (info->pos + len > info->length)
1238 len = info->length - info->pos;
1239
1240 if (info->pos + len < info->offset) {
1241 info->pos += len;
1242 return;
1243 }
1244
1245 if (info->pos < info->offset) {
1246 data += (info->offset - info->pos);
1247 len -= (info->offset - info->pos);
1248 }
1249
1250 if (len > 0) {
1251 memcpy(info->buffer + info->pos, data, len);
1252 info->pos += len;
1253 }
1254}
1255
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001256static int
1257mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258{
1259 va_list args;
1260 char buf[81];
1261 int len;
1262
1263 va_start(args, fmt);
1264 len = vsprintf(buf, fmt, args);
1265 va_end(args);
1266
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001267 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return len;
1269}
1270
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001271static int
1272mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
1274 struct info_str info;
1275
1276 info.buffer = pbuf;
1277 info.length = len;
1278 info.offset = offset;
1279 info.pos = 0;
1280
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001281 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1282 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1283 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1284 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1287}
1288
1289/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1290/**
1291 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001292 * @host: scsi host struct
1293 * @buffer: if write, user data; if read, buffer for user
1294 * @start: returns the buffer address
1295 * @offset: if write, 0; if read, the current offset into the buffer from
1296 * the previous read.
1297 * @length: if write, return length;
1298 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 *
1300 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001302int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1304 int length, int func)
1305{
1306 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1307 MPT_ADAPTER *ioc = hd->ioc;
1308 int size = 0;
1309
1310 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001311 /*
1312 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 */
1314 } else {
1315 if (start)
1316 *start = buffer;
1317
1318 size = mptscsih_host_info(ioc, buffer, offset, length);
1319 }
1320
1321 return size;
1322}
1323
1324/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1325#define ADD_INDEX_LOG(req_ent) do { } while(0)
1326
1327/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1328/**
1329 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1330 * @SCpnt: Pointer to scsi_cmnd structure
1331 * @done: Pointer SCSI mid-layer IO completion function
1332 *
1333 * (linux scsi_host_template.queuecommand routine)
1334 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1335 * from a linux scsi_cmnd request and send it to the IOC.
1336 *
1337 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1338 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001339int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1341{
1342 MPT_SCSI_HOST *hd;
1343 MPT_FRAME_HDR *mf;
1344 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001345 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 int lun;
1347 u32 datalen;
1348 u32 scsictl;
1349 u32 scsidir;
1350 u32 cmd_len;
1351 int my_idx;
1352 int ii;
1353
1354 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 lun = SCpnt->device->lun;
1356 SCpnt->scsi_done = done;
1357
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1359 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1360
1361 if (hd->resetPending) {
1362 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1363 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1364 return SCSI_MLQUEUE_HOST_BUSY;
1365 }
1366
1367 /*
1368 * Put together a MPT SCSI request...
1369 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001370 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1372 hd->ioc->name));
1373 return SCSI_MLQUEUE_HOST_BUSY;
1374 }
1375
1376 pScsiReq = (SCSIIORequest_t *) mf;
1377
1378 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1379
1380 ADD_INDEX_LOG(my_idx);
1381
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001382 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 * Seems we may receive a buffer (datalen>0) even when there
1384 * will be no data transfer! GRRRRR...
1385 */
1386 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1387 datalen = SCpnt->request_bufflen;
1388 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1389 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1390 datalen = SCpnt->request_bufflen;
1391 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1392 } else {
1393 datalen = 0;
1394 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1395 }
1396
1397 /* Default to untagged. Once a target structure has been allocated,
1398 * use the Inquiry data to determine if device supports tagged.
1399 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001400 if (vdev
1401 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 && (SCpnt->device->tagged_supported)) {
1403 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1404 } else {
1405 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1406 }
1407
1408 /* Use the above information to set up the message frame
1409 */
Eric Moore793955f2007-01-29 09:42:20 -07001410 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1411 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001413 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1414 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1415 else
1416 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 pScsiReq->CDBLength = SCpnt->cmd_len;
1418 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1419 pScsiReq->Reserved = 0;
1420 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001421 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 pScsiReq->Control = cpu_to_le32(scsictl);
1423
1424 /*
1425 * Write SCSI CDB into the message
1426 */
1427 cmd_len = SCpnt->cmd_len;
1428 for (ii=0; ii < cmd_len; ii++)
1429 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1430
1431 for (ii=cmd_len; ii < 16; ii++)
1432 pScsiReq->CDB[ii] = 0;
1433
1434 /* DataLength */
1435 pScsiReq->DataLength = cpu_to_le32(datalen);
1436
1437 /* SenseBuffer low address */
1438 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1439 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1440
1441 /* Now add the SG list
1442 * Always have a SGE even if null length.
1443 */
1444 if (datalen == 0) {
1445 /* Add a NULL SGE */
1446 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1447 (dma_addr_t) -1);
1448 } else {
1449 /* Add a 32 or 64 bit SGE */
1450 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1451 goto fail;
1452 }
1453
Eric Moore3dc0b032006-07-11 17:32:33 -06001454 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001457 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1459 hd->ioc->name, SCpnt, mf, my_idx));
1460 DBG_DUMP_REQUEST_FRAME(mf)
1461 return 0;
1462
1463 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001464 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1466 mpt_free_msg_frame(hd->ioc, mf);
1467 return SCSI_MLQUEUE_HOST_BUSY;
1468}
1469
1470/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1471/*
1472 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1473 * with a SCSI IO request
1474 * @hd: Pointer to the MPT_SCSI_HOST instance
1475 * @req_idx: Index of the SCSI IO request frame.
1476 *
1477 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1478 * No return.
1479 */
1480static void
1481mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1482{
1483 MPT_FRAME_HDR *chain;
1484 unsigned long flags;
1485 int chain_idx;
1486 int next;
1487
1488 /* Get the first chain index and reset
1489 * tracker state.
1490 */
1491 chain_idx = ioc->ReqToChain[req_idx];
1492 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1493
1494 while (chain_idx != MPT_HOST_NO_CHAIN) {
1495
1496 /* Save the next chain buffer index */
1497 next = ioc->ChainToChain[chain_idx];
1498
1499 /* Free this chain buffer and reset
1500 * tracker
1501 */
1502 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1503
1504 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1505 + (chain_idx * ioc->req_sz));
1506
1507 spin_lock_irqsave(&ioc->FreeQlock, flags);
1508 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1510
1511 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1512 ioc->name, chain_idx));
1513
1514 /* handle next */
1515 chain_idx = next;
1516 }
1517 return;
1518}
1519
1520/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1521/*
1522 * Reset Handling
1523 */
1524
1525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001526/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001528 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001530 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001531 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 * @lun: Logical Unit for reset (if appropriate)
1533 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001534 * @timeout: timeout for task management control
1535 *
1536 * Fall through to mpt_HardResetHandler if: not operational, too many
1537 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 *
1539 * Remark: Currently invoked from a non-interrupt thread (_bh).
1540 *
1541 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1542 * will be active.
1543 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001544 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001545 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001546int
Eric Moore793955f2007-01-29 09:42:20 -07001547mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548{
1549 MPT_ADAPTER *ioc;
1550 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 u32 ioc_raw_state;
1552 unsigned long flags;
1553
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1556
1557 // SJR - CHECKME - Can we avoid this here?
1558 // (mpt_HardResetHandler has this check...)
1559 spin_lock_irqsave(&ioc->diagLock, flags);
1560 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1561 spin_unlock_irqrestore(&ioc->diagLock, flags);
1562 return FAILED;
1563 }
1564 spin_unlock_irqrestore(&ioc->diagLock, flags);
1565
1566 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001567 * If we time out and not bus reset, then we return a FAILED status
1568 * to the caller.
1569 * The call to mptscsih_tm_pending_wait() will set the pending flag
1570 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 * successful. Otherwise, reload the FW.
1572 */
1573 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1574 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001575 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 "Timed out waiting for last TM (%d) to complete! \n",
1577 hd->ioc->name, hd->tmPending));
1578 return FAILED;
1579 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001580 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1581 "reset: Timed out waiting for last TM (%d) "
1582 "to complete! \n", hd->ioc->name,
1583 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 return FAILED;
1585 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001586 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 "Timed out waiting for last TM (%d) to complete! \n",
1588 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001589 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 }
1591 } else {
1592 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1593 hd->tmPending |= (1 << type);
1594 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1595 }
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1600 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001601 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1602 ioc->name, type, ioc_raw_state);
1603 printk(KERN_WARNING " Issuing HardReset!!\n");
1604 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1605 printk((KERN_WARNING "TMHandler: HardReset "
1606 "FAILED!!\n"));
1607 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
1609
Eric Moorecd2c6192007-01-29 09:47:47 -07001610 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1611 printk(MYIOC_s_WARN_FMT
1612 "TM Handler for type=%x: ioc_state: "
1613 "DOORBELL_ACTIVE (0x%x)!\n",
1614 ioc->name, type, ioc_raw_state);
1615 return FAILED;
1616 }
1617
1618 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001620 if (hd->hard_resets < -1)
1621 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Eric Moorecd2c6192007-01-29 09:47:47 -07001623 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1624 ctx2abort, timeout);
1625 if (rc)
1626 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1627 hd->ioc->name);
1628 else
1629 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1630 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001631
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1633
1634 return rc;
1635}
1636
1637
1638/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001639/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1641 * @hd: Pointer to MPT_SCSI_HOST structure
1642 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001643 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001644 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 * @lun: Logical Unit for reset (if appropriate)
1646 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001647 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 *
1649 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1650 * or a non-interrupt thread. In the former, must not call schedule().
1651 *
1652 * Not all fields are meaningfull for all task types.
1653 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001654 * Returns 0 for SUCCESS, or FAILED.
1655 *
1656 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657static int
Eric Moore793955f2007-01-29 09:42:20 -07001658mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659{
1660 MPT_FRAME_HDR *mf;
1661 SCSITaskMgmt_t *pScsiTm;
1662 int ii;
1663 int retval;
1664
1665 /* Return Fail to calling function if no message frames available.
1666 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001667 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1669 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001670 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 }
1672 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1673 hd->ioc->name, mf));
1674
1675 /* Format the Request
1676 */
1677 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001678 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 pScsiTm->Bus = channel;
1680 pScsiTm->ChainOffset = 0;
1681 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1682
1683 pScsiTm->Reserved = 0;
1684 pScsiTm->TaskType = type;
1685 pScsiTm->Reserved1 = 0;
1686 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1687 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1688
Eric Moore793955f2007-01-29 09:42:20 -07001689 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 for (ii=0; ii < 7; ii++)
1692 pScsiTm->Reserved2[ii] = 0;
1693
1694 pScsiTm->TaskMsgContext = ctx2abort;
1695
Eric Moorecd2c6192007-01-29 09:47:47 -07001696 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1697 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1700
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001701 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001702 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1703 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1704 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1705 hd->ioc, mf, retval));
1706 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 }
1708
1709 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001710 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1712 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1714 hd->ioc->name));
1715 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001716 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1717 hd->ioc->name, retval));
1718 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 }
1720
Eric Moorecd2c6192007-01-29 09:47:47 -07001721 /*
1722 * Handle success case, see if theres a non-zero ioc_status.
1723 */
1724 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1725 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1726 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1727 retval = 0;
1728 else
1729 retval = FAILED;
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001732
1733 fail_out:
1734
1735 /*
1736 * Free task managment mf, and corresponding tm flags
1737 */
1738 mpt_free_msg_frame(hd->ioc, mf);
1739 hd->tmPending = 0;
1740 hd->tmState = TM_STATE_NONE;
1741 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742}
1743
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001744static int
1745mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1746{
1747 switch (ioc->bus_type) {
1748 case FC:
1749 return 40;
1750 case SAS:
1751 return 10;
1752 case SPI:
1753 default:
1754 return 2;
1755 }
1756}
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1759/**
1760 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1761 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1762 *
1763 * (linux scsi_host_template.eh_abort_handler routine)
1764 *
1765 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001766 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001767int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768mptscsih_abort(struct scsi_cmnd * SCpnt)
1769{
1770 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 MPT_FRAME_HDR *mf;
1772 u32 ctx2abort;
1773 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001774 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001775 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001776 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 /* If we can't locate our host adapter structure, return FAILED status.
1779 */
1780 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1781 SCpnt->result = DID_RESET << 16;
1782 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 "Can't locate host! (sc=%p)\n",
1785 SCpnt));
1786 return FAILED;
1787 }
1788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 /* Find this command
1790 */
1791 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001792 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 * Do OS callback.
1794 */
1795 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001796 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 "Command not in the active list! (sc=%p)\n",
1798 hd->ioc->name, SCpnt));
1799 return SUCCESS;
1800 }
1801
Eric Moorecd2c6192007-01-29 09:47:47 -07001802 if (hd->resetPending)
Moore, Eric65207fe2006-04-21 16:14:35 -06001803 return FAILED;
Moore, Eric65207fe2006-04-21 16:14:35 -06001804
1805 if (hd->timeouts < -1)
1806 hd->timeouts++;
1807
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001808 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1809 hd->ioc->name, SCpnt);
1810 scsi_print_command(SCpnt);
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1813 * (the IO to be ABORT'd)
1814 *
1815 * NOTE: Since we do not byteswap MsgContext, we do not
1816 * swap it here either. It is an opaque cookie to
1817 * the controller, so it does not matter. -DaveM
1818 */
1819 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1820 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1821
1822 hd->abortSCpnt = SCpnt;
1823
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001824 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001825 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore793955f2007-01-29 09:42:20 -07001826 vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001827 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
Eric Moore3dc0b032006-07-11 17:32:33 -06001829 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001830 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001831 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001832
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001833 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1834 hd->ioc->name,
1835 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001837 if (retval == 0)
1838 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001839 else
1840 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841}
1842
1843/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1844/**
1845 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1846 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1847 *
1848 * (linux scsi_host_template.eh_dev_reset_handler routine)
1849 *
1850 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001851 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001852int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1854{
1855 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001856 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001857 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 /* If we can't locate our host adapter structure, return FAILED status.
1860 */
1861 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001862 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 "Can't locate host! (sc=%p)\n",
1864 SCpnt));
1865 return FAILED;
1866 }
1867
1868 if (hd->resetPending)
1869 return FAILED;
1870
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001871 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001873 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001875 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001876 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -07001877 vdev->vtarget->channel, vdev->vtarget->id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001878 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001879
1880 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1881 hd->ioc->name,
1882 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1883
1884 if (retval == 0)
1885 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001886 else
1887 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888}
1889
Eric Moorecd2c6192007-01-29 09:47:47 -07001890
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1892/**
1893 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1894 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1895 *
1896 * (linux scsi_host_template.eh_bus_reset_handler routine)
1897 *
1898 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001899 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001900int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1902{
1903 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001904 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001905 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907 /* If we can't locate our host adapter structure, return FAILED status.
1908 */
1909 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001910 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 "Can't locate host! (sc=%p)\n",
1912 SCpnt ) );
1913 return FAILED;
1914 }
1915
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001916 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001918 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920 if (hd->timeouts < -1)
1921 hd->timeouts++;
1922
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001923 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001924 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore793955f2007-01-29 09:42:20 -07001925 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001927 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1928 hd->ioc->name,
1929 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1930
1931 if (retval == 0)
1932 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001933 else
1934 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935}
1936
1937/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1938/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001939 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1941 *
1942 * (linux scsi_host_template.eh_host_reset_handler routine)
1943 *
1944 * Returns SUCCESS or FAILED.
1945 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001946int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1948{
1949 MPT_SCSI_HOST * hd;
1950 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
1952 /* If we can't locate the host to reset, then we failed. */
1953 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001954 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 "Can't locate host! (sc=%p)\n",
1956 SCpnt ) );
1957 return FAILED;
1958 }
1959
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001960 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 hd->ioc->name, SCpnt);
1962
1963 /* If our attempts to reset the host failed, then return a failed
1964 * status. The host will be taken off line by the SCSI mid-layer.
1965 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1967 status = FAILED;
1968 } else {
1969 /* Make sure TM pending is cleared and TM state is set to
1970 * NONE.
1971 */
1972 hd->tmPending = 0;
1973 hd->tmState = TM_STATE_NONE;
1974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001976 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 "Status = %s\n",
1978 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1979
1980 return status;
1981}
1982
1983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1984/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001985 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 * @hd: Pointer to MPT host structure.
1987 *
1988 * Returns {SUCCESS,FAILED}.
1989 */
1990static int
1991mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1992{
1993 unsigned long flags;
1994 int loop_count = 4 * 10; /* Wait 10 seconds */
1995 int status = FAILED;
1996
1997 do {
1998 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1999 if (hd->tmState == TM_STATE_NONE) {
2000 hd->tmState = TM_STATE_IN_PROGRESS;
2001 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002003 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 break;
2005 }
2006 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2007 msleep(250);
2008 } while (--loop_count);
2009
2010 return status;
2011}
2012
2013/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2014/**
2015 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2016 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002017 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 *
2019 * Returns {SUCCESS,FAILED}.
2020 */
2021static int
2022mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2023{
2024 unsigned long flags;
2025 int loop_count = 4 * timeout;
2026 int status = FAILED;
2027
2028 do {
2029 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2030 if(hd->tmPending == 0) {
2031 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002032 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 break;
2034 }
2035 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002036 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 } while (--loop_count);
2038
2039 return status;
2040}
2041
2042/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002043static void
2044mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2045{
2046 char *desc;
2047
2048 switch (response_code) {
2049 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2050 desc = "The task completed.";
2051 break;
2052 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2053 desc = "The IOC received an invalid frame status.";
2054 break;
2055 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2056 desc = "The task type is not supported.";
2057 break;
2058 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2059 desc = "The requested task failed.";
2060 break;
2061 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2062 desc = "The task completed successfully.";
2063 break;
2064 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2065 desc = "The LUN request is invalid.";
2066 break;
2067 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2068 desc = "The task is in the IOC queue and has not been sent to target.";
2069 break;
2070 default:
2071 desc = "unknown";
2072 break;
2073 }
2074 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2075 ioc->name, response_code, desc);
2076}
2077
2078/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079/**
2080 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2081 * @ioc: Pointer to MPT_ADAPTER structure
2082 * @mf: Pointer to SCSI task mgmt request frame
2083 * @mr: Pointer to SCSI task mgmt reply frame
2084 *
2085 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2086 * of any SCSI task management request.
2087 * This routine is registered with the MPT (base) driver at driver
2088 * load/init time via the mpt_register() API call.
2089 *
2090 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002091 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002092int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2094{
2095 SCSITaskMgmtReply_t *pScsiTmReply;
2096 SCSITaskMgmt_t *pScsiTmReq;
2097 MPT_SCSI_HOST *hd;
2098 unsigned long flags;
2099 u16 iocstatus;
2100 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002101 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
2103 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002104 ioc->name, mf, mr));
2105 if (!ioc->sh) {
2106 dtmprintk((MYIOC_s_WARN_FMT
2107 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 return 1;
2109 }
2110
2111 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002112 dtmprintk((MYIOC_s_WARN_FMT
2113 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
2116
Eric Moorecd2c6192007-01-29 09:47:47 -07002117 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2118 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2119 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2120 tmType = pScsiTmReq->TaskType;
2121 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2122 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2123
2124 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2125 pScsiTmReply->ResponseCode)
2126 mptscsih_taskmgmt_response_code(ioc,
2127 pScsiTmReply->ResponseCode);
2128 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2129
2130#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2131 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2132 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2133 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2134 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2135 le16_to_cpu(pScsiTmReply->IOCStatus),
2136 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2137 le32_to_cpu(pScsiTmReply->TerminationCount));
2138#endif
2139 if (!iocstatus) {
2140 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2141 hd->abortSCpnt = NULL;
2142 goto out;
2143 }
2144
2145 /* Error? (anything non-zero?) */
2146
2147 /* clear flags and continue.
2148 */
2149 switch (tmType) {
2150
2151 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2152 if (termination_count == 1)
2153 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2154 hd->abortSCpnt = NULL;
2155 break;
2156
2157 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2158
2159 /* If an internal command is present
2160 * or the TM failed - reload the FW.
2161 * FC FW may respond FAILED to an ABORT
2162 */
2163 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2164 hd->cmdPtr)
2165 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2166 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2167 break;
2168
2169 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2170 default:
2171 break;
2172 }
2173
2174 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 spin_lock_irqsave(&ioc->FreeQlock, flags);
2176 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002178 hd->tm_iocstatus = iocstatus;
2179 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
2181 return 1;
2182}
2183
2184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2185/*
2186 * This is anyones guess quite frankly.
2187 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002188int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2190 sector_t capacity, int geom[])
2191{
2192 int heads;
2193 int sectors;
2194 sector_t cylinders;
2195 ulong dummy;
2196
2197 heads = 64;
2198 sectors = 32;
2199
2200 dummy = heads * sectors;
2201 cylinders = capacity;
2202 sector_div(cylinders,dummy);
2203
2204 /*
2205 * Handle extended translation size for logical drives
2206 * > 1Gb
2207 */
2208 if ((ulong)capacity >= 0x200000) {
2209 heads = 255;
2210 sectors = 63;
2211 dummy = heads * sectors;
2212 cylinders = capacity;
2213 sector_div(cylinders,dummy);
2214 }
2215
2216 /* return result */
2217 geom[0] = heads;
2218 geom[1] = sectors;
2219 geom[2] = cylinders;
2220
2221 dprintk((KERN_NOTICE
2222 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002223 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
2225 return 0;
2226}
2227
Moore, Ericf44e5462006-03-14 09:14:21 -07002228/* Search IOC page 3 to determine if this is hidden physical disk
2229 *
2230 */
2231int
Eric Moore793955f2007-01-29 09:42:20 -07002232mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002233{
Eric Mooreb506ade2007-01-29 09:45:37 -07002234 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002235 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002236 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002237
Eric Moore793955f2007-01-29 09:42:20 -07002238 if (!ioc->raid_data.pIocPg3)
2239 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002240 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002241 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2242 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2243 rc = 1;
2244 goto out;
2245 }
2246 }
2247
Eric Mooreb506ade2007-01-29 09:45:37 -07002248 /*
2249 * Check inactive list for matching phys disks
2250 */
2251 if (list_empty(&ioc->raid_data.inactive_list))
2252 goto out;
2253
2254 down(&ioc->raid_data.inactive_list_mutex);
2255 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2256 list) {
2257 if ((component_info->d.PhysDiskID == id) &&
2258 (component_info->d.PhysDiskBus == channel))
2259 rc = 1;
2260 }
2261 up(&ioc->raid_data.inactive_list_mutex);
2262
Eric Moore793955f2007-01-29 09:42:20 -07002263 out:
2264 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002265}
2266EXPORT_SYMBOL(mptscsih_is_phys_disk);
2267
Eric Moore793955f2007-01-29 09:42:20 -07002268u8
2269mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002270{
Eric Mooreb506ade2007-01-29 09:45:37 -07002271 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002272 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002273 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002274
Eric Moore793955f2007-01-29 09:42:20 -07002275 if (!ioc->raid_data.pIocPg3)
2276 goto out;
2277 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2278 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2279 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2280 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2281 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002282 }
2283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
Eric Mooreb506ade2007-01-29 09:45:37 -07002285 /*
2286 * Check inactive list for matching phys disks
2287 */
2288 if (list_empty(&ioc->raid_data.inactive_list))
2289 goto out;
2290
2291 down(&ioc->raid_data.inactive_list_mutex);
2292 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2293 list) {
2294 if ((component_info->d.PhysDiskID == id) &&
2295 (component_info->d.PhysDiskBus == channel))
2296 rc = component_info->d.PhysDiskNum;
2297 }
2298 up(&ioc->raid_data.inactive_list_mutex);
2299
Eric Moore793955f2007-01-29 09:42:20 -07002300 out:
2301 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002302}
Eric Moore793955f2007-01-29 09:42:20 -07002303EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002304
2305/*
2306 * OS entry point to allow for host driver to free allocated memory
2307 * Called if no device present or device being unloaded
2308 */
2309void
2310mptscsih_slave_destroy(struct scsi_device *sdev)
2311{
2312 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002314 VirtTarget *vtarget;
2315 VirtDevice *vdevice;
2316 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002318 starget = scsi_target(sdev);
2319 vtarget = starget->hostdata;
2320 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002323 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 mptscsih_synchronize_cache(hd, vdevice);
2325 kfree(vdevice);
2326 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327}
2328
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002329/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2330/*
2331 * mptscsih_change_queue_depth - This function will set a devices queue depth
2332 * @sdev: per scsi_device pointer
2333 * @qdepth: requested queue depth
2334 *
2335 * Adding support for new 'change_queue_depth' api.
2336*/
2337int
2338mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002340 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2341 VirtTarget *vtarget;
2342 struct scsi_target *starget;
2343 int max_depth;
2344 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002346 starget = scsi_target(sdev);
2347 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002348
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002349 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002350 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002352 else if (sdev->type == TYPE_DISK &&
2353 vtarget->minSyncFactor <= MPT_ULTRA160)
2354 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2355 else
2356 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 } else
2358 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2359
2360 if (qdepth > max_depth)
2361 qdepth = max_depth;
2362 if (qdepth == 1)
2363 tagged = 0;
2364 else
2365 tagged = MSG_SIMPLE_TAG;
2366
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002367 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2368 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369}
2370
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371/*
2372 * OS entry point to adjust the queue_depths on a per-device basis.
2373 * Called once per device the bus scan. Use it to force the queue_depth
2374 * member to 1 if a device does not support Q tags.
2375 * Return non-zero if fails.
2376 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002377int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002378mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002380 struct Scsi_Host *sh = sdev->host;
2381 VirtTarget *vtarget;
2382 VirtDevice *vdevice;
2383 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2385
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002386 starget = scsi_target(sdev);
2387 vtarget = starget->hostdata;
2388 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389
2390 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002391 "device @ %p, channel=%d, id=%d, lun=%d\n",
2392 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002393 if (hd->ioc->bus_type == SPI)
2394 dsprintk((MYIOC_s_INFO_FMT
2395 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2396 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2397 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002399 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002401 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 goto slave_configure_exit;
2403 }
2404
Eric Moore793955f2007-01-29 09:42:20 -07002405 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002406 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408 dsprintk((MYIOC_s_INFO_FMT
2409 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002410 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002412 if (hd->ioc->bus_type == SPI)
2413 dsprintk((MYIOC_s_INFO_FMT
2414 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2415 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2416 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
2418slave_configure_exit:
2419
2420 dsprintk((MYIOC_s_INFO_FMT
2421 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002422 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2423 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 return 0;
2426}
2427
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2429/*
2430 * Private routines...
2431 */
2432
2433/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2434/* Utility function to copy sense data from the scsi_cmnd buffer
2435 * to the FC and SCSI target structures.
2436 *
2437 */
2438static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002439mptscsih_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 -07002440{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002441 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 SCSIIORequest_t *pReq;
2443 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
2445 /* Get target structure
2446 */
2447 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002448 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
2450 if (sense_count) {
2451 u8 *sense_data;
2452 int req_index;
2453
2454 /* Copy the sense received into the scsi command block. */
2455 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2456 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2457 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2458
2459 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2460 */
2461 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002462 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 int idx;
2464 MPT_ADAPTER *ioc = hd->ioc;
2465
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002466 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2468 ioc->events[idx].eventContext = ioc->eventContext;
2469
2470 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2471 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002472 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
2474 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2475
2476 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002477 if (hd->ioc->pcidev->vendor ==
2478 PCI_VENDOR_ID_IBM) {
2479 mptscsih_issue_sep_command(hd->ioc,
2480 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2481 vdev->vtarget->tflags |=
2482 MPT_TARGET_FLAGS_LED_ON;
2483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486 } else {
2487 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2488 hd->ioc->name));
2489 }
2490}
2491
Eric Moore3dc0b032006-07-11 17:32:33 -06002492static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2494{
2495 MPT_SCSI_HOST *hd;
2496 int i;
2497
2498 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2499
2500 for (i = 0; i < hd->ioc->req_depth; i++) {
2501 if (hd->ScsiLookup[i] == sc) {
2502 return i;
2503 }
2504 }
2505
2506 return -1;
2507}
2508
2509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002510int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2512{
2513 MPT_SCSI_HOST *hd;
2514 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002515 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
2517 dtmprintk((KERN_WARNING MYNAM
2518 ": IOC %s_reset routed to SCSI host driver!\n",
2519 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2520 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2521
2522 /* If a FW reload request arrives after base installed but
2523 * before all scsi hosts have been attached, then an alt_ioc
2524 * may have a NULL sh pointer.
2525 */
2526 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2527 return 0;
2528 else
2529 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2530
2531 if (reset_phase == MPT_IOC_SETUP_RESET) {
2532 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2533
2534 /* Clean Up:
2535 * 1. Set Hard Reset Pending Flag
2536 * All new commands go to doneQ
2537 */
2538 hd->resetPending = 1;
2539
2540 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2541 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2542
2543 /* 2. Flush running commands
2544 * Clean ScsiLookup (and associated memory)
2545 * AND clean mytaskQ
2546 */
2547
2548 /* 2b. Reply to OS all known outstanding I/O commands.
2549 */
2550 mptscsih_flush_running_cmds(hd);
2551
2552 /* 2c. If there was an internal command that
2553 * has not completed, configuration or io request,
2554 * free these resources.
2555 */
2556 if (hd->cmdPtr) {
2557 del_timer(&hd->timer);
2558 mpt_free_msg_frame(ioc, hd->cmdPtr);
2559 }
2560
2561 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2562
2563 } else {
2564 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2565
2566 /* Once a FW reload begins, all new OS commands are
2567 * redirected to the doneQ w/ a reset status.
2568 * Init all control structures.
2569 */
2570
2571 /* ScsiLookup initialization
2572 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002573 for (ii=0; ii < hd->ioc->req_depth; ii++)
2574 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
2576 /* 2. Chain Buffer initialization
2577 */
2578
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002579 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582 /* 5. Enable new commands to be posted
2583 */
2584 spin_lock_irqsave(&ioc->FreeQlock, flags);
2585 hd->tmPending = 0;
2586 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2587 hd->resetPending = 0;
2588 hd->tmState = TM_STATE_NONE;
2589
2590 /* 6. If there was an internal command,
2591 * wake this process up.
2592 */
2593 if (hd->cmdPtr) {
2594 /*
2595 * Wake up the original calling thread
2596 */
2597 hd->pLocal = &hd->localReply;
2598 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002599 hd->scandv_wait_done = 1;
2600 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 hd->cmdPtr = NULL;
2602 }
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2605
2606 }
2607
2608 return 1; /* currently means nothing really */
2609}
2610
2611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002612int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2614{
2615 MPT_SCSI_HOST *hd;
2616 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2617
Moore, Eric3a892be2006-03-14 09:14:03 -07002618 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 ioc->name, event));
2620
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002621 if (ioc->sh == NULL ||
2622 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2623 return 1;
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 switch (event) {
2626 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2627 /* FIXME! */
2628 break;
2629 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2630 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002631 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002632 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 break;
2634 case MPI_EVENT_LOGOUT: /* 09 */
2635 /* FIXME! */
2636 break;
2637
Michael Reed05e8ec12006-01-13 14:31:54 -06002638 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002639 break;
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 /*
2642 * CHECKME! Don't think we need to do
2643 * anything for these, but...
2644 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2646 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2647 /*
2648 * CHECKME! Falling thru...
2649 */
2650 break;
2651
2652 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002653 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 case MPI_EVENT_NONE: /* 00 */
2656 case MPI_EVENT_LOG_DATA: /* 01 */
2657 case MPI_EVENT_STATE_CHANGE: /* 02 */
2658 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2659 default:
2660 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2661 break;
2662 }
2663
2664 return 1; /* currently means nothing really */
2665}
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2668/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 * Bus Scan and Domain Validation functionality ...
2670 */
2671
2672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2673/*
2674 * mptscsih_scandv_complete - Scan and DV callback routine registered
2675 * to Fustion MPT (base) driver.
2676 *
2677 * @ioc: Pointer to MPT_ADAPTER structure
2678 * @mf: Pointer to original MPT request frame
2679 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2680 *
2681 * This routine is called from mpt.c::mpt_interrupt() at the completion
2682 * of any SCSI IO request.
2683 * This routine is registered with the Fusion MPT (base) driver at driver
2684 * load/init time via the mpt_register() API call.
2685 *
2686 * Returns 1 indicating alloc'd request frame ptr should be freed.
2687 *
2688 * Remark: Sets a completion code and (possibly) saves sense data
2689 * in the IOC member localReply structure.
2690 * Used ONLY for DV and other internal commands.
2691 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002692int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2694{
2695 MPT_SCSI_HOST *hd;
2696 SCSIIORequest_t *pReq;
2697 int completionCode;
2698 u16 req_idx;
2699
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002700 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 if ((mf == NULL) ||
2703 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2704 printk(MYIOC_s_ERR_FMT
2705 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2706 ioc->name, mf?"BAD":"NULL", (void *) mf);
2707 goto wakeup;
2708 }
2709
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 del_timer(&hd->timer);
2711 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2712 hd->ScsiLookup[req_idx] = NULL;
2713 pReq = (SCSIIORequest_t *) mf;
2714
2715 if (mf != hd->cmdPtr) {
2716 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2717 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2718 }
2719 hd->cmdPtr = NULL;
2720
2721 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2722 hd->ioc->name, mf, mr, req_idx));
2723
2724 hd->pLocal = &hd->localReply;
2725 hd->pLocal->scsiStatus = 0;
2726
2727 /* If target struct exists, clear sense valid flag.
2728 */
2729 if (mr == NULL) {
2730 completionCode = MPT_SCANDV_GOOD;
2731 } else {
2732 SCSIIOReply_t *pReply;
2733 u16 status;
2734 u8 scsi_status;
2735
2736 pReply = (SCSIIOReply_t *) mr;
2737
2738 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2739 scsi_status = pReply->SCSIStatus;
2740
2741 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2742 status, pReply->SCSIState, scsi_status,
2743 le32_to_cpu(pReply->IOCLogInfo)));
2744
2745 switch(status) {
2746
2747 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2748 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2749 break;
2750
2751 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2752 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2753 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2754 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2755 completionCode = MPT_SCANDV_DID_RESET;
2756 break;
2757
2758 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2759 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2760 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2761 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2762 ConfigReply_t *pr = (ConfigReply_t *)mr;
2763 completionCode = MPT_SCANDV_GOOD;
2764 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2765 hd->pLocal->header.PageLength = pr->Header.PageLength;
2766 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2767 hd->pLocal->header.PageType = pr->Header.PageType;
2768
2769 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2770 /* If the RAID Volume request is successful,
2771 * return GOOD, else indicate that
2772 * some type of error occurred.
2773 */
2774 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002775 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 completionCode = MPT_SCANDV_GOOD;
2777 else
2778 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002779 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
2781 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2782 u8 *sense_data;
2783 int sz;
2784
2785 /* save sense data in global structure
2786 */
2787 completionCode = MPT_SCANDV_SENSE;
2788 hd->pLocal->scsiStatus = scsi_status;
2789 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2790 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2791
2792 sz = min_t(int, pReq->SenseBufferLength,
2793 SCSI_STD_SENSE_BYTES);
2794 memcpy(hd->pLocal->sense, sense_data, sz);
2795
2796 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2797 sense_data));
2798 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2799 if (pReq->CDB[0] == INQUIRY)
2800 completionCode = MPT_SCANDV_ISSUE_SENSE;
2801 else
2802 completionCode = MPT_SCANDV_DID_RESET;
2803 }
2804 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2805 completionCode = MPT_SCANDV_DID_RESET;
2806 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2807 completionCode = MPT_SCANDV_DID_RESET;
2808 else {
2809 completionCode = MPT_SCANDV_GOOD;
2810 hd->pLocal->scsiStatus = scsi_status;
2811 }
2812 break;
2813
2814 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2815 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2816 completionCode = MPT_SCANDV_DID_RESET;
2817 else
2818 completionCode = MPT_SCANDV_SOME_ERROR;
2819 break;
2820
2821 default:
2822 completionCode = MPT_SCANDV_SOME_ERROR;
2823 break;
2824
2825 } /* switch(status) */
2826
2827 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2828 completionCode));
2829 } /* end of address reply case */
2830
2831 hd->pLocal->completion = completionCode;
2832
2833 /* MF and RF are freed in mpt_interrupt
2834 */
2835wakeup:
2836 /* Free Chain buffers (will never chain) in scan or dv */
2837 //mptscsih_freeChainBuffers(ioc, req_idx);
2838
2839 /*
2840 * Wake up the original calling thread
2841 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002842 hd->scandv_wait_done = 1;
2843 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
2845 return 1;
2846}
2847
2848/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2849/* mptscsih_timer_expired - Call back for timer process.
2850 * Used only for dv functionality.
2851 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2852 *
2853 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002854void
2855mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856{
2857 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2858
2859 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2860
2861 if (hd->cmdPtr) {
2862 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2863
2864 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2865 /* Desire to issue a task management request here.
2866 * TM requests MUST be single threaded.
2867 * If old eh code and no TM current, issue request.
2868 * If new eh code, do nothing. Wait for OS cmd timeout
2869 * for bus reset.
2870 */
2871 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2872 } else {
2873 /* Perform a FW reload */
2874 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2875 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2876 }
2877 }
2878 } else {
2879 /* This should NEVER happen */
2880 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2881 }
2882
2883 /* No more processing.
2884 * TM call will generate an interrupt for SCSI TM Management.
2885 * The FW will reply to all outstanding commands, callback will finish cleanup.
2886 * Hard reset clean-up will free all resources.
2887 */
2888 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2889
2890 return;
2891}
2892
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2895/**
2896 * mptscsih_do_cmd - Do internal command.
2897 * @hd: MPT_SCSI_HOST pointer
2898 * @io: INTERNAL_CMD pointer.
2899 *
2900 * Issue the specified internally generated command and do command
2901 * specific cleanup. For bus scan / DV only.
2902 * NOTES: If command is Inquiry and status is good,
2903 * initialize a target structure, save the data
2904 *
2905 * Remark: Single threaded access only.
2906 *
2907 * Return:
2908 * < 0 if an illegal command or no resources
2909 *
2910 * 0 if good
2911 *
2912 * > 0 if command complete but some type of completion error.
2913 */
2914static int
2915mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2916{
2917 MPT_FRAME_HDR *mf;
2918 SCSIIORequest_t *pScsiReq;
2919 SCSIIORequest_t ReqCopy;
2920 int my_idx, ii, dir;
2921 int rc, cmdTimeout;
2922 int in_isr;
2923 char cmdLen;
2924 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2925 char cmd = io->cmd;
2926
2927 in_isr = in_interrupt();
2928 if (in_isr) {
2929 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2930 hd->ioc->name));
2931 return -EPERM;
2932 }
2933
2934
2935 /* Set command specific information
2936 */
2937 switch (cmd) {
2938 case INQUIRY:
2939 cmdLen = 6;
2940 dir = MPI_SCSIIO_CONTROL_READ;
2941 CDB[0] = cmd;
2942 CDB[4] = io->size;
2943 cmdTimeout = 10;
2944 break;
2945
2946 case TEST_UNIT_READY:
2947 cmdLen = 6;
2948 dir = MPI_SCSIIO_CONTROL_READ;
2949 cmdTimeout = 10;
2950 break;
2951
2952 case START_STOP:
2953 cmdLen = 6;
2954 dir = MPI_SCSIIO_CONTROL_READ;
2955 CDB[0] = cmd;
2956 CDB[4] = 1; /*Spin up the disk */
2957 cmdTimeout = 15;
2958 break;
2959
2960 case REQUEST_SENSE:
2961 cmdLen = 6;
2962 CDB[0] = cmd;
2963 CDB[4] = io->size;
2964 dir = MPI_SCSIIO_CONTROL_READ;
2965 cmdTimeout = 10;
2966 break;
2967
2968 case READ_BUFFER:
2969 cmdLen = 10;
2970 dir = MPI_SCSIIO_CONTROL_READ;
2971 CDB[0] = cmd;
2972 if (io->flags & MPT_ICFLAG_ECHO) {
2973 CDB[1] = 0x0A;
2974 } else {
2975 CDB[1] = 0x02;
2976 }
2977
2978 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2979 CDB[1] |= 0x01;
2980 }
2981 CDB[6] = (io->size >> 16) & 0xFF;
2982 CDB[7] = (io->size >> 8) & 0xFF;
2983 CDB[8] = io->size & 0xFF;
2984 cmdTimeout = 10;
2985 break;
2986
2987 case WRITE_BUFFER:
2988 cmdLen = 10;
2989 dir = MPI_SCSIIO_CONTROL_WRITE;
2990 CDB[0] = cmd;
2991 if (io->flags & MPT_ICFLAG_ECHO) {
2992 CDB[1] = 0x0A;
2993 } else {
2994 CDB[1] = 0x02;
2995 }
2996 CDB[6] = (io->size >> 16) & 0xFF;
2997 CDB[7] = (io->size >> 8) & 0xFF;
2998 CDB[8] = io->size & 0xFF;
2999 cmdTimeout = 10;
3000 break;
3001
3002 case RESERVE:
3003 cmdLen = 6;
3004 dir = MPI_SCSIIO_CONTROL_READ;
3005 CDB[0] = cmd;
3006 cmdTimeout = 10;
3007 break;
3008
3009 case RELEASE:
3010 cmdLen = 6;
3011 dir = MPI_SCSIIO_CONTROL_READ;
3012 CDB[0] = cmd;
3013 cmdTimeout = 10;
3014 break;
3015
3016 case SYNCHRONIZE_CACHE:
3017 cmdLen = 10;
3018 dir = MPI_SCSIIO_CONTROL_READ;
3019 CDB[0] = cmd;
3020// CDB[1] = 0x02; /* set immediate bit */
3021 cmdTimeout = 10;
3022 break;
3023
3024 default:
3025 /* Error Case */
3026 return -EFAULT;
3027 }
3028
3029 /* Get and Populate a free Frame
3030 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003031 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3033 hd->ioc->name));
3034 return -EBUSY;
3035 }
3036
3037 pScsiReq = (SCSIIORequest_t *) mf;
3038
3039 /* Get the request index */
3040 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3041 ADD_INDEX_LOG(my_idx); /* for debug */
3042
3043 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3044 pScsiReq->TargetID = io->physDiskNum;
3045 pScsiReq->Bus = 0;
3046 pScsiReq->ChainOffset = 0;
3047 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3048 } else {
3049 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003050 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pScsiReq->ChainOffset = 0;
3052 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3053 }
3054
3055 pScsiReq->CDBLength = cmdLen;
3056 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3057
3058 pScsiReq->Reserved = 0;
3059
3060 pScsiReq->MsgFlags = mpt_msg_flags();
3061 /* MsgContext set in mpt_get_msg_fram call */
3062
Eric Moore793955f2007-01-29 09:42:20 -07003063 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
3065 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3066 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3067 else
3068 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3069
3070 if (cmd == REQUEST_SENSE) {
3071 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3072 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3073 hd->ioc->name, cmd));
3074 }
3075
3076 for (ii=0; ii < 16; ii++)
3077 pScsiReq->CDB[ii] = CDB[ii];
3078
3079 pScsiReq->DataLength = cpu_to_le32(io->size);
3080 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3081 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3082
3083 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003084 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
3086 if (dir == MPI_SCSIIO_CONTROL_READ) {
3087 mpt_add_sge((char *) &pScsiReq->SGL,
3088 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3089 io->data_dma);
3090 } else {
3091 mpt_add_sge((char *) &pScsiReq->SGL,
3092 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3093 io->data_dma);
3094 }
3095
3096 /* The ISR will free the request frame, but we need
3097 * the information to initialize the target. Duplicate.
3098 */
3099 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3100
3101 /* Issue this command after:
3102 * finish init
3103 * add timer
3104 * Wait until the reply has been received
3105 * ScsiScanDvCtx callback function will
3106 * set hd->pLocal;
3107 * set scandv_wait_done and call wake_up
3108 */
3109 hd->pLocal = NULL;
3110 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003111 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
3113 /* Save cmd pointer, for resource free if timeout or
3114 * FW reload occurs
3115 */
3116 hd->cmdPtr = mf;
3117
3118 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003119 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3120 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
3122 if (hd->pLocal) {
3123 rc = hd->pLocal->completion;
3124 hd->pLocal->skip = 0;
3125
3126 /* Always set fatal error codes in some cases.
3127 */
3128 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3129 rc = -ENXIO;
3130 else if (rc == MPT_SCANDV_SOME_ERROR)
3131 rc = -rc;
3132 } else {
3133 rc = -EFAULT;
3134 /* This should never happen. */
3135 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3136 hd->ioc->name));
3137 }
3138
3139 return rc;
3140}
3141
3142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3143/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003144 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3145 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003146 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003147 *
3148 * Uses the ISR, but with special processing.
3149 * MUST be single-threaded.
3150 *
3151 */
3152static void
3153mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3154{
3155 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
3157 /* Following parameters will not change
3158 * in this routine.
3159 */
3160 iocmd.cmd = SYNCHRONIZE_CACHE;
3161 iocmd.flags = 0;
3162 iocmd.physDiskNum = -1;
3163 iocmd.data = NULL;
3164 iocmd.data_dma = -1;
3165 iocmd.size = 0;
3166 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003167 iocmd.channel = vdevice->vtarget->channel;
3168 iocmd.id = vdevice->vtarget->id;
3169 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
James Bottomleyc92f2222006-03-01 09:02:49 -06003171 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003172 (vdevice->configured_lun))
3173 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174}
3175
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003176EXPORT_SYMBOL(mptscsih_remove);
3177EXPORT_SYMBOL(mptscsih_shutdown);
3178#ifdef CONFIG_PM
3179EXPORT_SYMBOL(mptscsih_suspend);
3180EXPORT_SYMBOL(mptscsih_resume);
3181#endif
3182EXPORT_SYMBOL(mptscsih_proc_info);
3183EXPORT_SYMBOL(mptscsih_info);
3184EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003185EXPORT_SYMBOL(mptscsih_slave_destroy);
3186EXPORT_SYMBOL(mptscsih_slave_configure);
3187EXPORT_SYMBOL(mptscsih_abort);
3188EXPORT_SYMBOL(mptscsih_dev_reset);
3189EXPORT_SYMBOL(mptscsih_bus_reset);
3190EXPORT_SYMBOL(mptscsih_host_reset);
3191EXPORT_SYMBOL(mptscsih_bios_param);
3192EXPORT_SYMBOL(mptscsih_io_done);
3193EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3194EXPORT_SYMBOL(mptscsih_scandv_complete);
3195EXPORT_SYMBOL(mptscsih_event_process);
3196EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003197EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003198EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003199EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/