blob: 3bc9446ec42d459259da9c45897779ccad734e40 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * (mailto:mpt_linux_developer@lsil.com)
8 *
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 */
57#include <linux/sched.h>
58#include <linux/workqueue.h>
59
60#include <scsi/scsi.h>
61#include <scsi/scsi_cmnd.h>
62#include <scsi/scsi_device.h>
63#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060065#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060069#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
72#define my_NAME "Fusion MPT SCSI Host driver"
73#define my_VERSION MPT_LINUX_VERSION_COMMON
74#define MYNAM "mptscsih"
75
76MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070079MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070082/*
83 * Other private/forward protos...
84 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040085int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040087int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
90 SCSIIORequest_t *pReq, int req_idx);
91static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040092static 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 -070093static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
94static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -060095static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Eric Moore793955f2007-01-29 09:42:20 -070097static 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 -070098
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040099int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
100int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400102int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700104static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400106void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700107void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400109int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
110int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#endif
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
116/**
117 * mptscsih_add_sge - Place a simple SGE at address pAddr.
118 * @pAddr: virtual address for SGE
119 * @flagslength: SGE flags and data transfer length
120 * @dma_addr: Physical address
121 *
122 * This routine places a MPT request frame back on the MPT adapter's
123 * FreeQ.
124 */
125static inline void
126mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
127{
128 if (sizeof(dma_addr_t) == sizeof(u64)) {
129 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
130 u32 tmp = dma_addr & 0xFFFFFFFF;
131
132 pSge->FlagsLength = cpu_to_le32(flagslength);
133 pSge->Address.Low = cpu_to_le32(tmp);
134 tmp = (u32) ((u64)dma_addr >> 32);
135 pSge->Address.High = cpu_to_le32(tmp);
136
137 } else {
138 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
139 pSge->FlagsLength = cpu_to_le32(flagslength);
140 pSge->Address = cpu_to_le32(dma_addr);
141 }
142} /* mptscsih_add_sge() */
143
144/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
145/**
146 * mptscsih_add_chain - Place a chain SGE at address pAddr.
147 * @pAddr: virtual address for SGE
148 * @next: nextChainOffset value (u32's)
149 * @length: length of next SGL segment
150 * @dma_addr: Physical address
151 *
152 * This routine places a MPT request frame back on the MPT adapter's
153 * FreeQ.
154 */
155static inline void
156mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
157{
158 if (sizeof(dma_addr_t) == sizeof(u64)) {
159 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
160 u32 tmp = dma_addr & 0xFFFFFFFF;
161
162 pChain->Length = cpu_to_le16(length);
163 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
164
165 pChain->NextChainOffset = next;
166
167 pChain->Address.Low = cpu_to_le32(tmp);
168 tmp = (u32) ((u64)dma_addr >> 32);
169 pChain->Address.High = cpu_to_le32(tmp);
170 } else {
171 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
172 pChain->Length = cpu_to_le16(length);
173 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
174 pChain->NextChainOffset = next;
175 pChain->Address = cpu_to_le32(dma_addr);
176 }
177} /* mptscsih_add_chain() */
178
179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
180/*
181 * mptscsih_getFreeChainBuffer - Function to get a free chain
182 * from the MPT_SCSI_HOST FreeChainQ.
183 * @ioc: Pointer to MPT_ADAPTER structure
184 * @req_idx: Index of the SCSI IO request frame. (output)
185 *
186 * return SUCCESS or FAILED
187 */
188static inline int
189mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
190{
191 MPT_FRAME_HDR *chainBuf;
192 unsigned long flags;
193 int rc;
194 int chain_idx;
195
196 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
197 ioc->name));
198 spin_lock_irqsave(&ioc->FreeQlock, flags);
199 if (!list_empty(&ioc->FreeChainQ)) {
200 int offset;
201
202 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
203 u.frame.linkage.list);
204 list_del(&chainBuf->u.frame.linkage.list);
205 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
206 chain_idx = offset / ioc->req_sz;
207 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200208 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
209 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 } else {
211 rc = FAILED;
212 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200213 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 ioc->name));
215 }
216 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
217
218 *retIndex = chain_idx;
219 return rc;
220} /* mptscsih_getFreeChainBuffer() */
221
222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
223/*
224 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
225 * SCSIIORequest_t Message Frame.
226 * @ioc: Pointer to MPT_ADAPTER structure
227 * @SCpnt: Pointer to scsi_cmnd structure
228 * @pReq: Pointer to SCSIIORequest_t structure
229 *
230 * Returns ...
231 */
232static int
233mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
234 SCSIIORequest_t *pReq, int req_idx)
235{
236 char *psge;
237 char *chainSge;
238 struct scatterlist *sg;
239 int frm_sz;
240 int sges_left, sg_done;
241 int chain_idx = MPT_HOST_NO_CHAIN;
242 int sgeOffset;
243 int numSgeSlots, numSgeThisFrame;
244 u32 sgflags, sgdir, thisxfer = 0;
245 int chain_dma_off = 0;
246 int newIndex;
247 int ii;
248 dma_addr_t v2;
249 u32 RequestNB;
250
251 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
252 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
253 sgdir = MPT_TRANSFER_HOST_TO_IOC;
254 } else {
255 sgdir = MPT_TRANSFER_IOC_TO_HOST;
256 }
257
258 psge = (char *) &pReq->SGL;
259 frm_sz = ioc->req_sz;
260
261 /* Map the data portion, if any.
262 * sges_left = 0 if no data transfer.
263 */
264 if ( (sges_left = SCpnt->use_sg) ) {
265 sges_left = pci_map_sg(ioc->pcidev,
266 (struct scatterlist *) SCpnt->request_buffer,
267 SCpnt->use_sg,
268 SCpnt->sc_data_direction);
269 if (sges_left == 0)
270 return FAILED;
271 } else if (SCpnt->request_bufflen) {
272 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
273 SCpnt->request_buffer,
274 SCpnt->request_bufflen,
275 SCpnt->sc_data_direction);
276 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
277 ioc->name, SCpnt, SCpnt->request_bufflen));
278 mptscsih_add_sge((char *) &pReq->SGL,
279 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
280 SCpnt->SCp.dma_handle);
281
282 return SUCCESS;
283 }
284
285 /* Handle the SG case.
286 */
287 sg = (struct scatterlist *) SCpnt->request_buffer;
288 sg_done = 0;
289 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
290 chainSge = NULL;
291
292 /* Prior to entering this loop - the following must be set
293 * current MF: sgeOffset (bytes)
294 * chainSge (Null if original MF is not a chain buffer)
295 * sg_done (num SGE done for this MF)
296 */
297
298nextSGEset:
299 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
300 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
301
302 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
303
304 /* Get first (num - 1) SG elements
305 * Skip any SG entries with a length of 0
306 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
307 */
308 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
309 thisxfer = sg_dma_len(sg);
310 if (thisxfer == 0) {
311 sg ++; /* Get next SG element from the OS */
312 sg_done++;
313 continue;
314 }
315
316 v2 = sg_dma_address(sg);
317 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
318
319 sg++; /* Get next SG element from the OS */
320 psge += (sizeof(u32) + sizeof(dma_addr_t));
321 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
322 sg_done++;
323 }
324
325 if (numSgeThisFrame == sges_left) {
326 /* Add last element, end of buffer and end of list flags.
327 */
328 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
329 MPT_SGE_FLAGS_END_OF_BUFFER |
330 MPT_SGE_FLAGS_END_OF_LIST;
331
332 /* Add last SGE and set termination flags.
333 * Note: Last SGE may have a length of 0 - which should be ok.
334 */
335 thisxfer = sg_dma_len(sg);
336
337 v2 = sg_dma_address(sg);
338 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
339 /*
340 sg++;
341 psge += (sizeof(u32) + sizeof(dma_addr_t));
342 */
343 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
344 sg_done++;
345
346 if (chainSge) {
347 /* The current buffer is a chain buffer,
348 * but there is not another one.
349 * Update the chain element
350 * Offset and Length fields.
351 */
352 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
353 } else {
354 /* The current buffer is the original MF
355 * and there is no Chain buffer.
356 */
357 pReq->ChainOffset = 0;
358 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200359 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
361 ioc->RequestNB[req_idx] = RequestNB;
362 }
363 } else {
364 /* At least one chain buffer is needed.
365 * Complete the first MF
366 * - last SGE element, set the LastElement bit
367 * - set ChainOffset (words) for orig MF
368 * (OR finish previous MF chain buffer)
369 * - update MFStructPtr ChainIndex
370 * - Populate chain element
371 * Also
372 * Loop until done.
373 */
374
375 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
376 ioc->name, sg_done));
377
378 /* Set LAST_ELEMENT flag for last non-chain element
379 * in the buffer. Since psge points at the NEXT
380 * SGE element, go back one SGE element, update the flags
381 * and reset the pointer. (Note: sgflags & thisxfer are already
382 * set properly).
383 */
384 if (sg_done) {
385 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
386 sgflags = le32_to_cpu(*ptmp);
387 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
388 *ptmp = cpu_to_le32(sgflags);
389 }
390
391 if (chainSge) {
392 /* The current buffer is a chain buffer.
393 * chainSge points to the previous Chain Element.
394 * Update its chain element Offset and Length (must
395 * include chain element size) fields.
396 * Old chain element is now complete.
397 */
398 u8 nextChain = (u8) (sgeOffset >> 2);
399 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
400 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
401 } else {
402 /* The original MF buffer requires a chain buffer -
403 * set the offset.
404 * Last element in this MF is a chain element.
405 */
406 pReq->ChainOffset = (u8) (sgeOffset >> 2);
407 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
408 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
409 ioc->RequestNB[req_idx] = RequestNB;
410 }
411
412 sges_left -= sg_done;
413
414
415 /* NOTE: psge points to the beginning of the chain element
416 * in current buffer. Get a chain buffer.
417 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200418 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
419 dfailprintk((MYIOC_s_INFO_FMT
420 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
421 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 /* Update the tracking arrays.
426 * If chainSge == NULL, update ReqToChain, else ChainToChain
427 */
428 if (chainSge) {
429 ioc->ChainToChain[chain_idx] = newIndex;
430 } else {
431 ioc->ReqToChain[req_idx] = newIndex;
432 }
433 chain_idx = newIndex;
434 chain_dma_off = ioc->req_sz * chain_idx;
435
436 /* Populate the chainSGE for the current buffer.
437 * - Set chain buffer pointer to psge and fill
438 * out the Address and Flags fields.
439 */
440 chainSge = (char *) psge;
441 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
442 psge, req_idx));
443
444 /* Start the SGE for the next buffer
445 */
446 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
447 sgeOffset = 0;
448 sg_done = 0;
449
450 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
451 psge, chain_idx));
452
453 /* Start the SGE for the next buffer
454 */
455
456 goto nextSGEset;
457 }
458
459 return SUCCESS;
460} /* mptscsih_AddSGE() */
461
Eric Moore786899b2006-07-11 17:22:22 -0600462static void
463mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
464 U32 SlotStatus)
465{
466 MPT_FRAME_HDR *mf;
467 SEPRequest_t *SEPMsg;
468
469 if (ioc->bus_type == FC)
470 return;
471
472 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
473 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
474 ioc->name,__FUNCTION__));
475 return;
476 }
477
478 SEPMsg = (SEPRequest_t *)mf;
479 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700480 SEPMsg->Bus = vtarget->channel;
481 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600482 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
483 SEPMsg->SlotStatus = SlotStatus;
484 devtverboseprintk((MYIOC_s_WARN_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700485 "Sending SEP cmd=%x channel=%d id=%d\n",
486 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600487 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
488}
489
Eric Moorec6c727a2007-01-29 09:44:54 -0700490#ifdef MPT_DEBUG_REPLY
491/**
492 * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
493 * @ioc: Pointer to MPT_ADAPTER structure
494 * @ioc_status: U32 IOCStatus word from IOC
495 * @scsi_status: U8 sam status from target
496 * @scsi_state: U8 scsi state
497 * @sc: original scsi cmnd pointer
498 * @mf: Pointer to MPT request frame
499 *
500 * Refer to lsi/mpi.h.
501 **/
502static void
503mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
504 u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
505{
506 char extend_desc[EVENT_DESCR_STR_SZ];
507 char *desc = NULL;
508
509 switch (ioc_status) {
510
511 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
512 desc = "SCSI Invalid Bus";
513 break;
514
515 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
516 desc = "SCSI Invalid TargetID";
517 break;
518
519 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
520 /*
521 * Inquiry is issued for device scanning
522 */
523 if (sc->cmnd[0] != 0x12)
524 desc = "SCSI Device Not There";
525 break;
526
527 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
528 desc = "SCSI Data Overrun";
529 break;
530
531 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
532 desc = "SCSI I/O Data Error";
533 break;
534
535 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
536 desc = "SCSI Protocol Error";
537 break;
538
539 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
540 desc = "SCSI Task Terminated";
541 break;
542
543 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
544 desc = "SCSI Residual Mismatch";
545 break;
546
547 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
548 desc = "SCSI Task Management Failed";
549 break;
550
551 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
552 desc = "SCSI IOC Terminated";
553 break;
554
555 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
556 desc = "SCSI Ext Terminated";
557 break;
558 }
559
560 if (!desc)
561 return;
562
563 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
564 "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
565 sc->device->host->host_no,
566 sc->device->channel, sc->device->id, sc->device->lun,
567 sc->cmnd[0], scsi_status, scsi_state);
568
569 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
570 ioc->name, ioc_status, desc, extend_desc);
571}
572#endif
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
575/*
576 * mptscsih_io_done - Main SCSI IO callback routine registered to
577 * Fusion MPT (base) driver
578 * @ioc: Pointer to MPT_ADAPTER structure
579 * @mf: Pointer to original MPT request frame
580 * @r: Pointer to MPT reply frame (NULL if TurboReply)
581 *
582 * This routine is called from mpt.c::mpt_interrupt() at the completion
583 * of any SCSI IO request.
584 * This routine is registered with the Fusion MPT (base) driver at driver
585 * load/init time via the mpt_register() API call.
586 *
587 * Returns 1 indicating alloc'd request frame ptr should be freed.
588 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400589int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
591{
592 struct scsi_cmnd *sc;
593 MPT_SCSI_HOST *hd;
594 SCSIIORequest_t *pScsiReq;
595 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700596 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600597 VirtDevice *vdev;
598 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
601
602 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700603 req_idx_MR = (mr != NULL) ?
604 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
605 if ((req_idx != req_idx_MR) ||
606 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
607 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
608 ioc->name);
609 printk (MYIOC_s_ERR_FMT
610 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
611 ioc->name, req_idx, req_idx_MR, mf, mr,
612 hd->ScsiLookup[req_idx_MR]);
613 return 0;
614 }
615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600617 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (sc == NULL) {
619 MPIHeader_t *hdr = (MPIHeader_t *)mf;
620
621 /* Remark: writeSDP1 will use the ScsiDoneCtx
622 * If a SCSI I/O cmd, device disabled by OS and
623 * completion done. Cannot touch sc struct. Just free mem.
624 */
625 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
626 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
627 ioc->name);
628
629 mptscsih_freeChainBuffers(ioc, req_idx);
630 return 1;
631 }
632
Eric Moore3dc0b032006-07-11 17:32:33 -0600633 if ((unsigned char *)mf != sc->host_scribble) {
634 mptscsih_freeChainBuffers(ioc, req_idx);
635 return 1;
636 }
637
638 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 sc->result = DID_OK << 16; /* Set default reply as OK */
640 pScsiReq = (SCSIIORequest_t *) mf;
641 pScsiReply = (SCSIIOReply_t *) mr;
642
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200643 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
644 dmfprintk((MYIOC_s_INFO_FMT
645 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
646 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
647 }else{
648 dmfprintk((MYIOC_s_INFO_FMT
649 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
650 ioc->name, mf, mr, sc, req_idx));
651 }
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 if (pScsiReply == NULL) {
654 /* special context reply handling */
655 ;
656 } else {
657 u32 xfer_cnt;
658 u16 status;
659 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700660 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
663 scsi_state = pScsiReply->SCSIState;
664 scsi_status = pScsiReply->SCSIStatus;
665 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
666 sc->resid = sc->request_bufflen - xfer_cnt;
Eric Moorec6c727a2007-01-29 09:44:54 -0700667 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600669 /*
670 * if we get a data underrun indication, yet no data was
671 * transferred and the SCSI status indicates that the
672 * command was never started, change the data underrun
673 * to success
674 */
675 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
676 (scsi_status == MPI_SCSI_STATUS_BUSY ||
677 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
678 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
679 status = MPI_IOCSTATUS_SUCCESS;
680 }
681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400683 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /*
686 * Look for + dump FCP ResponseInfo[]!
687 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600688 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
689 pScsiReply->ResponseInfo) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700690 printk(KERN_NOTICE "[%d:%d:%d:%d] "
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600691 "FCP_ResponseInfo=%08xh\n",
Eric Moorec6c727a2007-01-29 09:44:54 -0700692 sc->device->host->host_no, sc->device->channel,
693 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 le32_to_cpu(pScsiReply->ResponseInfo));
695 }
696
697 switch(status) {
698 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
699 /* CHECKME!
700 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
701 * But not: DID_BUS_BUSY lest one risk
702 * killing interrupt handler:-(
703 */
704 sc->result = SAM_STAT_BUSY;
705 break;
706
707 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
708 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
709 sc->result = DID_BAD_TARGET << 16;
710 break;
711
712 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
713 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600714 if (ioc->bus_type != FC)
715 sc->result = DID_NO_CONNECT << 16;
716 /* else fibre, just stall until rescan event */
717 else
718 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
721 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600722
723 vdev = sc->device->hostdata;
724 if (!vdev)
725 break;
726 vtarget = vdev->vtarget;
727 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
728 mptscsih_issue_sep_command(ioc, vtarget,
729 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
730 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 break;
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600735 if ( ioc->bus_type == SAS ) {
736 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
737 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700738 if ((log_info & SAS_LOGINFO_MASK)
739 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600740 sc->result = (DID_BUS_BUSY << 16);
741 break;
742 }
743 }
Eric Moore86dd4242007-01-04 20:44:01 -0700744 } else if (ioc->bus_type == FC) {
745 /*
746 * The FC IOC may kill a request for variety of
747 * reasons, some of which may be recovered by a
748 * retry, some which are unlikely to be
749 * recovered. Return DID_ERROR instead of
750 * DID_RESET to permit retry of the command,
751 * just not an infinite number of them
752 */
753 sc->result = DID_ERROR << 16;
754 break;
Eric Moorebf451522006-07-11 17:25:35 -0600755 }
756
757 /*
758 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
759 */
760
761 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
763 /* Linux handles an unsolicited DID_RESET better
764 * than an unsolicited DID_ABORT.
765 */
766 sc->result = DID_RESET << 16;
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 break;
769
770 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600771 sc->resid = sc->request_bufflen - xfer_cnt;
772 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
773 sc->result=DID_SOFT_ERROR << 16;
774 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600776 dreplyprintk((KERN_NOTICE
Eric Moorec6c727a2007-01-29 09:44:54 -0700777 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
778 sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
782 /*
783 * Do upfront check for valid SenseData and give it
784 * precedence!
785 */
786 sc->result = (DID_OK << 16) | scsi_status;
787 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
788 /* Have already saved the status and sense data
789 */
790 ;
791 } else {
792 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600793 if (scsi_status == SAM_STAT_BUSY)
794 sc->result = SAM_STAT_BUSY;
795 else
796 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 }
798 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
799 /* What to do?
800 */
801 sc->result = DID_SOFT_ERROR << 16;
802 }
803 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
804 /* Not real sure here either... */
805 sc->result = DID_RESET << 16;
806 }
807 }
808
809 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
810 sc->underflow));
811 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
812 /* Report Queue Full
813 */
814 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
815 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 break;
818
Moore, Eric7e551472006-01-16 18:53:21 -0700819 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
820 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
822 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600823 if (scsi_status == MPI_SCSI_STATUS_BUSY)
824 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
825 else
826 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (scsi_state == 0) {
828 ;
829 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
830 /*
831 * If running against circa 200003dd 909 MPT f/w,
832 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
833 * (QUEUE_FULL) returned from device! --> get 0x0000?128
834 * and with SenseBytes set to 0.
835 */
836 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
837 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
838
839 }
840 else if (scsi_state &
841 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
842 ) {
843 /*
844 * What to do?
845 */
846 sc->result = DID_SOFT_ERROR << 16;
847 }
848 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
849 /* Not real sure here either... */
850 sc->result = DID_RESET << 16;
851 }
852 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
853 /* Device Inq. data indicates that it supports
854 * QTags, but rejects QTag messages.
855 * This command completed OK.
856 *
857 * Not real sure here either so do nothing... */
858 }
859
860 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
861 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
862
863 /* Add handling of:
864 * Reservation Conflict, Busy,
865 * Command Terminated, CHECK
866 */
867 break;
868
869 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
870 sc->result = DID_SOFT_ERROR << 16;
871 break;
872
873 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
874 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
875 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
876 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
877 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
878 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
879 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
881 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
882 default:
883 /*
884 * What to do?
885 */
886 sc->result = DID_SOFT_ERROR << 16;
887 break;
888
889 } /* switch(status) */
890
Eric Moorec6c727a2007-01-29 09:44:54 -0700891#ifdef MPT_DEBUG_REPLY
892 if (sc->result) {
893
894 mptscsih_iocstatus_info_scsiio(ioc, status,
895 scsi_status, scsi_state, sc);
896
897 dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
898 "result=0x%08x\n\tiocstatus=0x%04X "
899 "scsi_state=0x%02X scsi_status=0x%02X "
900 "loginfo=0x%08X\n", __FUNCTION__,
901 sc->device->host->host_no, sc->device->channel, sc->device->id,
902 sc->device->lun, sc->cmnd[0], sc->result, status,
903 scsi_state, scsi_status, log_info));
904
905 dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
906 "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
907 sc->device->host->host_no, sc->device->channel, sc->device->id,
908 sc->device->lun, sc->resid, sc->request_bufflen,
909 xfer_cnt));
910 }
911#endif
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 } /* end of address reply case */
914
915 /* Unmap the DMA buffers, if any. */
916 if (sc->use_sg) {
917 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
918 sc->use_sg, sc->sc_data_direction);
919 } else if (sc->request_bufflen) {
920 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
921 sc->request_bufflen, sc->sc_data_direction);
922 }
923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 sc->scsi_done(sc); /* Issue the command callback */
925
926 /* Free Chain buffers */
927 mptscsih_freeChainBuffers(ioc, req_idx);
928 return 1;
929}
930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931/*
932 * mptscsih_flush_running_cmds - For each command found, search
933 * Scsi_Host instance taskQ and reply to OS.
934 * Called only if recovering from a FW reload.
935 * @hd: Pointer to a SCSI HOST structure
936 *
937 * Returns: None.
938 *
939 * Must be called while new I/Os are being queued.
940 */
941static void
942mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
943{
944 MPT_ADAPTER *ioc = hd->ioc;
945 struct scsi_cmnd *SCpnt;
946 MPT_FRAME_HDR *mf;
947 int ii;
948 int max = ioc->req_depth;
949
950 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
951 for (ii= 0; ii < max; ii++) {
952 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
953
954 /* Command found.
955 */
956
957 /* Null ScsiLookup index
958 */
959 hd->ScsiLookup[ii] = NULL;
960
961 mf = MPT_INDEX_2_MFPTR(ioc, ii);
962 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
963 mf, SCpnt));
964
Eric Moore3dc0b032006-07-11 17:32:33 -0600965 /* Free Chain buffers */
966 mptscsih_freeChainBuffers(ioc, ii);
967
968 /* Free Message frames */
969 mpt_free_msg_frame(ioc, mf);
970
971 if ((unsigned char *)mf != SCpnt->host_scribble)
972 continue;
973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 /* Set status, free OS resources (SG DMA buffers)
975 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400977 if (SCpnt->use_sg) {
978 pci_unmap_sg(ioc->pcidev,
979 (struct scatterlist *) SCpnt->request_buffer,
980 SCpnt->use_sg,
981 SCpnt->sc_data_direction);
982 } else if (SCpnt->request_bufflen) {
983 pci_unmap_single(ioc->pcidev,
984 SCpnt->SCp.dma_handle,
985 SCpnt->request_bufflen,
986 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
988 SCpnt->result = DID_RESET << 16;
989 SCpnt->host_scribble = NULL;
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
992 }
993 }
994
995 return;
996}
997
998/*
999 * mptscsih_search_running_cmds - Delete any commands associated
1000 * with the specified target and lun. Function called only
1001 * when a lun is disable by mid-layer.
1002 * Do NOT access the referenced scsi_cmnd structure or
1003 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001004 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001005 * @hd: Pointer to a SCSI HOST structure
1006 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 *
1008 * Returns: None.
1009 *
1010 * Called from slave_destroy.
1011 */
1012static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001013mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014{
1015 SCSIIORequest_t *mf = NULL;
1016 int ii;
1017 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001018 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001019 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Eric Moore793955f2007-01-29 09:42:20 -07001021 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
1022 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001025 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001028 if (mf == NULL)
1029 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001030 int_to_scsilun(vdevice->lun, &lun);
1031 if ((mf->Bus != vdevice->vtarget->channel) ||
1032 (mf->TargetID != vdevice->vtarget->id) ||
1033 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001035 dsprintk(( "search_running: found (sc=%p, mf = %p) "
1036 "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
1037 mf, mf->Bus, mf->TargetID, vdevice->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 /* Cleanup
1040 */
1041 hd->ScsiLookup[ii] = NULL;
1042 mptscsih_freeChainBuffers(hd->ioc, ii);
1043 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001044 if ((unsigned char *)mf != sc->host_scribble)
1045 continue;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001046 if (sc->use_sg) {
1047 pci_unmap_sg(hd->ioc->pcidev,
1048 (struct scatterlist *) sc->request_buffer,
1049 sc->use_sg,
1050 sc->sc_data_direction);
1051 } else if (sc->request_bufflen) {
1052 pci_unmap_single(hd->ioc->pcidev,
1053 sc->SCp.dma_handle,
1054 sc->request_bufflen,
1055 sc->sc_data_direction);
1056 }
1057 sc->host_scribble = NULL;
1058 sc->result = DID_NO_CONNECT << 16;
1059 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
1061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return;
1063}
1064
1065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1068/*
1069 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1070 * from a SCSI target device.
1071 * @sc: Pointer to scsi_cmnd structure
1072 * @pScsiReply: Pointer to SCSIIOReply_t
1073 * @pScsiReq: Pointer to original SCSI request
1074 *
1075 * This routine periodically reports QUEUE_FULL status returned from a
1076 * SCSI target device. It reports this to the console via kernel
1077 * printk() API call, not more than once every 10 seconds.
1078 */
1079static void
1080mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1081{
1082 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001085 if (sc->device == NULL)
1086 return;
1087 if (sc->device->host == NULL)
1088 return;
1089 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1090 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001092 if (time - hd->last_queue_full > 10 * HZ) {
1093 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1094 hd->ioc->name, 0, sc->device->id, sc->device->lun));
1095 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097}
1098
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/*
1101 * mptscsih_remove - Removed scsi devices
1102 * @pdev: Pointer to pci_dev structure
1103 *
1104 *
1105 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001106void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107mptscsih_remove(struct pci_dev *pdev)
1108{
1109 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1110 struct Scsi_Host *host = ioc->sh;
1111 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001112 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001114 if(!host) {
1115 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 scsi_remove_host(host);
1120
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001121 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1122 return;
1123
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001124 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001126 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128 if (hd->ScsiLookup != NULL) {
1129 sz1 = hd->ioc->req_depth * sizeof(void *);
1130 kfree(hd->ScsiLookup);
1131 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 }
1133
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001134 dprintk((MYIOC_s_INFO_FMT
1135 "Free'd ScsiLookup (%d) memory\n",
1136 hd->ioc->name, sz1));
1137
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001138 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001139
1140 /* NULL the Scsi_Host pointer
1141 */
1142 hd->ioc->sh = NULL;
1143
1144 scsi_host_put(host);
1145
1146 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148}
1149
1150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1151/*
1152 * mptscsih_shutdown - reboot notifier
1153 *
1154 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001156mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001158 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 struct Scsi_Host *host = ioc->sh;
1160 MPT_SCSI_HOST *hd;
1161
1162 if(!host)
1163 return;
1164
1165 hd = (MPT_SCSI_HOST *)host->hostdata;
1166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167}
1168
1169#ifdef CONFIG_PM
1170/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1171/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001172 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 *
1174 *
1175 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001176int
Pavel Machek8d189f72005-04-16 15:25:28 -07001177mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001179 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1184/*
1185 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1186 *
1187 *
1188 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001189int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190mptscsih_resume(struct pci_dev *pdev)
1191{
1192 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1193 struct Scsi_Host *host = ioc->sh;
1194 MPT_SCSI_HOST *hd;
1195
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if(!host)
1199 return 0;
1200
1201 hd = (MPT_SCSI_HOST *)host->hostdata;
1202 if(!hd)
1203 return 0;
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 return 0;
1206}
1207
1208#endif
1209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1211/**
1212 * mptscsih_info - Return information about MPT adapter
1213 * @SChost: Pointer to Scsi_Host structure
1214 *
1215 * (linux scsi_host_template.info routine)
1216 *
1217 * Returns pointer to buffer where information was written.
1218 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001219const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220mptscsih_info(struct Scsi_Host *SChost)
1221{
1222 MPT_SCSI_HOST *h;
1223 int size = 0;
1224
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001228 if (h->info_kbuf == NULL)
1229 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1230 return h->info_kbuf;
1231 h->info_kbuf[0] = '\0';
1232
1233 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1234 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 }
1236
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001237 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238}
1239
1240struct info_str {
1241 char *buffer;
1242 int length;
1243 int offset;
1244 int pos;
1245};
1246
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001247static void
1248mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
1250 if (info->pos + len > info->length)
1251 len = info->length - info->pos;
1252
1253 if (info->pos + len < info->offset) {
1254 info->pos += len;
1255 return;
1256 }
1257
1258 if (info->pos < info->offset) {
1259 data += (info->offset - info->pos);
1260 len -= (info->offset - info->pos);
1261 }
1262
1263 if (len > 0) {
1264 memcpy(info->buffer + info->pos, data, len);
1265 info->pos += len;
1266 }
1267}
1268
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001269static int
1270mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271{
1272 va_list args;
1273 char buf[81];
1274 int len;
1275
1276 va_start(args, fmt);
1277 len = vsprintf(buf, fmt, args);
1278 va_end(args);
1279
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001280 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 return len;
1282}
1283
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001284static int
1285mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286{
1287 struct info_str info;
1288
1289 info.buffer = pbuf;
1290 info.length = len;
1291 info.offset = offset;
1292 info.pos = 0;
1293
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001294 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1295 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1296 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1297 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1300}
1301
1302/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1303/**
1304 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001305 * @host: scsi host struct
1306 * @buffer: if write, user data; if read, buffer for user
1307 * @start: returns the buffer address
1308 * @offset: if write, 0; if read, the current offset into the buffer from
1309 * the previous read.
1310 * @length: if write, return length;
1311 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 *
1313 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001315int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1317 int length, int func)
1318{
1319 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1320 MPT_ADAPTER *ioc = hd->ioc;
1321 int size = 0;
1322
1323 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001324 /*
1325 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 */
1327 } else {
1328 if (start)
1329 *start = buffer;
1330
1331 size = mptscsih_host_info(ioc, buffer, offset, length);
1332 }
1333
1334 return size;
1335}
1336
1337/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1338#define ADD_INDEX_LOG(req_ent) do { } while(0)
1339
1340/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1341/**
1342 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1343 * @SCpnt: Pointer to scsi_cmnd structure
1344 * @done: Pointer SCSI mid-layer IO completion function
1345 *
1346 * (linux scsi_host_template.queuecommand routine)
1347 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1348 * from a linux scsi_cmnd request and send it to the IOC.
1349 *
1350 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1351 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001352int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1354{
1355 MPT_SCSI_HOST *hd;
1356 MPT_FRAME_HDR *mf;
1357 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001358 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 int lun;
1360 u32 datalen;
1361 u32 scsictl;
1362 u32 scsidir;
1363 u32 cmd_len;
1364 int my_idx;
1365 int ii;
1366
1367 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 lun = SCpnt->device->lun;
1369 SCpnt->scsi_done = done;
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1372 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1373
1374 if (hd->resetPending) {
1375 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1376 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1377 return SCSI_MLQUEUE_HOST_BUSY;
1378 }
1379
1380 /*
1381 * Put together a MPT SCSI request...
1382 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001383 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1385 hd->ioc->name));
1386 return SCSI_MLQUEUE_HOST_BUSY;
1387 }
1388
1389 pScsiReq = (SCSIIORequest_t *) mf;
1390
1391 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1392
1393 ADD_INDEX_LOG(my_idx);
1394
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001395 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 * Seems we may receive a buffer (datalen>0) even when there
1397 * will be no data transfer! GRRRRR...
1398 */
1399 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1400 datalen = SCpnt->request_bufflen;
1401 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1402 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1403 datalen = SCpnt->request_bufflen;
1404 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1405 } else {
1406 datalen = 0;
1407 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1408 }
1409
1410 /* Default to untagged. Once a target structure has been allocated,
1411 * use the Inquiry data to determine if device supports tagged.
1412 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001413 if (vdev
1414 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 && (SCpnt->device->tagged_supported)) {
1416 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1417 } else {
1418 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1419 }
1420
1421 /* Use the above information to set up the message frame
1422 */
Eric Moore793955f2007-01-29 09:42:20 -07001423 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1424 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001426 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1427 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1428 else
1429 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 pScsiReq->CDBLength = SCpnt->cmd_len;
1431 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1432 pScsiReq->Reserved = 0;
1433 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001434 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 pScsiReq->Control = cpu_to_le32(scsictl);
1436
1437 /*
1438 * Write SCSI CDB into the message
1439 */
1440 cmd_len = SCpnt->cmd_len;
1441 for (ii=0; ii < cmd_len; ii++)
1442 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1443
1444 for (ii=cmd_len; ii < 16; ii++)
1445 pScsiReq->CDB[ii] = 0;
1446
1447 /* DataLength */
1448 pScsiReq->DataLength = cpu_to_le32(datalen);
1449
1450 /* SenseBuffer low address */
1451 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1452 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1453
1454 /* Now add the SG list
1455 * Always have a SGE even if null length.
1456 */
1457 if (datalen == 0) {
1458 /* Add a NULL SGE */
1459 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1460 (dma_addr_t) -1);
1461 } else {
1462 /* Add a 32 or 64 bit SGE */
1463 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1464 goto fail;
1465 }
1466
Eric Moore3dc0b032006-07-11 17:32:33 -06001467 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001470 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1472 hd->ioc->name, SCpnt, mf, my_idx));
1473 DBG_DUMP_REQUEST_FRAME(mf)
1474 return 0;
1475
1476 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001477 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1479 mpt_free_msg_frame(hd->ioc, mf);
1480 return SCSI_MLQUEUE_HOST_BUSY;
1481}
1482
1483/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1484/*
1485 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1486 * with a SCSI IO request
1487 * @hd: Pointer to the MPT_SCSI_HOST instance
1488 * @req_idx: Index of the SCSI IO request frame.
1489 *
1490 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1491 * No return.
1492 */
1493static void
1494mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1495{
1496 MPT_FRAME_HDR *chain;
1497 unsigned long flags;
1498 int chain_idx;
1499 int next;
1500
1501 /* Get the first chain index and reset
1502 * tracker state.
1503 */
1504 chain_idx = ioc->ReqToChain[req_idx];
1505 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1506
1507 while (chain_idx != MPT_HOST_NO_CHAIN) {
1508
1509 /* Save the next chain buffer index */
1510 next = ioc->ChainToChain[chain_idx];
1511
1512 /* Free this chain buffer and reset
1513 * tracker
1514 */
1515 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1516
1517 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1518 + (chain_idx * ioc->req_sz));
1519
1520 spin_lock_irqsave(&ioc->FreeQlock, flags);
1521 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1522 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1523
1524 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1525 ioc->name, chain_idx));
1526
1527 /* handle next */
1528 chain_idx = next;
1529 }
1530 return;
1531}
1532
1533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1534/*
1535 * Reset Handling
1536 */
1537
1538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001539/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1541 * Fall through to mpt_HardResetHandler if: not operational, too many
1542 * failed TM requests or handshake failure.
1543 *
1544 * @ioc: Pointer to MPT_ADAPTER structure
1545 * @type: Task Management type
Eric Moore793955f2007-01-29 09:42:20 -07001546 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 * @lun: Logical Unit for reset (if appropriate)
1548 * @ctx2abort: Context for the task to be aborted (if appropriate)
1549 *
1550 * Remark: Currently invoked from a non-interrupt thread (_bh).
1551 *
1552 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1553 * will be active.
1554 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001555 * Returns 0 for SUCCESS, or FAILED.
1556 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001557int
Eric Moore793955f2007-01-29 09:42:20 -07001558mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559{
1560 MPT_ADAPTER *ioc;
1561 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 u32 ioc_raw_state;
1563 unsigned long flags;
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1567
1568 // SJR - CHECKME - Can we avoid this here?
1569 // (mpt_HardResetHandler has this check...)
1570 spin_lock_irqsave(&ioc->diagLock, flags);
1571 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1572 spin_unlock_irqrestore(&ioc->diagLock, flags);
1573 return FAILED;
1574 }
1575 spin_unlock_irqrestore(&ioc->diagLock, flags);
1576
1577 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001578 * If we time out and not bus reset, then we return a FAILED status
1579 * to the caller.
1580 * The call to mptscsih_tm_pending_wait() will set the pending flag
1581 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 * successful. Otherwise, reload the FW.
1583 */
1584 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1585 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001586 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 "Timed out waiting for last TM (%d) to complete! \n",
1588 hd->ioc->name, hd->tmPending));
1589 return FAILED;
1590 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001591 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
1592 "reset: Timed out waiting for last TM (%d) "
1593 "to complete! \n", hd->ioc->name,
1594 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 return FAILED;
1596 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001597 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 "Timed out waiting for last TM (%d) to complete! \n",
1599 hd->ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001600 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 }
1602 } else {
1603 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1604 hd->tmPending |= (1 << type);
1605 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1606 }
1607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1611 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001612 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1613 ioc->name, type, ioc_raw_state);
1614 printk(KERN_WARNING " Issuing HardReset!!\n");
1615 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1616 printk((KERN_WARNING "TMHandler: HardReset "
1617 "FAILED!!\n"));
1618 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
1620
Eric Moorecd2c6192007-01-29 09:47:47 -07001621 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1622 printk(MYIOC_s_WARN_FMT
1623 "TM Handler for type=%x: ioc_state: "
1624 "DOORBELL_ACTIVE (0x%x)!\n",
1625 ioc->name, type, ioc_raw_state);
1626 return FAILED;
1627 }
1628
1629 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001631 if (hd->hard_resets < -1)
1632 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Eric Moorecd2c6192007-01-29 09:47:47 -07001634 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1635 ctx2abort, timeout);
1636 if (rc)
1637 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
1638 hd->ioc->name);
1639 else
1640 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
1641 hd->ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1644
1645 return rc;
1646}
1647
1648
1649/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001650/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1652 * @hd: Pointer to MPT_SCSI_HOST structure
1653 * @type: Task Management type
Eric Moore793955f2007-01-29 09:42:20 -07001654 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 * @lun: Logical Unit for reset (if appropriate)
1656 * @ctx2abort: Context for the task to be aborted (if appropriate)
1657 *
1658 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1659 * or a non-interrupt thread. In the former, must not call schedule().
1660 *
1661 * Not all fields are meaningfull for all task types.
1662 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001663 * Returns 0 for SUCCESS, or FAILED.
1664 *
1665 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666static int
Eric Moore793955f2007-01-29 09:42:20 -07001667mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668{
1669 MPT_FRAME_HDR *mf;
1670 SCSITaskMgmt_t *pScsiTm;
1671 int ii;
1672 int retval;
1673
1674 /* Return Fail to calling function if no message frames available.
1675 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001676 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1678 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001679 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1682 hd->ioc->name, mf));
1683
1684 /* Format the Request
1685 */
1686 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001687 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 pScsiTm->Bus = channel;
1689 pScsiTm->ChainOffset = 0;
1690 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1691
1692 pScsiTm->Reserved = 0;
1693 pScsiTm->TaskType = type;
1694 pScsiTm->Reserved1 = 0;
1695 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1696 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1697
Eric Moore793955f2007-01-29 09:42:20 -07001698 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 for (ii=0; ii < 7; ii++)
1701 pScsiTm->Reserved2[ii] = 0;
1702
1703 pScsiTm->TaskMsgContext = ctx2abort;
1704
Eric Moorecd2c6192007-01-29 09:47:47 -07001705 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1706 "type=%d\n", hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1709
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001710 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Eric Moorecd2c6192007-01-29 09:47:47 -07001711 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
1712 dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
1713 " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
1714 hd->ioc, mf, retval));
1715 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717
1718 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Moorecd2c6192007-01-29 09:47:47 -07001719 dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1721 hd->ioc, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1723 hd->ioc->name));
1724 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
Eric Moorecd2c6192007-01-29 09:47:47 -07001725 dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
1726 hd->ioc->name, retval));
1727 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 }
1729
Eric Moorecd2c6192007-01-29 09:47:47 -07001730 /*
1731 * Handle success case, see if theres a non-zero ioc_status.
1732 */
1733 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1734 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1735 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1736 retval = 0;
1737 else
1738 retval = FAILED;
1739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001741
1742 fail_out:
1743
1744 /*
1745 * Free task managment mf, and corresponding tm flags
1746 */
1747 mpt_free_msg_frame(hd->ioc, mf);
1748 hd->tmPending = 0;
1749 hd->tmState = TM_STATE_NONE;
1750 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751}
1752
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001753static int
1754mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1755{
1756 switch (ioc->bus_type) {
1757 case FC:
1758 return 40;
1759 case SAS:
1760 return 10;
1761 case SPI:
1762 default:
1763 return 2;
1764 }
1765}
1766
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1768/**
1769 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1770 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1771 *
1772 * (linux scsi_host_template.eh_abort_handler routine)
1773 *
1774 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001775 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001776int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777mptscsih_abort(struct scsi_cmnd * SCpnt)
1778{
1779 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 MPT_FRAME_HDR *mf;
1781 u32 ctx2abort;
1782 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001784 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001785 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
1787 /* If we can't locate our host adapter structure, return FAILED status.
1788 */
1789 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1790 SCpnt->result = DID_RESET << 16;
1791 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001792 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 "Can't locate host! (sc=%p)\n",
1794 SCpnt));
1795 return FAILED;
1796 }
1797
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 /* Find this command
1799 */
1800 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001801 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 * Do OS callback.
1803 */
1804 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001805 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 "Command not in the active list! (sc=%p)\n",
1807 hd->ioc->name, SCpnt));
1808 return SUCCESS;
1809 }
1810
Eric Moorecd2c6192007-01-29 09:47:47 -07001811 if (hd->resetPending)
Moore, Eric65207fe2006-04-21 16:14:35 -06001812 return FAILED;
Moore, Eric65207fe2006-04-21 16:14:35 -06001813
1814 if (hd->timeouts < -1)
1815 hd->timeouts++;
1816
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001817 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1818 hd->ioc->name, SCpnt);
1819 scsi_print_command(SCpnt);
1820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1822 * (the IO to be ABORT'd)
1823 *
1824 * NOTE: Since we do not byteswap MsgContext, we do not
1825 * swap it here either. It is an opaque cookie to
1826 * the controller, so it does not matter. -DaveM
1827 */
1828 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1829 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1830
1831 hd->abortSCpnt = SCpnt;
1832
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001833 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001834 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore793955f2007-01-29 09:42:20 -07001835 vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001836 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
Eric Moore3dc0b032006-07-11 17:32:33 -06001838 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001839 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001840 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001841
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1843 hd->ioc->name,
1844 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001846 if (retval == 0)
1847 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001848 else
1849 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850}
1851
1852/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1853/**
1854 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1855 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1856 *
1857 * (linux scsi_host_template.eh_dev_reset_handler routine)
1858 *
1859 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001860 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001861int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1863{
1864 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001865 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001866 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 /* If we can't locate our host adapter structure, return FAILED status.
1869 */
1870 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001871 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 "Can't locate host! (sc=%p)\n",
1873 SCpnt));
1874 return FAILED;
1875 }
1876
1877 if (hd->resetPending)
1878 return FAILED;
1879
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001880 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001882 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001884 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001885 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -07001886 vdev->vtarget->channel, vdev->vtarget->id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001887 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001888
1889 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1890 hd->ioc->name,
1891 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1892
1893 if (retval == 0)
1894 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001895 else
1896 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897}
1898
Eric Moorecd2c6192007-01-29 09:47:47 -07001899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1901/**
1902 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1903 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1904 *
1905 * (linux scsi_host_template.eh_bus_reset_handler routine)
1906 *
1907 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001908 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001909int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1911{
1912 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001913 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001914 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 /* If we can't locate our host adapter structure, return FAILED status.
1917 */
1918 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001919 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 "Can't locate host! (sc=%p)\n",
1921 SCpnt ) );
1922 return FAILED;
1923 }
1924
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001925 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001927 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
1929 if (hd->timeouts < -1)
1930 hd->timeouts++;
1931
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001932 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001933 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore793955f2007-01-29 09:42:20 -07001934 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001936 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1937 hd->ioc->name,
1938 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1939
1940 if (retval == 0)
1941 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001942 else
1943 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944}
1945
1946/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1947/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001948 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1950 *
1951 * (linux scsi_host_template.eh_host_reset_handler routine)
1952 *
1953 * Returns SUCCESS or FAILED.
1954 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001955int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1957{
1958 MPT_SCSI_HOST * hd;
1959 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
1961 /* If we can't locate the host to reset, then we failed. */
1962 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001963 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 "Can't locate host! (sc=%p)\n",
1965 SCpnt ) );
1966 return FAILED;
1967 }
1968
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001969 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 hd->ioc->name, SCpnt);
1971
1972 /* If our attempts to reset the host failed, then return a failed
1973 * status. The host will be taken off line by the SCSI mid-layer.
1974 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1976 status = FAILED;
1977 } else {
1978 /* Make sure TM pending is cleared and TM state is set to
1979 * NONE.
1980 */
1981 hd->tmPending = 0;
1982 hd->tmState = TM_STATE_NONE;
1983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001985 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 "Status = %s\n",
1987 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1988
1989 return status;
1990}
1991
1992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1993/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001994 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 * @hd: Pointer to MPT host structure.
1996 *
1997 * Returns {SUCCESS,FAILED}.
1998 */
1999static int
2000mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2001{
2002 unsigned long flags;
2003 int loop_count = 4 * 10; /* Wait 10 seconds */
2004 int status = FAILED;
2005
2006 do {
2007 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2008 if (hd->tmState == TM_STATE_NONE) {
2009 hd->tmState = TM_STATE_IN_PROGRESS;
2010 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002012 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 break;
2014 }
2015 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
2016 msleep(250);
2017 } while (--loop_count);
2018
2019 return status;
2020}
2021
2022/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2023/**
2024 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2025 * @hd: Pointer to MPT host structure.
2026 *
2027 * Returns {SUCCESS,FAILED}.
2028 */
2029static int
2030mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2031{
2032 unsigned long flags;
2033 int loop_count = 4 * timeout;
2034 int status = FAILED;
2035
2036 do {
2037 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
2038 if(hd->tmPending == 0) {
2039 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002040 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 break;
2042 }
2043 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002044 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 } while (--loop_count);
2046
2047 return status;
2048}
2049
2050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002051static void
2052mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2053{
2054 char *desc;
2055
2056 switch (response_code) {
2057 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2058 desc = "The task completed.";
2059 break;
2060 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2061 desc = "The IOC received an invalid frame status.";
2062 break;
2063 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2064 desc = "The task type is not supported.";
2065 break;
2066 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2067 desc = "The requested task failed.";
2068 break;
2069 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2070 desc = "The task completed successfully.";
2071 break;
2072 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2073 desc = "The LUN request is invalid.";
2074 break;
2075 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2076 desc = "The task is in the IOC queue and has not been sent to target.";
2077 break;
2078 default:
2079 desc = "unknown";
2080 break;
2081 }
2082 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2083 ioc->name, response_code, desc);
2084}
2085
2086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087/**
2088 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2089 * @ioc: Pointer to MPT_ADAPTER structure
2090 * @mf: Pointer to SCSI task mgmt request frame
2091 * @mr: Pointer to SCSI task mgmt reply frame
2092 *
2093 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2094 * of any SCSI task management request.
2095 * This routine is registered with the MPT (base) driver at driver
2096 * load/init time via the mpt_register() API call.
2097 *
2098 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002099 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002100int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2102{
2103 SCSITaskMgmtReply_t *pScsiTmReply;
2104 SCSITaskMgmt_t *pScsiTmReq;
2105 MPT_SCSI_HOST *hd;
2106 unsigned long flags;
2107 u16 iocstatus;
2108 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002109 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
2111 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002112 ioc->name, mf, mr));
2113 if (!ioc->sh) {
2114 dtmprintk((MYIOC_s_WARN_FMT
2115 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 return 1;
2117 }
2118
2119 if (mr == NULL) {
Eric Moorecd2c6192007-01-29 09:47:47 -07002120 dtmprintk((MYIOC_s_WARN_FMT
2121 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 }
2124
Eric Moorecd2c6192007-01-29 09:47:47 -07002125 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2126 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2127 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2128 tmType = pScsiTmReq->TaskType;
2129 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2130 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2131
2132 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2133 pScsiTmReply->ResponseCode)
2134 mptscsih_taskmgmt_response_code(ioc,
2135 pScsiTmReply->ResponseCode);
2136 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2137
2138#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
2139 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2140 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2141 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2142 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2143 le16_to_cpu(pScsiTmReply->IOCStatus),
2144 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2145 le32_to_cpu(pScsiTmReply->TerminationCount));
2146#endif
2147 if (!iocstatus) {
2148 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2149 hd->abortSCpnt = NULL;
2150 goto out;
2151 }
2152
2153 /* Error? (anything non-zero?) */
2154
2155 /* clear flags and continue.
2156 */
2157 switch (tmType) {
2158
2159 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2160 if (termination_count == 1)
2161 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2162 hd->abortSCpnt = NULL;
2163 break;
2164
2165 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2166
2167 /* If an internal command is present
2168 * or the TM failed - reload the FW.
2169 * FC FW may respond FAILED to an ABORT
2170 */
2171 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2172 hd->cmdPtr)
2173 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
2174 printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
2175 break;
2176
2177 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2178 default:
2179 break;
2180 }
2181
2182 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 spin_lock_irqsave(&ioc->FreeQlock, flags);
2184 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002186 hd->tm_iocstatus = iocstatus;
2187 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
2189 return 1;
2190}
2191
2192/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2193/*
2194 * This is anyones guess quite frankly.
2195 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002196int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2198 sector_t capacity, int geom[])
2199{
2200 int heads;
2201 int sectors;
2202 sector_t cylinders;
2203 ulong dummy;
2204
2205 heads = 64;
2206 sectors = 32;
2207
2208 dummy = heads * sectors;
2209 cylinders = capacity;
2210 sector_div(cylinders,dummy);
2211
2212 /*
2213 * Handle extended translation size for logical drives
2214 * > 1Gb
2215 */
2216 if ((ulong)capacity >= 0x200000) {
2217 heads = 255;
2218 sectors = 63;
2219 dummy = heads * sectors;
2220 cylinders = capacity;
2221 sector_div(cylinders,dummy);
2222 }
2223
2224 /* return result */
2225 geom[0] = heads;
2226 geom[1] = sectors;
2227 geom[2] = cylinders;
2228
2229 dprintk((KERN_NOTICE
2230 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002231 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
2233 return 0;
2234}
2235
Moore, Ericf44e5462006-03-14 09:14:21 -07002236/* Search IOC page 3 to determine if this is hidden physical disk
2237 *
2238 */
2239int
Eric Moore793955f2007-01-29 09:42:20 -07002240mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002241{
Eric Mooreb506ade2007-01-29 09:45:37 -07002242 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002243 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002244 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002245
Eric Moore793955f2007-01-29 09:42:20 -07002246 if (!ioc->raid_data.pIocPg3)
2247 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002248 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002249 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2250 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2251 rc = 1;
2252 goto out;
2253 }
2254 }
2255
Eric Mooreb506ade2007-01-29 09:45:37 -07002256 /*
2257 * Check inactive list for matching phys disks
2258 */
2259 if (list_empty(&ioc->raid_data.inactive_list))
2260 goto out;
2261
2262 down(&ioc->raid_data.inactive_list_mutex);
2263 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2264 list) {
2265 if ((component_info->d.PhysDiskID == id) &&
2266 (component_info->d.PhysDiskBus == channel))
2267 rc = 1;
2268 }
2269 up(&ioc->raid_data.inactive_list_mutex);
2270
Eric Moore793955f2007-01-29 09:42:20 -07002271 out:
2272 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002273}
2274EXPORT_SYMBOL(mptscsih_is_phys_disk);
2275
Eric Moore793955f2007-01-29 09:42:20 -07002276u8
2277mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002278{
Eric Mooreb506ade2007-01-29 09:45:37 -07002279 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002280 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002281 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002282
Eric Moore793955f2007-01-29 09:42:20 -07002283 if (!ioc->raid_data.pIocPg3)
2284 goto out;
2285 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2286 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2287 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2288 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2289 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002290 }
2291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Eric Mooreb506ade2007-01-29 09:45:37 -07002293 /*
2294 * Check inactive list for matching phys disks
2295 */
2296 if (list_empty(&ioc->raid_data.inactive_list))
2297 goto out;
2298
2299 down(&ioc->raid_data.inactive_list_mutex);
2300 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2301 list) {
2302 if ((component_info->d.PhysDiskID == id) &&
2303 (component_info->d.PhysDiskBus == channel))
2304 rc = component_info->d.PhysDiskNum;
2305 }
2306 up(&ioc->raid_data.inactive_list_mutex);
2307
Eric Moore793955f2007-01-29 09:42:20 -07002308 out:
2309 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002310}
Eric Moore793955f2007-01-29 09:42:20 -07002311EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002312
2313/*
2314 * OS entry point to allow for host driver to free allocated memory
2315 * Called if no device present or device being unloaded
2316 */
2317void
2318mptscsih_slave_destroy(struct scsi_device *sdev)
2319{
2320 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322 VirtTarget *vtarget;
2323 VirtDevice *vdevice;
2324 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002326 starget = scsi_target(sdev);
2327 vtarget = starget->hostdata;
2328 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002330 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002331 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002332 mptscsih_synchronize_cache(hd, vdevice);
2333 kfree(vdevice);
2334 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335}
2336
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002337/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2338/*
2339 * mptscsih_change_queue_depth - This function will set a devices queue depth
2340 * @sdev: per scsi_device pointer
2341 * @qdepth: requested queue depth
2342 *
2343 * Adding support for new 'change_queue_depth' api.
2344*/
2345int
2346mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002348 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2349 VirtTarget *vtarget;
2350 struct scsi_target *starget;
2351 int max_depth;
2352 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002354 starget = scsi_target(sdev);
2355 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002356
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002357 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002358 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002360 else if (sdev->type == TYPE_DISK &&
2361 vtarget->minSyncFactor <= MPT_ULTRA160)
2362 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2363 else
2364 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 } else
2366 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2367
2368 if (qdepth > max_depth)
2369 qdepth = max_depth;
2370 if (qdepth == 1)
2371 tagged = 0;
2372 else
2373 tagged = MSG_SIMPLE_TAG;
2374
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002375 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2376 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377}
2378
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379/*
2380 * OS entry point to adjust the queue_depths on a per-device basis.
2381 * Called once per device the bus scan. Use it to force the queue_depth
2382 * member to 1 if a device does not support Q tags.
2383 * Return non-zero if fails.
2384 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002385int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002386mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002388 struct Scsi_Host *sh = sdev->host;
2389 VirtTarget *vtarget;
2390 VirtDevice *vdevice;
2391 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2393
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002394 starget = scsi_target(sdev);
2395 vtarget = starget->hostdata;
2396 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002399 "device @ %p, channel=%d, id=%d, lun=%d\n",
2400 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002401 if (hd->ioc->bus_type == SPI)
2402 dsprintk((MYIOC_s_INFO_FMT
2403 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2404 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2405 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002409 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 goto slave_configure_exit;
2411 }
2412
Eric Moore793955f2007-01-29 09:42:20 -07002413 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002414 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 dsprintk((MYIOC_s_INFO_FMT
2417 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002418 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002420 if (hd->ioc->bus_type == SPI)
2421 dsprintk((MYIOC_s_INFO_FMT
2422 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2423 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2424 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426slave_configure_exit:
2427
2428 dsprintk((MYIOC_s_INFO_FMT
2429 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002430 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2431 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
2433 return 0;
2434}
2435
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2437/*
2438 * Private routines...
2439 */
2440
2441/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2442/* Utility function to copy sense data from the scsi_cmnd buffer
2443 * to the FC and SCSI target structures.
2444 *
2445 */
2446static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002447mptscsih_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 -07002448{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002449 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 SCSIIORequest_t *pReq;
2451 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
2453 /* Get target structure
2454 */
2455 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002456 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
2458 if (sense_count) {
2459 u8 *sense_data;
2460 int req_index;
2461
2462 /* Copy the sense received into the scsi command block. */
2463 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2464 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2465 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2466
2467 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2468 */
2469 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002470 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 int idx;
2472 MPT_ADAPTER *ioc = hd->ioc;
2473
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002474 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2476 ioc->events[idx].eventContext = ioc->eventContext;
2477
2478 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2479 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002480 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2483
2484 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002485 if (hd->ioc->pcidev->vendor ==
2486 PCI_VENDOR_ID_IBM) {
2487 mptscsih_issue_sep_command(hd->ioc,
2488 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2489 vdev->vtarget->tflags |=
2490 MPT_TARGET_FLAGS_LED_ON;
2491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 }
2493 }
2494 } else {
2495 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2496 hd->ioc->name));
2497 }
2498}
2499
Eric Moore3dc0b032006-07-11 17:32:33 -06002500static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2502{
2503 MPT_SCSI_HOST *hd;
2504 int i;
2505
2506 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2507
2508 for (i = 0; i < hd->ioc->req_depth; i++) {
2509 if (hd->ScsiLookup[i] == sc) {
2510 return i;
2511 }
2512 }
2513
2514 return -1;
2515}
2516
2517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002518int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2520{
2521 MPT_SCSI_HOST *hd;
2522 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002523 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524
2525 dtmprintk((KERN_WARNING MYNAM
2526 ": IOC %s_reset routed to SCSI host driver!\n",
2527 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2528 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2529
2530 /* If a FW reload request arrives after base installed but
2531 * before all scsi hosts have been attached, then an alt_ioc
2532 * may have a NULL sh pointer.
2533 */
2534 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2535 return 0;
2536 else
2537 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2538
2539 if (reset_phase == MPT_IOC_SETUP_RESET) {
2540 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2541
2542 /* Clean Up:
2543 * 1. Set Hard Reset Pending Flag
2544 * All new commands go to doneQ
2545 */
2546 hd->resetPending = 1;
2547
2548 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2549 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2550
2551 /* 2. Flush running commands
2552 * Clean ScsiLookup (and associated memory)
2553 * AND clean mytaskQ
2554 */
2555
2556 /* 2b. Reply to OS all known outstanding I/O commands.
2557 */
2558 mptscsih_flush_running_cmds(hd);
2559
2560 /* 2c. If there was an internal command that
2561 * has not completed, configuration or io request,
2562 * free these resources.
2563 */
2564 if (hd->cmdPtr) {
2565 del_timer(&hd->timer);
2566 mpt_free_msg_frame(ioc, hd->cmdPtr);
2567 }
2568
2569 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2570
2571 } else {
2572 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2573
2574 /* Once a FW reload begins, all new OS commands are
2575 * redirected to the doneQ w/ a reset status.
2576 * Init all control structures.
2577 */
2578
2579 /* ScsiLookup initialization
2580 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002581 for (ii=0; ii < hd->ioc->req_depth; ii++)
2582 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 /* 2. Chain Buffer initialization
2585 */
2586
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002587 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
2590 /* 5. Enable new commands to be posted
2591 */
2592 spin_lock_irqsave(&ioc->FreeQlock, flags);
2593 hd->tmPending = 0;
2594 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2595 hd->resetPending = 0;
2596 hd->tmState = TM_STATE_NONE;
2597
2598 /* 6. If there was an internal command,
2599 * wake this process up.
2600 */
2601 if (hd->cmdPtr) {
2602 /*
2603 * Wake up the original calling thread
2604 */
2605 hd->pLocal = &hd->localReply;
2606 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002607 hd->scandv_wait_done = 1;
2608 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 hd->cmdPtr = NULL;
2610 }
2611
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2613
2614 }
2615
2616 return 1; /* currently means nothing really */
2617}
2618
2619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002620int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2622{
2623 MPT_SCSI_HOST *hd;
2624 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2625
Moore, Eric3a892be2006-03-14 09:14:03 -07002626 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 ioc->name, event));
2628
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002629 if (ioc->sh == NULL ||
2630 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2631 return 1;
2632
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 switch (event) {
2634 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2635 /* FIXME! */
2636 break;
2637 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2638 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002639 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002640 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 break;
2642 case MPI_EVENT_LOGOUT: /* 09 */
2643 /* FIXME! */
2644 break;
2645
Michael Reed05e8ec12006-01-13 14:31:54 -06002646 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002647 break;
2648
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 /*
2650 * CHECKME! Don't think we need to do
2651 * anything for these, but...
2652 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2654 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2655 /*
2656 * CHECKME! Falling thru...
2657 */
2658 break;
2659
2660 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002661 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 case MPI_EVENT_NONE: /* 00 */
2664 case MPI_EVENT_LOG_DATA: /* 01 */
2665 case MPI_EVENT_STATE_CHANGE: /* 02 */
2666 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2667 default:
2668 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2669 break;
2670 }
2671
2672 return 1; /* currently means nothing really */
2673}
2674
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2676/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 * Bus Scan and Domain Validation functionality ...
2678 */
2679
2680/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2681/*
2682 * mptscsih_scandv_complete - Scan and DV callback routine registered
2683 * to Fustion MPT (base) driver.
2684 *
2685 * @ioc: Pointer to MPT_ADAPTER structure
2686 * @mf: Pointer to original MPT request frame
2687 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2688 *
2689 * This routine is called from mpt.c::mpt_interrupt() at the completion
2690 * of any SCSI IO request.
2691 * This routine is registered with the Fusion MPT (base) driver at driver
2692 * load/init time via the mpt_register() API call.
2693 *
2694 * Returns 1 indicating alloc'd request frame ptr should be freed.
2695 *
2696 * Remark: Sets a completion code and (possibly) saves sense data
2697 * in the IOC member localReply structure.
2698 * Used ONLY for DV and other internal commands.
2699 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002700int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2702{
2703 MPT_SCSI_HOST *hd;
2704 SCSIIORequest_t *pReq;
2705 int completionCode;
2706 u16 req_idx;
2707
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002708 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2709
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 if ((mf == NULL) ||
2711 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2712 printk(MYIOC_s_ERR_FMT
2713 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2714 ioc->name, mf?"BAD":"NULL", (void *) mf);
2715 goto wakeup;
2716 }
2717
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 del_timer(&hd->timer);
2719 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2720 hd->ScsiLookup[req_idx] = NULL;
2721 pReq = (SCSIIORequest_t *) mf;
2722
2723 if (mf != hd->cmdPtr) {
2724 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2725 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2726 }
2727 hd->cmdPtr = NULL;
2728
2729 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2730 hd->ioc->name, mf, mr, req_idx));
2731
2732 hd->pLocal = &hd->localReply;
2733 hd->pLocal->scsiStatus = 0;
2734
2735 /* If target struct exists, clear sense valid flag.
2736 */
2737 if (mr == NULL) {
2738 completionCode = MPT_SCANDV_GOOD;
2739 } else {
2740 SCSIIOReply_t *pReply;
2741 u16 status;
2742 u8 scsi_status;
2743
2744 pReply = (SCSIIOReply_t *) mr;
2745
2746 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2747 scsi_status = pReply->SCSIStatus;
2748
2749 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2750 status, pReply->SCSIState, scsi_status,
2751 le32_to_cpu(pReply->IOCLogInfo)));
2752
2753 switch(status) {
2754
2755 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2756 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2757 break;
2758
2759 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2760 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2761 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2762 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2763 completionCode = MPT_SCANDV_DID_RESET;
2764 break;
2765
2766 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2767 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2768 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2769 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2770 ConfigReply_t *pr = (ConfigReply_t *)mr;
2771 completionCode = MPT_SCANDV_GOOD;
2772 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2773 hd->pLocal->header.PageLength = pr->Header.PageLength;
2774 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2775 hd->pLocal->header.PageType = pr->Header.PageType;
2776
2777 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2778 /* If the RAID Volume request is successful,
2779 * return GOOD, else indicate that
2780 * some type of error occurred.
2781 */
2782 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002783 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 completionCode = MPT_SCANDV_GOOD;
2785 else
2786 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002787 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2790 u8 *sense_data;
2791 int sz;
2792
2793 /* save sense data in global structure
2794 */
2795 completionCode = MPT_SCANDV_SENSE;
2796 hd->pLocal->scsiStatus = scsi_status;
2797 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2798 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2799
2800 sz = min_t(int, pReq->SenseBufferLength,
2801 SCSI_STD_SENSE_BYTES);
2802 memcpy(hd->pLocal->sense, sense_data, sz);
2803
2804 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2805 sense_data));
2806 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2807 if (pReq->CDB[0] == INQUIRY)
2808 completionCode = MPT_SCANDV_ISSUE_SENSE;
2809 else
2810 completionCode = MPT_SCANDV_DID_RESET;
2811 }
2812 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2813 completionCode = MPT_SCANDV_DID_RESET;
2814 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2815 completionCode = MPT_SCANDV_DID_RESET;
2816 else {
2817 completionCode = MPT_SCANDV_GOOD;
2818 hd->pLocal->scsiStatus = scsi_status;
2819 }
2820 break;
2821
2822 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2823 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2824 completionCode = MPT_SCANDV_DID_RESET;
2825 else
2826 completionCode = MPT_SCANDV_SOME_ERROR;
2827 break;
2828
2829 default:
2830 completionCode = MPT_SCANDV_SOME_ERROR;
2831 break;
2832
2833 } /* switch(status) */
2834
2835 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2836 completionCode));
2837 } /* end of address reply case */
2838
2839 hd->pLocal->completion = completionCode;
2840
2841 /* MF and RF are freed in mpt_interrupt
2842 */
2843wakeup:
2844 /* Free Chain buffers (will never chain) in scan or dv */
2845 //mptscsih_freeChainBuffers(ioc, req_idx);
2846
2847 /*
2848 * Wake up the original calling thread
2849 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002850 hd->scandv_wait_done = 1;
2851 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853 return 1;
2854}
2855
2856/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2857/* mptscsih_timer_expired - Call back for timer process.
2858 * Used only for dv functionality.
2859 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2860 *
2861 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002862void
2863mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864{
2865 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
2866
2867 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
2868
2869 if (hd->cmdPtr) {
2870 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2871
2872 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2873 /* Desire to issue a task management request here.
2874 * TM requests MUST be single threaded.
2875 * If old eh code and no TM current, issue request.
2876 * If new eh code, do nothing. Wait for OS cmd timeout
2877 * for bus reset.
2878 */
2879 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
2880 } else {
2881 /* Perform a FW reload */
2882 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
2883 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
2884 }
2885 }
2886 } else {
2887 /* This should NEVER happen */
2888 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
2889 }
2890
2891 /* No more processing.
2892 * TM call will generate an interrupt for SCSI TM Management.
2893 * The FW will reply to all outstanding commands, callback will finish cleanup.
2894 * Hard reset clean-up will free all resources.
2895 */
2896 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
2897
2898 return;
2899}
2900
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2903/**
2904 * mptscsih_do_cmd - Do internal command.
2905 * @hd: MPT_SCSI_HOST pointer
2906 * @io: INTERNAL_CMD pointer.
2907 *
2908 * Issue the specified internally generated command and do command
2909 * specific cleanup. For bus scan / DV only.
2910 * NOTES: If command is Inquiry and status is good,
2911 * initialize a target structure, save the data
2912 *
2913 * Remark: Single threaded access only.
2914 *
2915 * Return:
2916 * < 0 if an illegal command or no resources
2917 *
2918 * 0 if good
2919 *
2920 * > 0 if command complete but some type of completion error.
2921 */
2922static int
2923mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2924{
2925 MPT_FRAME_HDR *mf;
2926 SCSIIORequest_t *pScsiReq;
2927 SCSIIORequest_t ReqCopy;
2928 int my_idx, ii, dir;
2929 int rc, cmdTimeout;
2930 int in_isr;
2931 char cmdLen;
2932 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2933 char cmd = io->cmd;
2934
2935 in_isr = in_interrupt();
2936 if (in_isr) {
2937 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2938 hd->ioc->name));
2939 return -EPERM;
2940 }
2941
2942
2943 /* Set command specific information
2944 */
2945 switch (cmd) {
2946 case INQUIRY:
2947 cmdLen = 6;
2948 dir = MPI_SCSIIO_CONTROL_READ;
2949 CDB[0] = cmd;
2950 CDB[4] = io->size;
2951 cmdTimeout = 10;
2952 break;
2953
2954 case TEST_UNIT_READY:
2955 cmdLen = 6;
2956 dir = MPI_SCSIIO_CONTROL_READ;
2957 cmdTimeout = 10;
2958 break;
2959
2960 case START_STOP:
2961 cmdLen = 6;
2962 dir = MPI_SCSIIO_CONTROL_READ;
2963 CDB[0] = cmd;
2964 CDB[4] = 1; /*Spin up the disk */
2965 cmdTimeout = 15;
2966 break;
2967
2968 case REQUEST_SENSE:
2969 cmdLen = 6;
2970 CDB[0] = cmd;
2971 CDB[4] = io->size;
2972 dir = MPI_SCSIIO_CONTROL_READ;
2973 cmdTimeout = 10;
2974 break;
2975
2976 case READ_BUFFER:
2977 cmdLen = 10;
2978 dir = MPI_SCSIIO_CONTROL_READ;
2979 CDB[0] = cmd;
2980 if (io->flags & MPT_ICFLAG_ECHO) {
2981 CDB[1] = 0x0A;
2982 } else {
2983 CDB[1] = 0x02;
2984 }
2985
2986 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2987 CDB[1] |= 0x01;
2988 }
2989 CDB[6] = (io->size >> 16) & 0xFF;
2990 CDB[7] = (io->size >> 8) & 0xFF;
2991 CDB[8] = io->size & 0xFF;
2992 cmdTimeout = 10;
2993 break;
2994
2995 case WRITE_BUFFER:
2996 cmdLen = 10;
2997 dir = MPI_SCSIIO_CONTROL_WRITE;
2998 CDB[0] = cmd;
2999 if (io->flags & MPT_ICFLAG_ECHO) {
3000 CDB[1] = 0x0A;
3001 } else {
3002 CDB[1] = 0x02;
3003 }
3004 CDB[6] = (io->size >> 16) & 0xFF;
3005 CDB[7] = (io->size >> 8) & 0xFF;
3006 CDB[8] = io->size & 0xFF;
3007 cmdTimeout = 10;
3008 break;
3009
3010 case RESERVE:
3011 cmdLen = 6;
3012 dir = MPI_SCSIIO_CONTROL_READ;
3013 CDB[0] = cmd;
3014 cmdTimeout = 10;
3015 break;
3016
3017 case RELEASE:
3018 cmdLen = 6;
3019 dir = MPI_SCSIIO_CONTROL_READ;
3020 CDB[0] = cmd;
3021 cmdTimeout = 10;
3022 break;
3023
3024 case SYNCHRONIZE_CACHE:
3025 cmdLen = 10;
3026 dir = MPI_SCSIIO_CONTROL_READ;
3027 CDB[0] = cmd;
3028// CDB[1] = 0x02; /* set immediate bit */
3029 cmdTimeout = 10;
3030 break;
3031
3032 default:
3033 /* Error Case */
3034 return -EFAULT;
3035 }
3036
3037 /* Get and Populate a free Frame
3038 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003039 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3041 hd->ioc->name));
3042 return -EBUSY;
3043 }
3044
3045 pScsiReq = (SCSIIORequest_t *) mf;
3046
3047 /* Get the request index */
3048 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3049 ADD_INDEX_LOG(my_idx); /* for debug */
3050
3051 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3052 pScsiReq->TargetID = io->physDiskNum;
3053 pScsiReq->Bus = 0;
3054 pScsiReq->ChainOffset = 0;
3055 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3056 } else {
3057 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003058 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 pScsiReq->ChainOffset = 0;
3060 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3061 }
3062
3063 pScsiReq->CDBLength = cmdLen;
3064 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3065
3066 pScsiReq->Reserved = 0;
3067
3068 pScsiReq->MsgFlags = mpt_msg_flags();
3069 /* MsgContext set in mpt_get_msg_fram call */
3070
Eric Moore793955f2007-01-29 09:42:20 -07003071 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
3073 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3074 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3075 else
3076 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3077
3078 if (cmd == REQUEST_SENSE) {
3079 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3080 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3081 hd->ioc->name, cmd));
3082 }
3083
3084 for (ii=0; ii < 16; ii++)
3085 pScsiReq->CDB[ii] = CDB[ii];
3086
3087 pScsiReq->DataLength = cpu_to_le32(io->size);
3088 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3089 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3090
3091 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003092 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
3094 if (dir == MPI_SCSIIO_CONTROL_READ) {
3095 mpt_add_sge((char *) &pScsiReq->SGL,
3096 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3097 io->data_dma);
3098 } else {
3099 mpt_add_sge((char *) &pScsiReq->SGL,
3100 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3101 io->data_dma);
3102 }
3103
3104 /* The ISR will free the request frame, but we need
3105 * the information to initialize the target. Duplicate.
3106 */
3107 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3108
3109 /* Issue this command after:
3110 * finish init
3111 * add timer
3112 * Wait until the reply has been received
3113 * ScsiScanDvCtx callback function will
3114 * set hd->pLocal;
3115 * set scandv_wait_done and call wake_up
3116 */
3117 hd->pLocal = NULL;
3118 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003119 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121 /* Save cmd pointer, for resource free if timeout or
3122 * FW reload occurs
3123 */
3124 hd->cmdPtr = mf;
3125
3126 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003127 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3128 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129
3130 if (hd->pLocal) {
3131 rc = hd->pLocal->completion;
3132 hd->pLocal->skip = 0;
3133
3134 /* Always set fatal error codes in some cases.
3135 */
3136 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3137 rc = -ENXIO;
3138 else if (rc == MPT_SCANDV_SOME_ERROR)
3139 rc = -rc;
3140 } else {
3141 rc = -EFAULT;
3142 /* This should never happen. */
3143 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3144 hd->ioc->name));
3145 }
3146
3147 return rc;
3148}
3149
3150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3151/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003152 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3153 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003154 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003155 *
3156 * Uses the ISR, but with special processing.
3157 * MUST be single-threaded.
3158 *
3159 */
3160static void
3161mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3162{
3163 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
3165 /* Following parameters will not change
3166 * in this routine.
3167 */
3168 iocmd.cmd = SYNCHRONIZE_CACHE;
3169 iocmd.flags = 0;
3170 iocmd.physDiskNum = -1;
3171 iocmd.data = NULL;
3172 iocmd.data_dma = -1;
3173 iocmd.size = 0;
3174 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003175 iocmd.channel = vdevice->vtarget->channel;
3176 iocmd.id = vdevice->vtarget->id;
3177 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
James Bottomleyc92f2222006-03-01 09:02:49 -06003179 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003180 (vdevice->configured_lun))
3181 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182}
3183
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003184EXPORT_SYMBOL(mptscsih_remove);
3185EXPORT_SYMBOL(mptscsih_shutdown);
3186#ifdef CONFIG_PM
3187EXPORT_SYMBOL(mptscsih_suspend);
3188EXPORT_SYMBOL(mptscsih_resume);
3189#endif
3190EXPORT_SYMBOL(mptscsih_proc_info);
3191EXPORT_SYMBOL(mptscsih_info);
3192EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003193EXPORT_SYMBOL(mptscsih_slave_destroy);
3194EXPORT_SYMBOL(mptscsih_slave_configure);
3195EXPORT_SYMBOL(mptscsih_abort);
3196EXPORT_SYMBOL(mptscsih_dev_reset);
3197EXPORT_SYMBOL(mptscsih_bus_reset);
3198EXPORT_SYMBOL(mptscsih_host_reset);
3199EXPORT_SYMBOL(mptscsih_bios_param);
3200EXPORT_SYMBOL(mptscsih_io_done);
3201EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3202EXPORT_SYMBOL(mptscsih_scandv_complete);
3203EXPORT_SYMBOL(mptscsih_event_process);
3204EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003205EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003206EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003207EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/