blob: 537fcc221c9d4d88b9a57859f7e3a026fb091b0b [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{
Hormsb364fd52007-03-19 15:06:44 +09001191 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192}
1193
1194#endif
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1197/**
1198 * mptscsih_info - Return information about MPT adapter
1199 * @SChost: Pointer to Scsi_Host structure
1200 *
1201 * (linux scsi_host_template.info routine)
1202 *
1203 * Returns pointer to buffer where information was written.
1204 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001205const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206mptscsih_info(struct Scsi_Host *SChost)
1207{
1208 MPT_SCSI_HOST *h;
1209 int size = 0;
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001214 if (h->info_kbuf == NULL)
1215 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1216 return h->info_kbuf;
1217 h->info_kbuf[0] = '\0';
1218
1219 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1220 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
1222
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001223 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
1226struct info_str {
1227 char *buffer;
1228 int length;
1229 int offset;
1230 int pos;
1231};
1232
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001233static void
1234mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235{
1236 if (info->pos + len > info->length)
1237 len = info->length - info->pos;
1238
1239 if (info->pos + len < info->offset) {
1240 info->pos += len;
1241 return;
1242 }
1243
1244 if (info->pos < info->offset) {
1245 data += (info->offset - info->pos);
1246 len -= (info->offset - info->pos);
1247 }
1248
1249 if (len > 0) {
1250 memcpy(info->buffer + info->pos, data, len);
1251 info->pos += len;
1252 }
1253}
1254
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001255static int
1256mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
1258 va_list args;
1259 char buf[81];
1260 int len;
1261
1262 va_start(args, fmt);
1263 len = vsprintf(buf, fmt, args);
1264 va_end(args);
1265
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001266 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 return len;
1268}
1269
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001270static int
1271mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272{
1273 struct info_str info;
1274
1275 info.buffer = pbuf;
1276 info.length = len;
1277 info.offset = offset;
1278 info.pos = 0;
1279
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001280 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1281 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1282 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1283 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1286}
1287
1288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1289/**
1290 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001291 * @host: scsi host struct
1292 * @buffer: if write, user data; if read, buffer for user
1293 * @start: returns the buffer address
1294 * @offset: if write, 0; if read, the current offset into the buffer from
1295 * the previous read.
1296 * @length: if write, return length;
1297 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 *
1299 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001301int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1303 int length, int func)
1304{
1305 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1306 MPT_ADAPTER *ioc = hd->ioc;
1307 int size = 0;
1308
1309 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001310 /*
1311 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 */
1313 } else {
1314 if (start)
1315 *start = buffer;
1316
1317 size = mptscsih_host_info(ioc, buffer, offset, length);
1318 }
1319
1320 return size;
1321}
1322
1323/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1324#define ADD_INDEX_LOG(req_ent) do { } while(0)
1325
1326/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1327/**
1328 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1329 * @SCpnt: Pointer to scsi_cmnd structure
1330 * @done: Pointer SCSI mid-layer IO completion function
1331 *
1332 * (linux scsi_host_template.queuecommand routine)
1333 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1334 * from a linux scsi_cmnd request and send it to the IOC.
1335 *
1336 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1337 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001338int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1340{
1341 MPT_SCSI_HOST *hd;
1342 MPT_FRAME_HDR *mf;
1343 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001344 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 int lun;
1346 u32 datalen;
1347 u32 scsictl;
1348 u32 scsidir;
1349 u32 cmd_len;
1350 int my_idx;
1351 int ii;
1352
1353 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 lun = SCpnt->device->lun;
1355 SCpnt->scsi_done = done;
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1358 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1359
1360 if (hd->resetPending) {
1361 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1362 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1363 return SCSI_MLQUEUE_HOST_BUSY;
1364 }
1365
1366 /*
1367 * Put together a MPT SCSI request...
1368 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001369 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1371 hd->ioc->name));
1372 return SCSI_MLQUEUE_HOST_BUSY;
1373 }
1374
1375 pScsiReq = (SCSIIORequest_t *) mf;
1376
1377 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1378
1379 ADD_INDEX_LOG(my_idx);
1380
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001381 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 * Seems we may receive a buffer (datalen>0) even when there
1383 * will be no data transfer! GRRRRR...
1384 */
1385 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1386 datalen = SCpnt->request_bufflen;
1387 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1388 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1389 datalen = SCpnt->request_bufflen;
1390 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1391 } else {
1392 datalen = 0;
1393 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1394 }
1395
1396 /* Default to untagged. Once a target structure has been allocated,
1397 * use the Inquiry data to determine if device supports tagged.
1398 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001399 if (vdev
1400 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 && (SCpnt->device->tagged_supported)) {
1402 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1403 } else {
1404 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1405 }
1406
1407 /* Use the above information to set up the message frame
1408 */
Eric Moore793955f2007-01-29 09:42:20 -07001409 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1410 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001412 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1413 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1414 else
1415 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 pScsiReq->CDBLength = SCpnt->cmd_len;
1417 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1418 pScsiReq->Reserved = 0;
1419 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001420 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 pScsiReq->Control = cpu_to_le32(scsictl);
1422
1423 /*
1424 * Write SCSI CDB into the message
1425 */
1426 cmd_len = SCpnt->cmd_len;
1427 for (ii=0; ii < cmd_len; ii++)
1428 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1429
1430 for (ii=cmd_len; ii < 16; ii++)
1431 pScsiReq->CDB[ii] = 0;
1432
1433 /* DataLength */
1434 pScsiReq->DataLength = cpu_to_le32(datalen);
1435
1436 /* SenseBuffer low address */
1437 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1438 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1439
1440 /* Now add the SG list
1441 * Always have a SGE even if null length.
1442 */
1443 if (datalen == 0) {
1444 /* Add a NULL SGE */
1445 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1446 (dma_addr_t) -1);
1447 } else {
1448 /* Add a 32 or 64 bit SGE */
1449 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1450 goto fail;
1451 }
1452
Eric Moore3dc0b032006-07-11 17:32:33 -06001453 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001456 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1458 hd->ioc->name, SCpnt, mf, my_idx));
1459 DBG_DUMP_REQUEST_FRAME(mf)
1460 return 0;
1461
1462 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001463 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1465 mpt_free_msg_frame(hd->ioc, mf);
1466 return SCSI_MLQUEUE_HOST_BUSY;
1467}
1468
1469/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1470/*
1471 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1472 * with a SCSI IO request
1473 * @hd: Pointer to the MPT_SCSI_HOST instance
1474 * @req_idx: Index of the SCSI IO request frame.
1475 *
1476 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1477 * No return.
1478 */
1479static void
1480mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1481{
1482 MPT_FRAME_HDR *chain;
1483 unsigned long flags;
1484 int chain_idx;
1485 int next;
1486
1487 /* Get the first chain index and reset
1488 * tracker state.
1489 */
1490 chain_idx = ioc->ReqToChain[req_idx];
1491 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1492
1493 while (chain_idx != MPT_HOST_NO_CHAIN) {
1494
1495 /* Save the next chain buffer index */
1496 next = ioc->ChainToChain[chain_idx];
1497
1498 /* Free this chain buffer and reset
1499 * tracker
1500 */
1501 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1502
1503 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1504 + (chain_idx * ioc->req_sz));
1505
1506 spin_lock_irqsave(&ioc->FreeQlock, flags);
1507 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1508 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1509
1510 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1511 ioc->name, chain_idx));
1512
1513 /* handle next */
1514 chain_idx = next;
1515 }
1516 return;
1517}
1518
1519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1520/*
1521 * Reset Handling
1522 */
1523
1524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001525/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001527 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001529 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001530 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 * @lun: Logical Unit for reset (if appropriate)
1532 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001533 * @timeout: timeout for task management control
1534 *
1535 * Fall through to mpt_HardResetHandler if: not operational, too many
1536 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 *
1538 * Remark: Currently invoked from a non-interrupt thread (_bh).
1539 *
1540 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1541 * will be active.
1542 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001543 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001544 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001545int
Eric Moore793955f2007-01-29 09:42:20 -07001546mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
1548 MPT_ADAPTER *ioc;
1549 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 u32 ioc_raw_state;
1551 unsigned long flags;
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1555
1556 // SJR - CHECKME - Can we avoid this here?
1557 // (mpt_HardResetHandler has this check...)
1558 spin_lock_irqsave(&ioc->diagLock, flags);
1559 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1560 spin_unlock_irqrestore(&ioc->diagLock, flags);
1561 return FAILED;
1562 }
1563 spin_unlock_irqrestore(&ioc->diagLock, flags);
1564
1565 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001566 * If we time out and not bus reset, then we return a FAILED status
1567 * to the caller.
1568 * The call to mptscsih_tm_pending_wait() will set the pending flag
1569 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 * successful. Otherwise, reload the FW.
1571 */
1572 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1573 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001574 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 "Timed out waiting for last TM (%d) to complete! \n",
1576 hd->ioc->name, hd->tmPending));
1577 return FAILED;
1578 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001579 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1580 "reset: Timed out waiting for last TM (%d) "
1581 "to complete! \n", hd->ioc->name,
1582 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return FAILED;
1584 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001585 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 "Timed out waiting for last TM (%d) to complete! \n",
1587 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001588 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 }
1590 } else {
1591 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1592 hd->tmPending |= (1 << type);
1593 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1594 }
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1597
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1599 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001600 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1601 ioc->name, type, ioc_raw_state);
1602 printk(KERN_WARNING " Issuing HardReset!!\n");
1603 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1604 printk((KERN_WARNING "TMHandler: HardReset "
1605 "FAILED!!\n"));
1606 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
1608
Eric Moorecd2c6192007-01-29 09:47:47 -07001609 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1610 printk(MYIOC_s_WARN_FMT
1611 "TM Handler for type=%x: ioc_state: "
1612 "DOORBELL_ACTIVE (0x%x)!\n",
1613 ioc->name, type, ioc_raw_state);
1614 return FAILED;
1615 }
1616
1617 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001619 if (hd->hard_resets < -1)
1620 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Eric Moorecd2c6192007-01-29 09:47:47 -07001622 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1623 ctx2abort, timeout);
1624 if (rc)
1625 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1626 hd->ioc->name);
1627 else
1628 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1629 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1632
1633 return rc;
1634}
1635
1636
1637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001638/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1640 * @hd: Pointer to MPT_SCSI_HOST structure
1641 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001642 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001643 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 * @lun: Logical Unit for reset (if appropriate)
1645 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001646 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 *
1648 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1649 * or a non-interrupt thread. In the former, must not call schedule().
1650 *
1651 * Not all fields are meaningfull for all task types.
1652 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001653 * Returns 0 for SUCCESS, or FAILED.
1654 *
1655 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656static int
Eric Moore793955f2007-01-29 09:42:20 -07001657mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658{
1659 MPT_FRAME_HDR *mf;
1660 SCSITaskMgmt_t *pScsiTm;
1661 int ii;
1662 int retval;
1663
1664 /* Return Fail to calling function if no message frames available.
1665 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001666 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1668 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001669 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 }
1671 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1672 hd->ioc->name, mf));
1673
1674 /* Format the Request
1675 */
1676 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001677 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 pScsiTm->Bus = channel;
1679 pScsiTm->ChainOffset = 0;
1680 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1681
1682 pScsiTm->Reserved = 0;
1683 pScsiTm->TaskType = type;
1684 pScsiTm->Reserved1 = 0;
1685 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1686 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1687
Eric Moore793955f2007-01-29 09:42:20 -07001688 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 for (ii=0; ii < 7; ii++)
1691 pScsiTm->Reserved2[ii] = 0;
1692
1693 pScsiTm->TaskMsgContext = ctx2abort;
1694
Eric Moorecd2c6192007-01-29 09:47:47 -07001695 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1696 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
1698 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1699
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001700 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001701 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1702 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1703 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1704 hd->ioc, mf, retval));
1705 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 }
1707
1708 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001709 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1711 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1713 hd->ioc->name));
1714 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001715 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1716 hd->ioc->name, retval));
1717 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 }
1719
Eric Moorecd2c6192007-01-29 09:47:47 -07001720 /*
1721 * Handle success case, see if theres a non-zero ioc_status.
1722 */
1723 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1724 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1725 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1726 retval = 0;
1727 else
1728 retval = FAILED;
1729
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001731
1732 fail_out:
1733
1734 /*
1735 * Free task managment mf, and corresponding tm flags
1736 */
1737 mpt_free_msg_frame(hd->ioc, mf);
1738 hd->tmPending = 0;
1739 hd->tmState = TM_STATE_NONE;
1740 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741}
1742
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001743static int
1744mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1745{
1746 switch (ioc->bus_type) {
1747 case FC:
1748 return 40;
1749 case SAS:
1750 return 10;
1751 case SPI:
1752 default:
1753 return 2;
1754 }
1755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1758/**
1759 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1760 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1761 *
1762 * (linux scsi_host_template.eh_abort_handler routine)
1763 *
1764 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001765 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001766int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767mptscsih_abort(struct scsi_cmnd * SCpnt)
1768{
1769 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 MPT_FRAME_HDR *mf;
1771 u32 ctx2abort;
1772 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001773 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001774 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001775 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 /* If we can't locate our host adapter structure, return FAILED status.
1778 */
1779 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1780 SCpnt->result = DID_RESET << 16;
1781 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001782 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 "Can't locate host! (sc=%p)\n",
1784 SCpnt));
1785 return FAILED;
1786 }
1787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 /* Find this command
1789 */
1790 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001791 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 * Do OS callback.
1793 */
1794 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001795 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 "Command not in the active list! (sc=%p)\n",
1797 hd->ioc->name, SCpnt));
1798 return SUCCESS;
1799 }
1800
Eric Moorecd2c6192007-01-29 09:47:47 -07001801 if (hd->resetPending)
Moore, Eric65207fe2006-04-21 16:14:35 -06001802 return FAILED;
Moore, Eric65207fe2006-04-21 16:14:35 -06001803
1804 if (hd->timeouts < -1)
1805 hd->timeouts++;
1806
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001807 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1808 hd->ioc->name, SCpnt);
1809 scsi_print_command(SCpnt);
1810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1812 * (the IO to be ABORT'd)
1813 *
1814 * NOTE: Since we do not byteswap MsgContext, we do not
1815 * swap it here either. It is an opaque cookie to
1816 * the controller, so it does not matter. -DaveM
1817 */
1818 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1819 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1820
1821 hd->abortSCpnt = SCpnt;
1822
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001823 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001824 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore793955f2007-01-29 09:42:20 -07001825 vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001826 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Eric Moore3dc0b032006-07-11 17:32:33 -06001828 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001829 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001830 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001831
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001832 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1833 hd->ioc->name,
1834 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001836 if (retval == 0)
1837 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001838 else
1839 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840}
1841
1842/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1843/**
1844 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1845 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1846 *
1847 * (linux scsi_host_template.eh_dev_reset_handler routine)
1848 *
1849 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001850 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001851int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1853{
1854 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001855 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001856 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
1858 /* If we can't locate our host adapter structure, return FAILED status.
1859 */
1860 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001861 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 "Can't locate host! (sc=%p)\n",
1863 SCpnt));
1864 return FAILED;
1865 }
1866
1867 if (hd->resetPending)
1868 return FAILED;
1869
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001870 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001872 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001874 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001875 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -07001876 vdev->vtarget->channel, vdev->vtarget->id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001877 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001878
1879 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1880 hd->ioc->name,
1881 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1882
1883 if (retval == 0)
1884 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001885 else
1886 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887}
1888
Eric Moorecd2c6192007-01-29 09:47:47 -07001889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1891/**
1892 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1893 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1894 *
1895 * (linux scsi_host_template.eh_bus_reset_handler routine)
1896 *
1897 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001898 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001899int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1901{
1902 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001903 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001904 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906 /* If we can't locate our host adapter structure, return FAILED status.
1907 */
1908 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001909 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 "Can't locate host! (sc=%p)\n",
1911 SCpnt ) );
1912 return FAILED;
1913 }
1914
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001915 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001917 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919 if (hd->timeouts < -1)
1920 hd->timeouts++;
1921
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001922 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001923 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore793955f2007-01-29 09:42:20 -07001924 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001926 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1927 hd->ioc->name,
1928 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1929
1930 if (retval == 0)
1931 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001932 else
1933 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934}
1935
1936/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1937/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001938 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1940 *
1941 * (linux scsi_host_template.eh_host_reset_handler routine)
1942 *
1943 * Returns SUCCESS or FAILED.
1944 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001945int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1947{
1948 MPT_SCSI_HOST * hd;
1949 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
1951 /* If we can't locate the host to reset, then we failed. */
1952 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001953 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 "Can't locate host! (sc=%p)\n",
1955 SCpnt ) );
1956 return FAILED;
1957 }
1958
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001959 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 hd->ioc->name, SCpnt);
1961
1962 /* If our attempts to reset the host failed, then return a failed
1963 * status. The host will be taken off line by the SCSI mid-layer.
1964 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1966 status = FAILED;
1967 } else {
1968 /* Make sure TM pending is cleared and TM state is set to
1969 * NONE.
1970 */
1971 hd->tmPending = 0;
1972 hd->tmState = TM_STATE_NONE;
1973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001975 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 "Status = %s\n",
1977 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1978
1979 return status;
1980}
1981
1982/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1983/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001984 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 * @hd: Pointer to MPT host structure.
1986 *
1987 * Returns {SUCCESS,FAILED}.
1988 */
1989static int
1990mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1991{
1992 unsigned long flags;
1993 int loop_count = 4 * 10; /* Wait 10 seconds */
1994 int status = FAILED;
1995
1996 do {
1997 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1998 if (hd->tmState == TM_STATE_NONE) {
1999 hd->tmState = TM_STATE_IN_PROGRESS;
2000 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002002 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 break;
2004 }
2005 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2006 msleep(250);
2007 } while (--loop_count);
2008
2009 return status;
2010}
2011
2012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2013/**
2014 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2015 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002016 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 *
2018 * Returns {SUCCESS,FAILED}.
2019 */
2020static int
2021mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2022{
2023 unsigned long flags;
2024 int loop_count = 4 * timeout;
2025 int status = FAILED;
2026
2027 do {
2028 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2029 if(hd->tmPending == 0) {
2030 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002031 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 break;
2033 }
2034 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002035 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 } while (--loop_count);
2037
2038 return status;
2039}
2040
2041/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002042static void
2043mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2044{
2045 char *desc;
2046
2047 switch (response_code) {
2048 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2049 desc = "The task completed.";
2050 break;
2051 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2052 desc = "The IOC received an invalid frame status.";
2053 break;
2054 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2055 desc = "The task type is not supported.";
2056 break;
2057 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2058 desc = "The requested task failed.";
2059 break;
2060 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2061 desc = "The task completed successfully.";
2062 break;
2063 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2064 desc = "The LUN request is invalid.";
2065 break;
2066 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2067 desc = "The task is in the IOC queue and has not been sent to target.";
2068 break;
2069 default:
2070 desc = "unknown";
2071 break;
2072 }
2073 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2074 ioc->name, response_code, desc);
2075}
2076
2077/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078/**
2079 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2080 * @ioc: Pointer to MPT_ADAPTER structure
2081 * @mf: Pointer to SCSI task mgmt request frame
2082 * @mr: Pointer to SCSI task mgmt reply frame
2083 *
2084 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2085 * of any SCSI task management request.
2086 * This routine is registered with the MPT (base) driver at driver
2087 * load/init time via the mpt_register() API call.
2088 *
2089 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002090 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002091int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2093{
2094 SCSITaskMgmtReply_t *pScsiTmReply;
2095 SCSITaskMgmt_t *pScsiTmReq;
2096 MPT_SCSI_HOST *hd;
2097 unsigned long flags;
2098 u16 iocstatus;
2099 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002100 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002103 ioc->name, mf, mr));
2104 if (!ioc->sh) {
2105 dtmprintk((MYIOC_s_WARN_FMT
2106 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 return 1;
2108 }
2109
2110 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002111 dtmprintk((MYIOC_s_WARN_FMT
2112 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 }
2115
Eric Moorecd2c6192007-01-29 09:47:47 -07002116 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2117 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2118 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2119 tmType = pScsiTmReq->TaskType;
2120 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2121 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2122
2123 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2124 pScsiTmReply->ResponseCode)
2125 mptscsih_taskmgmt_response_code(ioc,
2126 pScsiTmReply->ResponseCode);
2127 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2128
2129#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2130 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2131 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2132 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2133 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2134 le16_to_cpu(pScsiTmReply->IOCStatus),
2135 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2136 le32_to_cpu(pScsiTmReply->TerminationCount));
2137#endif
2138 if (!iocstatus) {
2139 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2140 hd->abortSCpnt = NULL;
2141 goto out;
2142 }
2143
2144 /* Error? (anything non-zero?) */
2145
2146 /* clear flags and continue.
2147 */
2148 switch (tmType) {
2149
2150 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2151 if (termination_count == 1)
2152 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2153 hd->abortSCpnt = NULL;
2154 break;
2155
2156 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2157
2158 /* If an internal command is present
2159 * or the TM failed - reload the FW.
2160 * FC FW may respond FAILED to an ABORT
2161 */
2162 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2163 hd->cmdPtr)
2164 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2165 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2166 break;
2167
2168 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2169 default:
2170 break;
2171 }
2172
2173 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 spin_lock_irqsave(&ioc->FreeQlock, flags);
2175 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002177 hd->tm_iocstatus = iocstatus;
2178 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180 return 1;
2181}
2182
2183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2184/*
2185 * This is anyones guess quite frankly.
2186 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002187int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2189 sector_t capacity, int geom[])
2190{
2191 int heads;
2192 int sectors;
2193 sector_t cylinders;
2194 ulong dummy;
2195
2196 heads = 64;
2197 sectors = 32;
2198
2199 dummy = heads * sectors;
2200 cylinders = capacity;
2201 sector_div(cylinders,dummy);
2202
2203 /*
2204 * Handle extended translation size for logical drives
2205 * > 1Gb
2206 */
2207 if ((ulong)capacity >= 0x200000) {
2208 heads = 255;
2209 sectors = 63;
2210 dummy = heads * sectors;
2211 cylinders = capacity;
2212 sector_div(cylinders,dummy);
2213 }
2214
2215 /* return result */
2216 geom[0] = heads;
2217 geom[1] = sectors;
2218 geom[2] = cylinders;
2219
2220 dprintk((KERN_NOTICE
2221 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002222 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 return 0;
2225}
2226
Moore, Ericf44e5462006-03-14 09:14:21 -07002227/* Search IOC page 3 to determine if this is hidden physical disk
2228 *
2229 */
2230int
Eric Moore793955f2007-01-29 09:42:20 -07002231mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002232{
Eric Mooreb506ade2007-01-29 09:45:37 -07002233 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002234 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002235 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002236
Eric Moore793955f2007-01-29 09:42:20 -07002237 if (!ioc->raid_data.pIocPg3)
2238 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002239 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002240 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2241 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2242 rc = 1;
2243 goto out;
2244 }
2245 }
2246
Eric Mooreb506ade2007-01-29 09:45:37 -07002247 /*
2248 * Check inactive list for matching phys disks
2249 */
2250 if (list_empty(&ioc->raid_data.inactive_list))
2251 goto out;
2252
2253 down(&ioc->raid_data.inactive_list_mutex);
2254 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2255 list) {
2256 if ((component_info->d.PhysDiskID == id) &&
2257 (component_info->d.PhysDiskBus == channel))
2258 rc = 1;
2259 }
2260 up(&ioc->raid_data.inactive_list_mutex);
2261
Eric Moore793955f2007-01-29 09:42:20 -07002262 out:
2263 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002264}
2265EXPORT_SYMBOL(mptscsih_is_phys_disk);
2266
Eric Moore793955f2007-01-29 09:42:20 -07002267u8
2268mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002269{
Eric Mooreb506ade2007-01-29 09:45:37 -07002270 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002271 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002272 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002273
Eric Moore793955f2007-01-29 09:42:20 -07002274 if (!ioc->raid_data.pIocPg3)
2275 goto out;
2276 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2277 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2278 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2279 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2280 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002281 }
2282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
Eric Mooreb506ade2007-01-29 09:45:37 -07002284 /*
2285 * Check inactive list for matching phys disks
2286 */
2287 if (list_empty(&ioc->raid_data.inactive_list))
2288 goto out;
2289
2290 down(&ioc->raid_data.inactive_list_mutex);
2291 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2292 list) {
2293 if ((component_info->d.PhysDiskID == id) &&
2294 (component_info->d.PhysDiskBus == channel))
2295 rc = component_info->d.PhysDiskNum;
2296 }
2297 up(&ioc->raid_data.inactive_list_mutex);
2298
Eric Moore793955f2007-01-29 09:42:20 -07002299 out:
2300 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002301}
Eric Moore793955f2007-01-29 09:42:20 -07002302EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002303
2304/*
2305 * OS entry point to allow for host driver to free allocated memory
2306 * Called if no device present or device being unloaded
2307 */
2308void
2309mptscsih_slave_destroy(struct scsi_device *sdev)
2310{
2311 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002313 VirtTarget *vtarget;
2314 VirtDevice *vdevice;
2315 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002317 starget = scsi_target(sdev);
2318 vtarget = starget->hostdata;
2319 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002321 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002323 mptscsih_synchronize_cache(hd, vdevice);
2324 kfree(vdevice);
2325 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326}
2327
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002328/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2329/*
2330 * mptscsih_change_queue_depth - This function will set a devices queue depth
2331 * @sdev: per scsi_device pointer
2332 * @qdepth: requested queue depth
2333 *
2334 * Adding support for new 'change_queue_depth' api.
2335*/
2336int
2337mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002339 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2340 VirtTarget *vtarget;
2341 struct scsi_target *starget;
2342 int max_depth;
2343 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002345 starget = scsi_target(sdev);
2346 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002347
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002348 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002349 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002351 else if (sdev->type == TYPE_DISK &&
2352 vtarget->minSyncFactor <= MPT_ULTRA160)
2353 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2354 else
2355 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 } else
2357 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2358
2359 if (qdepth > max_depth)
2360 qdepth = max_depth;
2361 if (qdepth == 1)
2362 tagged = 0;
2363 else
2364 tagged = MSG_SIMPLE_TAG;
2365
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002366 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2367 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368}
2369
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370/*
2371 * OS entry point to adjust the queue_depths on a per-device basis.
2372 * Called once per device the bus scan. Use it to force the queue_depth
2373 * member to 1 if a device does not support Q tags.
2374 * Return non-zero if fails.
2375 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002376int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002377mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379 struct Scsi_Host *sh = sdev->host;
2380 VirtTarget *vtarget;
2381 VirtDevice *vdevice;
2382 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2384
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002385 starget = scsi_target(sdev);
2386 vtarget = starget->hostdata;
2387 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
2389 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002390 "device @ %p, channel=%d, id=%d, lun=%d\n",
2391 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 if (hd->ioc->bus_type == SPI)
2393 dsprintk((MYIOC_s_INFO_FMT
2394 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2395 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2396 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002398 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002400 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 goto slave_configure_exit;
2402 }
2403
Eric Moore793955f2007-01-29 09:42:20 -07002404 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002405 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 dsprintk((MYIOC_s_INFO_FMT
2408 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002409 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 if (hd->ioc->bus_type == SPI)
2412 dsprintk((MYIOC_s_INFO_FMT
2413 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2414 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2415 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
2417slave_configure_exit:
2418
2419 dsprintk((MYIOC_s_INFO_FMT
2420 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002421 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2422 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424 return 0;
2425}
2426
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2428/*
2429 * Private routines...
2430 */
2431
2432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2433/* Utility function to copy sense data from the scsi_cmnd buffer
2434 * to the FC and SCSI target structures.
2435 *
2436 */
2437static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002438mptscsih_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 -07002439{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002440 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 SCSIIORequest_t *pReq;
2442 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 /* Get target structure
2445 */
2446 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002447 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
2449 if (sense_count) {
2450 u8 *sense_data;
2451 int req_index;
2452
2453 /* Copy the sense received into the scsi command block. */
2454 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2455 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2456 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2457
2458 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2459 */
2460 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002461 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 int idx;
2463 MPT_ADAPTER *ioc = hd->ioc;
2464
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002465 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2467 ioc->events[idx].eventContext = ioc->eventContext;
2468
2469 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2470 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002471 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2474
2475 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002476 if (hd->ioc->pcidev->vendor ==
2477 PCI_VENDOR_ID_IBM) {
2478 mptscsih_issue_sep_command(hd->ioc,
2479 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2480 vdev->vtarget->tflags |=
2481 MPT_TARGET_FLAGS_LED_ON;
2482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 }
2484 }
2485 } else {
2486 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2487 hd->ioc->name));
2488 }
2489}
2490
Eric Moore3dc0b032006-07-11 17:32:33 -06002491static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2493{
2494 MPT_SCSI_HOST *hd;
2495 int i;
2496
2497 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2498
2499 for (i = 0; i < hd->ioc->req_depth; i++) {
2500 if (hd->ScsiLookup[i] == sc) {
2501 return i;
2502 }
2503 }
2504
2505 return -1;
2506}
2507
2508/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002509int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2511{
2512 MPT_SCSI_HOST *hd;
2513 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002514 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 dtmprintk((KERN_WARNING MYNAM
2517 ": IOC %s_reset routed to SCSI host driver!\n",
2518 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2519 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2520
2521 /* If a FW reload request arrives after base installed but
2522 * before all scsi hosts have been attached, then an alt_ioc
2523 * may have a NULL sh pointer.
2524 */
2525 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2526 return 0;
2527 else
2528 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2529
2530 if (reset_phase == MPT_IOC_SETUP_RESET) {
2531 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2532
2533 /* Clean Up:
2534 * 1. Set Hard Reset Pending Flag
2535 * All new commands go to doneQ
2536 */
2537 hd->resetPending = 1;
2538
2539 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2540 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2541
2542 /* 2. Flush running commands
2543 * Clean ScsiLookup (and associated memory)
2544 * AND clean mytaskQ
2545 */
2546
2547 /* 2b. Reply to OS all known outstanding I/O commands.
2548 */
2549 mptscsih_flush_running_cmds(hd);
2550
2551 /* 2c. If there was an internal command that
2552 * has not completed, configuration or io request,
2553 * free these resources.
2554 */
2555 if (hd->cmdPtr) {
2556 del_timer(&hd->timer);
2557 mpt_free_msg_frame(ioc, hd->cmdPtr);
2558 }
2559
2560 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2561
2562 } else {
2563 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2564
2565 /* Once a FW reload begins, all new OS commands are
2566 * redirected to the doneQ w/ a reset status.
2567 * Init all control structures.
2568 */
2569
2570 /* ScsiLookup initialization
2571 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002572 for (ii=0; ii < hd->ioc->req_depth; ii++)
2573 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
2575 /* 2. Chain Buffer initialization
2576 */
2577
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002578 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 /* 5. Enable new commands to be posted
2582 */
2583 spin_lock_irqsave(&ioc->FreeQlock, flags);
2584 hd->tmPending = 0;
2585 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2586 hd->resetPending = 0;
2587 hd->tmState = TM_STATE_NONE;
2588
2589 /* 6. If there was an internal command,
2590 * wake this process up.
2591 */
2592 if (hd->cmdPtr) {
2593 /*
2594 * Wake up the original calling thread
2595 */
2596 hd->pLocal = &hd->localReply;
2597 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002598 hd->scandv_wait_done = 1;
2599 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 hd->cmdPtr = NULL;
2601 }
2602
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2604
2605 }
2606
2607 return 1; /* currently means nothing really */
2608}
2609
2610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002611int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2613{
2614 MPT_SCSI_HOST *hd;
2615 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2616
Moore, Eric3a892be2006-03-14 09:14:03 -07002617 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 ioc->name, event));
2619
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002620 if (ioc->sh == NULL ||
2621 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2622 return 1;
2623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 switch (event) {
2625 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2626 /* FIXME! */
2627 break;
2628 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2629 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002630 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002631 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 break;
2633 case MPI_EVENT_LOGOUT: /* 09 */
2634 /* FIXME! */
2635 break;
2636
Michael Reed05e8ec12006-01-13 14:31:54 -06002637 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002638 break;
2639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 /*
2641 * CHECKME! Don't think we need to do
2642 * anything for these, but...
2643 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2645 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2646 /*
2647 * CHECKME! Falling thru...
2648 */
2649 break;
2650
2651 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002652 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 case MPI_EVENT_NONE: /* 00 */
2655 case MPI_EVENT_LOG_DATA: /* 01 */
2656 case MPI_EVENT_STATE_CHANGE: /* 02 */
2657 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2658 default:
2659 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2660 break;
2661 }
2662
2663 return 1; /* currently means nothing really */
2664}
2665
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2667/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 * Bus Scan and Domain Validation functionality ...
2669 */
2670
2671/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2672/*
2673 * mptscsih_scandv_complete - Scan and DV callback routine registered
2674 * to Fustion MPT (base) driver.
2675 *
2676 * @ioc: Pointer to MPT_ADAPTER structure
2677 * @mf: Pointer to original MPT request frame
2678 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2679 *
2680 * This routine is called from mpt.c::mpt_interrupt() at the completion
2681 * of any SCSI IO request.
2682 * This routine is registered with the Fusion MPT (base) driver at driver
2683 * load/init time via the mpt_register() API call.
2684 *
2685 * Returns 1 indicating alloc'd request frame ptr should be freed.
2686 *
2687 * Remark: Sets a completion code and (possibly) saves sense data
2688 * in the IOC member localReply structure.
2689 * Used ONLY for DV and other internal commands.
2690 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002691int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2693{
2694 MPT_SCSI_HOST *hd;
2695 SCSIIORequest_t *pReq;
2696 int completionCode;
2697 u16 req_idx;
2698
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002699 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 if ((mf == NULL) ||
2702 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2703 printk(MYIOC_s_ERR_FMT
2704 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2705 ioc->name, mf?"BAD":"NULL", (void *) mf);
2706 goto wakeup;
2707 }
2708
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 del_timer(&hd->timer);
2710 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2711 hd->ScsiLookup[req_idx] = NULL;
2712 pReq = (SCSIIORequest_t *) mf;
2713
2714 if (mf != hd->cmdPtr) {
2715 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2716 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2717 }
2718 hd->cmdPtr = NULL;
2719
2720 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2721 hd->ioc->name, mf, mr, req_idx));
2722
2723 hd->pLocal = &hd->localReply;
2724 hd->pLocal->scsiStatus = 0;
2725
2726 /* If target struct exists, clear sense valid flag.
2727 */
2728 if (mr == NULL) {
2729 completionCode = MPT_SCANDV_GOOD;
2730 } else {
2731 SCSIIOReply_t *pReply;
2732 u16 status;
2733 u8 scsi_status;
2734
2735 pReply = (SCSIIOReply_t *) mr;
2736
2737 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2738 scsi_status = pReply->SCSIStatus;
2739
2740 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2741 status, pReply->SCSIState, scsi_status,
2742 le32_to_cpu(pReply->IOCLogInfo)));
2743
2744 switch(status) {
2745
2746 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2747 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2748 break;
2749
2750 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2751 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2752 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2753 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2754 completionCode = MPT_SCANDV_DID_RESET;
2755 break;
2756
2757 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2758 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2759 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2760 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2761 ConfigReply_t *pr = (ConfigReply_t *)mr;
2762 completionCode = MPT_SCANDV_GOOD;
2763 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2764 hd->pLocal->header.PageLength = pr->Header.PageLength;
2765 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2766 hd->pLocal->header.PageType = pr->Header.PageType;
2767
2768 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2769 /* If the RAID Volume request is successful,
2770 * return GOOD, else indicate that
2771 * some type of error occurred.
2772 */
2773 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002774 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 completionCode = MPT_SCANDV_GOOD;
2776 else
2777 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002778 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
2780 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2781 u8 *sense_data;
2782 int sz;
2783
2784 /* save sense data in global structure
2785 */
2786 completionCode = MPT_SCANDV_SENSE;
2787 hd->pLocal->scsiStatus = scsi_status;
2788 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2789 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2790
2791 sz = min_t(int, pReq->SenseBufferLength,
2792 SCSI_STD_SENSE_BYTES);
2793 memcpy(hd->pLocal->sense, sense_data, sz);
2794
2795 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2796 sense_data));
2797 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2798 if (pReq->CDB[0] == INQUIRY)
2799 completionCode = MPT_SCANDV_ISSUE_SENSE;
2800 else
2801 completionCode = MPT_SCANDV_DID_RESET;
2802 }
2803 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2804 completionCode = MPT_SCANDV_DID_RESET;
2805 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2806 completionCode = MPT_SCANDV_DID_RESET;
2807 else {
2808 completionCode = MPT_SCANDV_GOOD;
2809 hd->pLocal->scsiStatus = scsi_status;
2810 }
2811 break;
2812
2813 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2814 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2815 completionCode = MPT_SCANDV_DID_RESET;
2816 else
2817 completionCode = MPT_SCANDV_SOME_ERROR;
2818 break;
2819
2820 default:
2821 completionCode = MPT_SCANDV_SOME_ERROR;
2822 break;
2823
2824 } /* switch(status) */
2825
2826 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2827 completionCode));
2828 } /* end of address reply case */
2829
2830 hd->pLocal->completion = completionCode;
2831
2832 /* MF and RF are freed in mpt_interrupt
2833 */
2834wakeup:
2835 /* Free Chain buffers (will never chain) in scan or dv */
2836 //mptscsih_freeChainBuffers(ioc, req_idx);
2837
2838 /*
2839 * Wake up the original calling thread
2840 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002841 hd->scandv_wait_done = 1;
2842 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
2844 return 1;
2845}
2846
2847/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2848/* mptscsih_timer_expired - Call back for timer process.
2849 * Used only for dv functionality.
2850 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2851 *
2852 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002853void
2854mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855{
2856 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2857
2858 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2859
2860 if (hd->cmdPtr) {
2861 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2862
2863 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2864 /* Desire to issue a task management request here.
2865 * TM requests MUST be single threaded.
2866 * If old eh code and no TM current, issue request.
2867 * If new eh code, do nothing. Wait for OS cmd timeout
2868 * for bus reset.
2869 */
2870 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2871 } else {
2872 /* Perform a FW reload */
2873 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2874 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2875 }
2876 }
2877 } else {
2878 /* This should NEVER happen */
2879 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2880 }
2881
2882 /* No more processing.
2883 * TM call will generate an interrupt for SCSI TM Management.
2884 * The FW will reply to all outstanding commands, callback will finish cleanup.
2885 * Hard reset clean-up will free all resources.
2886 */
2887 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2888
2889 return;
2890}
2891
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892
2893/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2894/**
2895 * mptscsih_do_cmd - Do internal command.
2896 * @hd: MPT_SCSI_HOST pointer
2897 * @io: INTERNAL_CMD pointer.
2898 *
2899 * Issue the specified internally generated command and do command
2900 * specific cleanup. For bus scan / DV only.
2901 * NOTES: If command is Inquiry and status is good,
2902 * initialize a target structure, save the data
2903 *
2904 * Remark: Single threaded access only.
2905 *
2906 * Return:
2907 * < 0 if an illegal command or no resources
2908 *
2909 * 0 if good
2910 *
2911 * > 0 if command complete but some type of completion error.
2912 */
2913static int
2914mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2915{
2916 MPT_FRAME_HDR *mf;
2917 SCSIIORequest_t *pScsiReq;
2918 SCSIIORequest_t ReqCopy;
2919 int my_idx, ii, dir;
2920 int rc, cmdTimeout;
2921 int in_isr;
2922 char cmdLen;
2923 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2924 char cmd = io->cmd;
2925
2926 in_isr = in_interrupt();
2927 if (in_isr) {
2928 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2929 hd->ioc->name));
2930 return -EPERM;
2931 }
2932
2933
2934 /* Set command specific information
2935 */
2936 switch (cmd) {
2937 case INQUIRY:
2938 cmdLen = 6;
2939 dir = MPI_SCSIIO_CONTROL_READ;
2940 CDB[0] = cmd;
2941 CDB[4] = io->size;
2942 cmdTimeout = 10;
2943 break;
2944
2945 case TEST_UNIT_READY:
2946 cmdLen = 6;
2947 dir = MPI_SCSIIO_CONTROL_READ;
2948 cmdTimeout = 10;
2949 break;
2950
2951 case START_STOP:
2952 cmdLen = 6;
2953 dir = MPI_SCSIIO_CONTROL_READ;
2954 CDB[0] = cmd;
2955 CDB[4] = 1; /*Spin up the disk */
2956 cmdTimeout = 15;
2957 break;
2958
2959 case REQUEST_SENSE:
2960 cmdLen = 6;
2961 CDB[0] = cmd;
2962 CDB[4] = io->size;
2963 dir = MPI_SCSIIO_CONTROL_READ;
2964 cmdTimeout = 10;
2965 break;
2966
2967 case READ_BUFFER:
2968 cmdLen = 10;
2969 dir = MPI_SCSIIO_CONTROL_READ;
2970 CDB[0] = cmd;
2971 if (io->flags & MPT_ICFLAG_ECHO) {
2972 CDB[1] = 0x0A;
2973 } else {
2974 CDB[1] = 0x02;
2975 }
2976
2977 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2978 CDB[1] |= 0x01;
2979 }
2980 CDB[6] = (io->size >> 16) & 0xFF;
2981 CDB[7] = (io->size >> 8) & 0xFF;
2982 CDB[8] = io->size & 0xFF;
2983 cmdTimeout = 10;
2984 break;
2985
2986 case WRITE_BUFFER:
2987 cmdLen = 10;
2988 dir = MPI_SCSIIO_CONTROL_WRITE;
2989 CDB[0] = cmd;
2990 if (io->flags & MPT_ICFLAG_ECHO) {
2991 CDB[1] = 0x0A;
2992 } else {
2993 CDB[1] = 0x02;
2994 }
2995 CDB[6] = (io->size >> 16) & 0xFF;
2996 CDB[7] = (io->size >> 8) & 0xFF;
2997 CDB[8] = io->size & 0xFF;
2998 cmdTimeout = 10;
2999 break;
3000
3001 case RESERVE:
3002 cmdLen = 6;
3003 dir = MPI_SCSIIO_CONTROL_READ;
3004 CDB[0] = cmd;
3005 cmdTimeout = 10;
3006 break;
3007
3008 case RELEASE:
3009 cmdLen = 6;
3010 dir = MPI_SCSIIO_CONTROL_READ;
3011 CDB[0] = cmd;
3012 cmdTimeout = 10;
3013 break;
3014
3015 case SYNCHRONIZE_CACHE:
3016 cmdLen = 10;
3017 dir = MPI_SCSIIO_CONTROL_READ;
3018 CDB[0] = cmd;
3019// CDB[1] = 0x02; /* set immediate bit */
3020 cmdTimeout = 10;
3021 break;
3022
3023 default:
3024 /* Error Case */
3025 return -EFAULT;
3026 }
3027
3028 /* Get and Populate a free Frame
3029 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003030 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3032 hd->ioc->name));
3033 return -EBUSY;
3034 }
3035
3036 pScsiReq = (SCSIIORequest_t *) mf;
3037
3038 /* Get the request index */
3039 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3040 ADD_INDEX_LOG(my_idx); /* for debug */
3041
3042 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3043 pScsiReq->TargetID = io->physDiskNum;
3044 pScsiReq->Bus = 0;
3045 pScsiReq->ChainOffset = 0;
3046 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3047 } else {
3048 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003049 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 pScsiReq->ChainOffset = 0;
3051 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3052 }
3053
3054 pScsiReq->CDBLength = cmdLen;
3055 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3056
3057 pScsiReq->Reserved = 0;
3058
3059 pScsiReq->MsgFlags = mpt_msg_flags();
3060 /* MsgContext set in mpt_get_msg_fram call */
3061
Eric Moore793955f2007-01-29 09:42:20 -07003062 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
3064 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3065 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3066 else
3067 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3068
3069 if (cmd == REQUEST_SENSE) {
3070 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3071 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3072 hd->ioc->name, cmd));
3073 }
3074
3075 for (ii=0; ii < 16; ii++)
3076 pScsiReq->CDB[ii] = CDB[ii];
3077
3078 pScsiReq->DataLength = cpu_to_le32(io->size);
3079 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3080 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3081
3082 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003083 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084
3085 if (dir == MPI_SCSIIO_CONTROL_READ) {
3086 mpt_add_sge((char *) &pScsiReq->SGL,
3087 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3088 io->data_dma);
3089 } else {
3090 mpt_add_sge((char *) &pScsiReq->SGL,
3091 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3092 io->data_dma);
3093 }
3094
3095 /* The ISR will free the request frame, but we need
3096 * the information to initialize the target. Duplicate.
3097 */
3098 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3099
3100 /* Issue this command after:
3101 * finish init
3102 * add timer
3103 * Wait until the reply has been received
3104 * ScsiScanDvCtx callback function will
3105 * set hd->pLocal;
3106 * set scandv_wait_done and call wake_up
3107 */
3108 hd->pLocal = NULL;
3109 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003110 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
3112 /* Save cmd pointer, for resource free if timeout or
3113 * FW reload occurs
3114 */
3115 hd->cmdPtr = mf;
3116
3117 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003118 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3119 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121 if (hd->pLocal) {
3122 rc = hd->pLocal->completion;
3123 hd->pLocal->skip = 0;
3124
3125 /* Always set fatal error codes in some cases.
3126 */
3127 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3128 rc = -ENXIO;
3129 else if (rc == MPT_SCANDV_SOME_ERROR)
3130 rc = -rc;
3131 } else {
3132 rc = -EFAULT;
3133 /* This should never happen. */
3134 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3135 hd->ioc->name));
3136 }
3137
3138 return rc;
3139}
3140
3141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3142/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003143 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3144 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003145 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003146 *
3147 * Uses the ISR, but with special processing.
3148 * MUST be single-threaded.
3149 *
3150 */
3151static void
3152mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3153{
3154 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
3156 /* Following parameters will not change
3157 * in this routine.
3158 */
3159 iocmd.cmd = SYNCHRONIZE_CACHE;
3160 iocmd.flags = 0;
3161 iocmd.physDiskNum = -1;
3162 iocmd.data = NULL;
3163 iocmd.data_dma = -1;
3164 iocmd.size = 0;
3165 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003166 iocmd.channel = vdevice->vtarget->channel;
3167 iocmd.id = vdevice->vtarget->id;
3168 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
James Bottomleyc92f2222006-03-01 09:02:49 -06003170 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003171 (vdevice->configured_lun))
3172 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173}
3174
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003175EXPORT_SYMBOL(mptscsih_remove);
3176EXPORT_SYMBOL(mptscsih_shutdown);
3177#ifdef CONFIG_PM
3178EXPORT_SYMBOL(mptscsih_suspend);
3179EXPORT_SYMBOL(mptscsih_resume);
3180#endif
3181EXPORT_SYMBOL(mptscsih_proc_info);
3182EXPORT_SYMBOL(mptscsih_info);
3183EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003184EXPORT_SYMBOL(mptscsih_slave_destroy);
3185EXPORT_SYMBOL(mptscsih_slave_configure);
3186EXPORT_SYMBOL(mptscsih_abort);
3187EXPORT_SYMBOL(mptscsih_dev_reset);
3188EXPORT_SYMBOL(mptscsih_bus_reset);
3189EXPORT_SYMBOL(mptscsih_host_reset);
3190EXPORT_SYMBOL(mptscsih_bios_param);
3191EXPORT_SYMBOL(mptscsih_io_done);
3192EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3193EXPORT_SYMBOL(mptscsih_scandv_complete);
3194EXPORT_SYMBOL(mptscsih_event_process);
3195EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003196EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003197EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003198EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/