blob: ce58431bee8e13fffb33b8786684f67516bad0d4 [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
James Bottomleyc92f2222006-03-01 09:02:49 -0600102static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
103static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
Eric Moore793955f2007-01-29 09:42:20 -0700104static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int channel, int id);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400105int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700107static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400109void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700110void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400112int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
113int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#endif
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
119/**
120 * mptscsih_add_sge - Place a simple SGE at address pAddr.
121 * @pAddr: virtual address for SGE
122 * @flagslength: SGE flags and data transfer length
123 * @dma_addr: Physical address
124 *
125 * This routine places a MPT request frame back on the MPT adapter's
126 * FreeQ.
127 */
128static inline void
129mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
130{
131 if (sizeof(dma_addr_t) == sizeof(u64)) {
132 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
133 u32 tmp = dma_addr & 0xFFFFFFFF;
134
135 pSge->FlagsLength = cpu_to_le32(flagslength);
136 pSge->Address.Low = cpu_to_le32(tmp);
137 tmp = (u32) ((u64)dma_addr >> 32);
138 pSge->Address.High = cpu_to_le32(tmp);
139
140 } else {
141 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
142 pSge->FlagsLength = cpu_to_le32(flagslength);
143 pSge->Address = cpu_to_le32(dma_addr);
144 }
145} /* mptscsih_add_sge() */
146
147/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
148/**
149 * mptscsih_add_chain - Place a chain SGE at address pAddr.
150 * @pAddr: virtual address for SGE
151 * @next: nextChainOffset value (u32's)
152 * @length: length of next SGL segment
153 * @dma_addr: Physical address
154 *
155 * This routine places a MPT request frame back on the MPT adapter's
156 * FreeQ.
157 */
158static inline void
159mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
160{
161 if (sizeof(dma_addr_t) == sizeof(u64)) {
162 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
163 u32 tmp = dma_addr & 0xFFFFFFFF;
164
165 pChain->Length = cpu_to_le16(length);
166 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
167
168 pChain->NextChainOffset = next;
169
170 pChain->Address.Low = cpu_to_le32(tmp);
171 tmp = (u32) ((u64)dma_addr >> 32);
172 pChain->Address.High = cpu_to_le32(tmp);
173 } else {
174 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
175 pChain->Length = cpu_to_le16(length);
176 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
177 pChain->NextChainOffset = next;
178 pChain->Address = cpu_to_le32(dma_addr);
179 }
180} /* mptscsih_add_chain() */
181
182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
183/*
184 * mptscsih_getFreeChainBuffer - Function to get a free chain
185 * from the MPT_SCSI_HOST FreeChainQ.
186 * @ioc: Pointer to MPT_ADAPTER structure
187 * @req_idx: Index of the SCSI IO request frame. (output)
188 *
189 * return SUCCESS or FAILED
190 */
191static inline int
192mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
193{
194 MPT_FRAME_HDR *chainBuf;
195 unsigned long flags;
196 int rc;
197 int chain_idx;
198
199 dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
200 ioc->name));
201 spin_lock_irqsave(&ioc->FreeQlock, flags);
202 if (!list_empty(&ioc->FreeChainQ)) {
203 int offset;
204
205 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
206 u.frame.linkage.list);
207 list_del(&chainBuf->u.frame.linkage.list);
208 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
209 chain_idx = offset / ioc->req_sz;
210 rc = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200211 dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
212 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 } else {
214 rc = FAILED;
215 chain_idx = MPT_HOST_NO_CHAIN;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200216 dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 ioc->name));
218 }
219 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
220
221 *retIndex = chain_idx;
222 return rc;
223} /* mptscsih_getFreeChainBuffer() */
224
225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
226/*
227 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
228 * SCSIIORequest_t Message Frame.
229 * @ioc: Pointer to MPT_ADAPTER structure
230 * @SCpnt: Pointer to scsi_cmnd structure
231 * @pReq: Pointer to SCSIIORequest_t structure
232 *
233 * Returns ...
234 */
235static int
236mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
237 SCSIIORequest_t *pReq, int req_idx)
238{
239 char *psge;
240 char *chainSge;
241 struct scatterlist *sg;
242 int frm_sz;
243 int sges_left, sg_done;
244 int chain_idx = MPT_HOST_NO_CHAIN;
245 int sgeOffset;
246 int numSgeSlots, numSgeThisFrame;
247 u32 sgflags, sgdir, thisxfer = 0;
248 int chain_dma_off = 0;
249 int newIndex;
250 int ii;
251 dma_addr_t v2;
252 u32 RequestNB;
253
254 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
255 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
256 sgdir = MPT_TRANSFER_HOST_TO_IOC;
257 } else {
258 sgdir = MPT_TRANSFER_IOC_TO_HOST;
259 }
260
261 psge = (char *) &pReq->SGL;
262 frm_sz = ioc->req_sz;
263
264 /* Map the data portion, if any.
265 * sges_left = 0 if no data transfer.
266 */
267 if ( (sges_left = SCpnt->use_sg) ) {
268 sges_left = pci_map_sg(ioc->pcidev,
269 (struct scatterlist *) SCpnt->request_buffer,
270 SCpnt->use_sg,
271 SCpnt->sc_data_direction);
272 if (sges_left == 0)
273 return FAILED;
274 } else if (SCpnt->request_bufflen) {
275 SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
276 SCpnt->request_buffer,
277 SCpnt->request_bufflen,
278 SCpnt->sc_data_direction);
279 dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
280 ioc->name, SCpnt, SCpnt->request_bufflen));
281 mptscsih_add_sge((char *) &pReq->SGL,
282 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
283 SCpnt->SCp.dma_handle);
284
285 return SUCCESS;
286 }
287
288 /* Handle the SG case.
289 */
290 sg = (struct scatterlist *) SCpnt->request_buffer;
291 sg_done = 0;
292 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
293 chainSge = NULL;
294
295 /* Prior to entering this loop - the following must be set
296 * current MF: sgeOffset (bytes)
297 * chainSge (Null if original MF is not a chain buffer)
298 * sg_done (num SGE done for this MF)
299 */
300
301nextSGEset:
302 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
303 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
304
305 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
306
307 /* Get first (num - 1) SG elements
308 * Skip any SG entries with a length of 0
309 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
310 */
311 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
312 thisxfer = sg_dma_len(sg);
313 if (thisxfer == 0) {
314 sg ++; /* Get next SG element from the OS */
315 sg_done++;
316 continue;
317 }
318
319 v2 = sg_dma_address(sg);
320 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
321
322 sg++; /* Get next SG element from the OS */
323 psge += (sizeof(u32) + sizeof(dma_addr_t));
324 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
325 sg_done++;
326 }
327
328 if (numSgeThisFrame == sges_left) {
329 /* Add last element, end of buffer and end of list flags.
330 */
331 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
332 MPT_SGE_FLAGS_END_OF_BUFFER |
333 MPT_SGE_FLAGS_END_OF_LIST;
334
335 /* Add last SGE and set termination flags.
336 * Note: Last SGE may have a length of 0 - which should be ok.
337 */
338 thisxfer = sg_dma_len(sg);
339
340 v2 = sg_dma_address(sg);
341 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
342 /*
343 sg++;
344 psge += (sizeof(u32) + sizeof(dma_addr_t));
345 */
346 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
347 sg_done++;
348
349 if (chainSge) {
350 /* The current buffer is a chain buffer,
351 * but there is not another one.
352 * Update the chain element
353 * Offset and Length fields.
354 */
355 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
356 } else {
357 /* The current buffer is the original MF
358 * and there is no Chain buffer.
359 */
360 pReq->ChainOffset = 0;
361 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200362 dsgprintk((MYIOC_s_INFO_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
364 ioc->RequestNB[req_idx] = RequestNB;
365 }
366 } else {
367 /* At least one chain buffer is needed.
368 * Complete the first MF
369 * - last SGE element, set the LastElement bit
370 * - set ChainOffset (words) for orig MF
371 * (OR finish previous MF chain buffer)
372 * - update MFStructPtr ChainIndex
373 * - Populate chain element
374 * Also
375 * Loop until done.
376 */
377
378 dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
379 ioc->name, sg_done));
380
381 /* Set LAST_ELEMENT flag for last non-chain element
382 * in the buffer. Since psge points at the NEXT
383 * SGE element, go back one SGE element, update the flags
384 * and reset the pointer. (Note: sgflags & thisxfer are already
385 * set properly).
386 */
387 if (sg_done) {
388 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
389 sgflags = le32_to_cpu(*ptmp);
390 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
391 *ptmp = cpu_to_le32(sgflags);
392 }
393
394 if (chainSge) {
395 /* The current buffer is a chain buffer.
396 * chainSge points to the previous Chain Element.
397 * Update its chain element Offset and Length (must
398 * include chain element size) fields.
399 * Old chain element is now complete.
400 */
401 u8 nextChain = (u8) (sgeOffset >> 2);
402 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
403 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
404 } else {
405 /* The original MF buffer requires a chain buffer -
406 * set the offset.
407 * Last element in this MF is a chain element.
408 */
409 pReq->ChainOffset = (u8) (sgeOffset >> 2);
410 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
411 dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
412 ioc->RequestNB[req_idx] = RequestNB;
413 }
414
415 sges_left -= sg_done;
416
417
418 /* NOTE: psge points to the beginning of the chain element
419 * in current buffer. Get a chain buffer.
420 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200421 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
422 dfailprintk((MYIOC_s_INFO_FMT
423 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
424 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 /* Update the tracking arrays.
429 * If chainSge == NULL, update ReqToChain, else ChainToChain
430 */
431 if (chainSge) {
432 ioc->ChainToChain[chain_idx] = newIndex;
433 } else {
434 ioc->ReqToChain[req_idx] = newIndex;
435 }
436 chain_idx = newIndex;
437 chain_dma_off = ioc->req_sz * chain_idx;
438
439 /* Populate the chainSGE for the current buffer.
440 * - Set chain buffer pointer to psge and fill
441 * out the Address and Flags fields.
442 */
443 chainSge = (char *) psge;
444 dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
445 psge, req_idx));
446
447 /* Start the SGE for the next buffer
448 */
449 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
450 sgeOffset = 0;
451 sg_done = 0;
452
453 dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
454 psge, chain_idx));
455
456 /* Start the SGE for the next buffer
457 */
458
459 goto nextSGEset;
460 }
461
462 return SUCCESS;
463} /* mptscsih_AddSGE() */
464
Eric Moore786899b2006-07-11 17:22:22 -0600465static void
466mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
467 U32 SlotStatus)
468{
469 MPT_FRAME_HDR *mf;
470 SEPRequest_t *SEPMsg;
471
472 if (ioc->bus_type == FC)
473 return;
474
475 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
476 dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
477 ioc->name,__FUNCTION__));
478 return;
479 }
480
481 SEPMsg = (SEPRequest_t *)mf;
482 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700483 SEPMsg->Bus = vtarget->channel;
484 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600485 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
486 SEPMsg->SlotStatus = SlotStatus;
487 devtverboseprintk((MYIOC_s_WARN_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700488 "Sending SEP cmd=%x channel=%d id=%d\n",
489 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600490 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
491}
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
494/*
495 * mptscsih_io_done - Main SCSI IO callback routine registered to
496 * Fusion MPT (base) driver
497 * @ioc: Pointer to MPT_ADAPTER structure
498 * @mf: Pointer to original MPT request frame
499 * @r: Pointer to MPT reply frame (NULL if TurboReply)
500 *
501 * This routine is called from mpt.c::mpt_interrupt() at the completion
502 * of any SCSI IO request.
503 * This routine is registered with the Fusion MPT (base) driver at driver
504 * load/init time via the mpt_register() API call.
505 *
506 * Returns 1 indicating alloc'd request frame ptr should be freed.
507 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400508int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
510{
511 struct scsi_cmnd *sc;
512 MPT_SCSI_HOST *hd;
513 SCSIIORequest_t *pScsiReq;
514 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700515 u16 req_idx, req_idx_MR;
Eric Moore786899b2006-07-11 17:22:22 -0600516 VirtDevice *vdev;
517 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
520
521 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700522 req_idx_MR = (mr != NULL) ?
523 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
524 if ((req_idx != req_idx_MR) ||
525 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
526 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
527 ioc->name);
528 printk (MYIOC_s_ERR_FMT
529 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
530 ioc->name, req_idx, req_idx_MR, mf, mr,
531 hd->ScsiLookup[req_idx_MR]);
532 return 0;
533 }
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600536 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 if (sc == NULL) {
538 MPIHeader_t *hdr = (MPIHeader_t *)mf;
539
540 /* Remark: writeSDP1 will use the ScsiDoneCtx
541 * If a SCSI I/O cmd, device disabled by OS and
542 * completion done. Cannot touch sc struct. Just free mem.
543 */
544 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
545 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
546 ioc->name);
547
548 mptscsih_freeChainBuffers(ioc, req_idx);
549 return 1;
550 }
551
Eric Moore3dc0b032006-07-11 17:32:33 -0600552 if ((unsigned char *)mf != sc->host_scribble) {
553 mptscsih_freeChainBuffers(ioc, req_idx);
554 return 1;
555 }
556
557 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 sc->result = DID_OK << 16; /* Set default reply as OK */
559 pScsiReq = (SCSIIORequest_t *) mf;
560 pScsiReply = (SCSIIOReply_t *) mr;
561
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200562 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
563 dmfprintk((MYIOC_s_INFO_FMT
564 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
565 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
566 }else{
567 dmfprintk((MYIOC_s_INFO_FMT
568 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
569 ioc->name, mf, mr, sc, req_idx));
570 }
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 if (pScsiReply == NULL) {
573 /* special context reply handling */
574 ;
575 } else {
576 u32 xfer_cnt;
577 u16 status;
578 u8 scsi_state, scsi_status;
579
580 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
581 scsi_state = pScsiReply->SCSIState;
582 scsi_status = pScsiReply->SCSIStatus;
583 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
584 sc->resid = sc->request_bufflen - xfer_cnt;
585
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600586 /*
587 * if we get a data underrun indication, yet no data was
588 * transferred and the SCSI status indicates that the
589 * command was never started, change the data underrun
590 * to success
591 */
592 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
593 (scsi_status == MPI_SCSI_STATUS_BUSY ||
594 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
595 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
596 status = MPI_IOCSTATUS_SUCCESS;
597 }
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
600 "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
601 "resid=%d bufflen=%d xfer_cnt=%d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700602 ioc->id, sc->device->id, sc->device->lun,
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600603 status, scsi_state, scsi_status, sc->resid,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 sc->request_bufflen, xfer_cnt));
605
606 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400607 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 /*
610 * Look for + dump FCP ResponseInfo[]!
611 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600612 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
613 pScsiReply->ResponseInfo) {
614 printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
615 "FCP_ResponseInfo=%08xh\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700616 ioc->id, sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 le32_to_cpu(pScsiReply->ResponseInfo));
618 }
619
620 switch(status) {
621 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
622 /* CHECKME!
623 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
624 * But not: DID_BUS_BUSY lest one risk
625 * killing interrupt handler:-(
626 */
627 sc->result = SAM_STAT_BUSY;
628 break;
629
630 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
631 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
632 sc->result = DID_BAD_TARGET << 16;
633 break;
634
635 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
636 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600637 if (ioc->bus_type != FC)
638 sc->result = DID_NO_CONNECT << 16;
639 /* else fibre, just stall until rescan event */
640 else
641 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
644 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600645
646 vdev = sc->device->hostdata;
647 if (!vdev)
648 break;
649 vtarget = vdev->vtarget;
650 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
651 mptscsih_issue_sep_command(ioc, vtarget,
652 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
653 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 break;
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600658 if ( ioc->bus_type == SAS ) {
659 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
660 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
661 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
662 log_info &=SAS_LOGINFO_MASK;
663 if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
664 sc->result = (DID_BUS_BUSY << 16);
665 break;
666 }
667 }
Eric Moore86dd4242007-01-04 20:44:01 -0700668 } else if (ioc->bus_type == FC) {
669 /*
670 * The FC IOC may kill a request for variety of
671 * reasons, some of which may be recovered by a
672 * retry, some which are unlikely to be
673 * recovered. Return DID_ERROR instead of
674 * DID_RESET to permit retry of the command,
675 * just not an infinite number of them
676 */
677 sc->result = DID_ERROR << 16;
678 break;
Eric Moorebf451522006-07-11 17:25:35 -0600679 }
680
681 /*
682 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
683 */
684
685 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
687 /* Linux handles an unsolicited DID_RESET better
688 * than an unsolicited DID_ABORT.
689 */
690 sc->result = DID_RESET << 16;
691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 break;
693
694 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600695 sc->resid = sc->request_bufflen - xfer_cnt;
696 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
697 sc->result=DID_SOFT_ERROR << 16;
698 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore3dc0b032006-07-11 17:32:33 -0600700 dreplyprintk((KERN_NOTICE
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600701 "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
705 /*
706 * Do upfront check for valid SenseData and give it
707 * precedence!
708 */
709 sc->result = (DID_OK << 16) | scsi_status;
710 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
711 /* Have already saved the status and sense data
712 */
713 ;
714 } else {
715 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600716 if (scsi_status == SAM_STAT_BUSY)
717 sc->result = SAM_STAT_BUSY;
718 else
719 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
722 /* What to do?
723 */
724 sc->result = DID_SOFT_ERROR << 16;
725 }
726 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
727 /* Not real sure here either... */
728 sc->result = DID_RESET << 16;
729 }
730 }
731
732 dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
733 sc->underflow));
734 dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
735 /* Report Queue Full
736 */
737 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
738 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 break;
741
Moore, Eric7e551472006-01-16 18:53:21 -0700742 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
743 sc->resid=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
745 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600746 if (scsi_status == MPI_SCSI_STATUS_BUSY)
747 sc->result = (DID_BUS_BUSY << 16) | scsi_status;
748 else
749 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (scsi_state == 0) {
751 ;
752 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
753 /*
754 * If running against circa 200003dd 909 MPT f/w,
755 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
756 * (QUEUE_FULL) returned from device! --> get 0x0000?128
757 * and with SenseBytes set to 0.
758 */
759 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
760 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
761
762 }
763 else if (scsi_state &
764 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
765 ) {
766 /*
767 * What to do?
768 */
769 sc->result = DID_SOFT_ERROR << 16;
770 }
771 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
772 /* Not real sure here either... */
773 sc->result = DID_RESET << 16;
774 }
775 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
776 /* Device Inq. data indicates that it supports
777 * QTags, but rejects QTag messages.
778 * This command completed OK.
779 *
780 * Not real sure here either so do nothing... */
781 }
782
783 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
784 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
785
786 /* Add handling of:
787 * Reservation Conflict, Busy,
788 * Command Terminated, CHECK
789 */
790 break;
791
792 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
793 sc->result = DID_SOFT_ERROR << 16;
794 break;
795
796 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
797 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
798 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
799 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
800 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
801 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
802 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
804 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
805 default:
806 /*
807 * What to do?
808 */
809 sc->result = DID_SOFT_ERROR << 16;
810 break;
811
812 } /* switch(status) */
813
814 dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
815 } /* end of address reply case */
816
817 /* Unmap the DMA buffers, if any. */
818 if (sc->use_sg) {
819 pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
820 sc->use_sg, sc->sc_data_direction);
821 } else if (sc->request_bufflen) {
822 pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
823 sc->request_bufflen, sc->sc_data_direction);
824 }
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 sc->scsi_done(sc); /* Issue the command callback */
827
828 /* Free Chain buffers */
829 mptscsih_freeChainBuffers(ioc, req_idx);
830 return 1;
831}
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833/*
834 * mptscsih_flush_running_cmds - For each command found, search
835 * Scsi_Host instance taskQ and reply to OS.
836 * Called only if recovering from a FW reload.
837 * @hd: Pointer to a SCSI HOST structure
838 *
839 * Returns: None.
840 *
841 * Must be called while new I/Os are being queued.
842 */
843static void
844mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
845{
846 MPT_ADAPTER *ioc = hd->ioc;
847 struct scsi_cmnd *SCpnt;
848 MPT_FRAME_HDR *mf;
849 int ii;
850 int max = ioc->req_depth;
851
852 dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
853 for (ii= 0; ii < max; ii++) {
854 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
855
856 /* Command found.
857 */
858
859 /* Null ScsiLookup index
860 */
861 hd->ScsiLookup[ii] = NULL;
862
863 mf = MPT_INDEX_2_MFPTR(ioc, ii);
864 dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
865 mf, SCpnt));
866
Eric Moore3dc0b032006-07-11 17:32:33 -0600867 /* Free Chain buffers */
868 mptscsih_freeChainBuffers(ioc, ii);
869
870 /* Free Message frames */
871 mpt_free_msg_frame(ioc, mf);
872
873 if ((unsigned char *)mf != SCpnt->host_scribble)
874 continue;
875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 /* Set status, free OS resources (SG DMA buffers)
877 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400879 if (SCpnt->use_sg) {
880 pci_unmap_sg(ioc->pcidev,
881 (struct scatterlist *) SCpnt->request_buffer,
882 SCpnt->use_sg,
883 SCpnt->sc_data_direction);
884 } else if (SCpnt->request_bufflen) {
885 pci_unmap_single(ioc->pcidev,
886 SCpnt->SCp.dma_handle,
887 SCpnt->request_bufflen,
888 SCpnt->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 }
890 SCpnt->result = DID_RESET << 16;
891 SCpnt->host_scribble = NULL;
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
894 }
895 }
896
897 return;
898}
899
900/*
901 * mptscsih_search_running_cmds - Delete any commands associated
902 * with the specified target and lun. Function called only
903 * when a lun is disable by mid-layer.
904 * Do NOT access the referenced scsi_cmnd structure or
905 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600906 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700907 * @hd: Pointer to a SCSI HOST structure
908 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 *
910 * Returns: None.
911 *
912 * Called from slave_destroy.
913 */
914static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700915mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
917 SCSIIORequest_t *mf = NULL;
918 int ii;
919 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600920 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700921 struct scsi_lun lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Eric Moore793955f2007-01-29 09:42:20 -0700923 dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
924 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600927 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600930 if (mf == NULL)
931 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700932 int_to_scsilun(vdevice->lun, &lun);
933 if ((mf->Bus != vdevice->vtarget->channel) ||
934 (mf->TargetID != vdevice->vtarget->id) ||
935 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700937 dsprintk(( "search_running: found (sc=%p, mf = %p) "
938 "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
939 mf, mf->Bus, mf->TargetID, vdevice->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 /* Cleanup
942 */
943 hd->ScsiLookup[ii] = NULL;
944 mptscsih_freeChainBuffers(hd->ioc, ii);
945 mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -0600946 if ((unsigned char *)mf != sc->host_scribble)
947 continue;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600948 if (sc->use_sg) {
949 pci_unmap_sg(hd->ioc->pcidev,
950 (struct scatterlist *) sc->request_buffer,
951 sc->use_sg,
952 sc->sc_data_direction);
953 } else if (sc->request_bufflen) {
954 pci_unmap_single(hd->ioc->pcidev,
955 sc->SCp.dma_handle,
956 sc->request_bufflen,
957 sc->sc_data_direction);
958 }
959 sc->host_scribble = NULL;
960 sc->result = DID_NO_CONNECT << 16;
961 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 }
963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return;
965}
966
967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
969/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
970/*
971 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
972 * from a SCSI target device.
973 * @sc: Pointer to scsi_cmnd structure
974 * @pScsiReply: Pointer to SCSIIOReply_t
975 * @pScsiReq: Pointer to original SCSI request
976 *
977 * This routine periodically reports QUEUE_FULL status returned from a
978 * SCSI target device. It reports this to the console via kernel
979 * printk() API call, not more than once every 10 seconds.
980 */
981static void
982mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
983{
984 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400987 if (sc->device == NULL)
988 return;
989 if (sc->device->host == NULL)
990 return;
991 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
992 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400994 if (time - hd->last_queue_full > 10 * HZ) {
995 dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
996 hd->ioc->name, 0, sc->device->id, sc->device->lun));
997 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999}
1000
1001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1002/*
1003 * mptscsih_remove - Removed scsi devices
1004 * @pdev: Pointer to pci_dev structure
1005 *
1006 *
1007 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001008void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009mptscsih_remove(struct pci_dev *pdev)
1010{
1011 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1012 struct Scsi_Host *host = ioc->sh;
1013 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001014 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001016 if(!host) {
1017 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021 scsi_remove_host(host);
1022
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001023 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1024 return;
1025
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001026 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001028 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001030 if (hd->ScsiLookup != NULL) {
1031 sz1 = hd->ioc->req_depth * sizeof(void *);
1032 kfree(hd->ScsiLookup);
1033 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 }
1035
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001036 dprintk((MYIOC_s_INFO_FMT
1037 "Free'd ScsiLookup (%d) memory\n",
1038 hd->ioc->name, sz1));
1039
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001040 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001041
1042 /* NULL the Scsi_Host pointer
1043 */
1044 hd->ioc->sh = NULL;
1045
1046 scsi_host_put(host);
1047
1048 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050}
1051
1052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1053/*
1054 * mptscsih_shutdown - reboot notifier
1055 *
1056 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001057void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001058mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001060 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 struct Scsi_Host *host = ioc->sh;
1062 MPT_SCSI_HOST *hd;
1063
1064 if(!host)
1065 return;
1066
1067 hd = (MPT_SCSI_HOST *)host->hostdata;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
1071#ifdef CONFIG_PM
1072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1073/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001074 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 *
1076 *
1077 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001078int
Pavel Machek8d189f72005-04-16 15:25:28 -07001079mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001081 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001082 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083}
1084
1085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1086/*
1087 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1088 *
1089 *
1090 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001091int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092mptscsih_resume(struct pci_dev *pdev)
1093{
1094 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1095 struct Scsi_Host *host = ioc->sh;
1096 MPT_SCSI_HOST *hd;
1097
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001098 mpt_resume(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 if(!host)
1101 return 0;
1102
1103 hd = (MPT_SCSI_HOST *)host->hostdata;
1104 if(!hd)
1105 return 0;
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return 0;
1108}
1109
1110#endif
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1113/**
1114 * mptscsih_info - Return information about MPT adapter
1115 * @SChost: Pointer to Scsi_Host structure
1116 *
1117 * (linux scsi_host_template.info routine)
1118 *
1119 * Returns pointer to buffer where information was written.
1120 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001121const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122mptscsih_info(struct Scsi_Host *SChost)
1123{
1124 MPT_SCSI_HOST *h;
1125 int size = 0;
1126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001130 if (h->info_kbuf == NULL)
1131 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1132 return h->info_kbuf;
1133 h->info_kbuf[0] = '\0';
1134
1135 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1136 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001139 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140}
1141
1142struct info_str {
1143 char *buffer;
1144 int length;
1145 int offset;
1146 int pos;
1147};
1148
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001149static void
1150mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
1152 if (info->pos + len > info->length)
1153 len = info->length - info->pos;
1154
1155 if (info->pos + len < info->offset) {
1156 info->pos += len;
1157 return;
1158 }
1159
1160 if (info->pos < info->offset) {
1161 data += (info->offset - info->pos);
1162 len -= (info->offset - info->pos);
1163 }
1164
1165 if (len > 0) {
1166 memcpy(info->buffer + info->pos, data, len);
1167 info->pos += len;
1168 }
1169}
1170
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001171static int
1172mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
1174 va_list args;
1175 char buf[81];
1176 int len;
1177
1178 va_start(args, fmt);
1179 len = vsprintf(buf, fmt, args);
1180 va_end(args);
1181
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001182 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return len;
1184}
1185
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001186static int
1187mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
1189 struct info_str info;
1190
1191 info.buffer = pbuf;
1192 info.length = len;
1193 info.offset = offset;
1194 info.pos = 0;
1195
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1197 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1198 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1199 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1202}
1203
1204/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1205/**
1206 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * @host: scsi host struct
1208 * @buffer: if write, user data; if read, buffer for user
1209 * @start: returns the buffer address
1210 * @offset: if write, 0; if read, the current offset into the buffer from
1211 * the previous read.
1212 * @length: if write, return length;
1213 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 *
1215 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001217int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1219 int length, int func)
1220{
1221 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1222 MPT_ADAPTER *ioc = hd->ioc;
1223 int size = 0;
1224
1225 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001226 /*
1227 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 */
1229 } else {
1230 if (start)
1231 *start = buffer;
1232
1233 size = mptscsih_host_info(ioc, buffer, offset, length);
1234 }
1235
1236 return size;
1237}
1238
1239/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1240#define ADD_INDEX_LOG(req_ent) do { } while(0)
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1245 * @SCpnt: Pointer to scsi_cmnd structure
1246 * @done: Pointer SCSI mid-layer IO completion function
1247 *
1248 * (linux scsi_host_template.queuecommand routine)
1249 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1250 * from a linux scsi_cmnd request and send it to the IOC.
1251 *
1252 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1253 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001254int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1256{
1257 MPT_SCSI_HOST *hd;
1258 MPT_FRAME_HDR *mf;
1259 SCSIIORequest_t *pScsiReq;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001260 VirtDevice *vdev = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 int lun;
1262 u32 datalen;
1263 u32 scsictl;
1264 u32 scsidir;
1265 u32 cmd_len;
1266 int my_idx;
1267 int ii;
1268
1269 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 lun = SCpnt->device->lun;
1271 SCpnt->scsi_done = done;
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
1274 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
1275
1276 if (hd->resetPending) {
1277 dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1278 (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
1279 return SCSI_MLQUEUE_HOST_BUSY;
1280 }
1281
1282 /*
1283 * Put together a MPT SCSI request...
1284 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001285 if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1287 hd->ioc->name));
1288 return SCSI_MLQUEUE_HOST_BUSY;
1289 }
1290
1291 pScsiReq = (SCSIIORequest_t *) mf;
1292
1293 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1294
1295 ADD_INDEX_LOG(my_idx);
1296
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001297 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 * Seems we may receive a buffer (datalen>0) even when there
1299 * will be no data transfer! GRRRRR...
1300 */
1301 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
1302 datalen = SCpnt->request_bufflen;
1303 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1304 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
1305 datalen = SCpnt->request_bufflen;
1306 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1307 } else {
1308 datalen = 0;
1309 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1310 }
1311
1312 /* Default to untagged. Once a target structure has been allocated,
1313 * use the Inquiry data to determine if device supports tagged.
1314 */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001315 if (vdev
1316 && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 && (SCpnt->device->tagged_supported)) {
1318 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1319 } else {
1320 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1321 }
1322
1323 /* Use the above information to set up the message frame
1324 */
Eric Moore793955f2007-01-29 09:42:20 -07001325 pScsiReq->TargetID = (u8) vdev->vtarget->id;
1326 pScsiReq->Bus = vdev->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 pScsiReq->ChainOffset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06001328 if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
1329 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1330 else
1331 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 pScsiReq->CDBLength = SCpnt->cmd_len;
1333 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1334 pScsiReq->Reserved = 0;
1335 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001336 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pScsiReq->Control = cpu_to_le32(scsictl);
1338
1339 /*
1340 * Write SCSI CDB into the message
1341 */
1342 cmd_len = SCpnt->cmd_len;
1343 for (ii=0; ii < cmd_len; ii++)
1344 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1345
1346 for (ii=cmd_len; ii < 16; ii++)
1347 pScsiReq->CDB[ii] = 0;
1348
1349 /* DataLength */
1350 pScsiReq->DataLength = cpu_to_le32(datalen);
1351
1352 /* SenseBuffer low address */
1353 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
1354 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1355
1356 /* Now add the SG list
1357 * Always have a SGE even if null length.
1358 */
1359 if (datalen == 0) {
1360 /* Add a NULL SGE */
1361 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1362 (dma_addr_t) -1);
1363 } else {
1364 /* Add a 32 or 64 bit SGE */
1365 if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
1366 goto fail;
1367 }
1368
Eric Moore3dc0b032006-07-11 17:32:33 -06001369 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001372 mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1374 hd->ioc->name, SCpnt, mf, my_idx));
1375 DBG_DUMP_REQUEST_FRAME(mf)
1376 return 0;
1377
1378 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001379 hd->ScsiLookup[my_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 mptscsih_freeChainBuffers(hd->ioc, my_idx);
1381 mpt_free_msg_frame(hd->ioc, mf);
1382 return SCSI_MLQUEUE_HOST_BUSY;
1383}
1384
1385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1386/*
1387 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1388 * with a SCSI IO request
1389 * @hd: Pointer to the MPT_SCSI_HOST instance
1390 * @req_idx: Index of the SCSI IO request frame.
1391 *
1392 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1393 * No return.
1394 */
1395static void
1396mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1397{
1398 MPT_FRAME_HDR *chain;
1399 unsigned long flags;
1400 int chain_idx;
1401 int next;
1402
1403 /* Get the first chain index and reset
1404 * tracker state.
1405 */
1406 chain_idx = ioc->ReqToChain[req_idx];
1407 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1408
1409 while (chain_idx != MPT_HOST_NO_CHAIN) {
1410
1411 /* Save the next chain buffer index */
1412 next = ioc->ChainToChain[chain_idx];
1413
1414 /* Free this chain buffer and reset
1415 * tracker
1416 */
1417 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1418
1419 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1420 + (chain_idx * ioc->req_sz));
1421
1422 spin_lock_irqsave(&ioc->FreeQlock, flags);
1423 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1424 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1425
1426 dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
1427 ioc->name, chain_idx));
1428
1429 /* handle next */
1430 chain_idx = next;
1431 }
1432 return;
1433}
1434
1435/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1436/*
1437 * Reset Handling
1438 */
1439
1440/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1441/*
1442 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
1443 * Fall through to mpt_HardResetHandler if: not operational, too many
1444 * failed TM requests or handshake failure.
1445 *
1446 * @ioc: Pointer to MPT_ADAPTER structure
1447 * @type: Task Management type
Eric Moore793955f2007-01-29 09:42:20 -07001448 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 * @lun: Logical Unit for reset (if appropriate)
1450 * @ctx2abort: Context for the task to be aborted (if appropriate)
1451 *
1452 * Remark: Currently invoked from a non-interrupt thread (_bh).
1453 *
1454 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1455 * will be active.
1456 *
1457 * Returns 0 for SUCCESS or -1 if FAILED.
1458 */
James Bottomley663e1aa2006-01-29 12:10:24 -06001459int
Eric Moore793955f2007-01-29 09:42:20 -07001460mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
1462 MPT_ADAPTER *ioc;
1463 int rc = -1;
1464 int doTask = 1;
1465 u32 ioc_raw_state;
1466 unsigned long flags;
1467
1468 /* If FW is being reloaded currently, return success to
1469 * the calling function.
1470 */
1471 if (hd == NULL)
1472 return 0;
1473
1474 ioc = hd->ioc;
1475 if (ioc == NULL) {
1476 printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
1477 return FAILED;
1478 }
1479 dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
1480
1481 // SJR - CHECKME - Can we avoid this here?
1482 // (mpt_HardResetHandler has this check...)
1483 spin_lock_irqsave(&ioc->diagLock, flags);
1484 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1485 spin_unlock_irqrestore(&ioc->diagLock, flags);
1486 return FAILED;
1487 }
1488 spin_unlock_irqrestore(&ioc->diagLock, flags);
1489
1490 /* Wait a fixed amount of time for the TM pending flag to be cleared.
1491 * If we time out and not bus reset, then we return a FAILED status to the caller.
1492 * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
1493 * successful. Otherwise, reload the FW.
1494 */
1495 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1496 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001497 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 "Timed out waiting for last TM (%d) to complete! \n",
1499 hd->ioc->name, hd->tmPending));
1500 return FAILED;
1501 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001502 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 "Timed out waiting for last TM (%d) to complete! \n",
1504 hd->ioc->name, hd->tmPending));
1505 return FAILED;
1506 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001507 dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 "Timed out waiting for last TM (%d) to complete! \n",
1509 hd->ioc->name, hd->tmPending));
1510 if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
1511 return FAILED;
1512
1513 doTask = 0;
1514 }
1515 } else {
1516 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1517 hd->tmPending |= (1 << type);
1518 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1519 }
1520
1521 /* Is operational?
1522 */
1523 ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
1524
1525#ifdef MPT_DEBUG_RESET
1526 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1527 printk(MYIOC_s_WARN_FMT
1528 "TM Handler: IOC Not operational(0x%x)!\n",
1529 hd->ioc->name, ioc_raw_state);
1530 }
1531#endif
1532
1533 if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
1534 && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
1535
1536 /* Isse the Task Mgmt request.
1537 */
1538 if (hd->hard_resets < -1)
1539 hd->hard_resets++;
Eric Moore793955f2007-01-29 09:42:20 -07001540 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, ctx2abort, timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 if (rc) {
1542 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
1543 } else {
1544 dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
1545 }
1546 }
1547
1548 /* Only fall through to the HRH if this is a bus reset
1549 */
1550 if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
1551 ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
1552 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1553 hd->ioc->name));
1554 rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1555 }
1556
Eric Moore3dc0b032006-07-11 17:32:33 -06001557 /*
1558 * Check IOCStatus from TM reply message
1559 */
1560 if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
1561 rc = FAILED;
1562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
1564
1565 return rc;
1566}
1567
1568
1569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1570/*
1571 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1572 * @hd: Pointer to MPT_SCSI_HOST structure
1573 * @type: Task Management type
Eric Moore793955f2007-01-29 09:42:20 -07001574 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 * @lun: Logical Unit for reset (if appropriate)
1576 * @ctx2abort: Context for the task to be aborted (if appropriate)
1577 *
1578 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1579 * or a non-interrupt thread. In the former, must not call schedule().
1580 *
1581 * Not all fields are meaningfull for all task types.
1582 *
1583 * Returns 0 for SUCCESS, -999 for "no msg frames",
1584 * else other non-zero value returned.
1585 */
1586static int
Eric Moore793955f2007-01-29 09:42:20 -07001587mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588{
1589 MPT_FRAME_HDR *mf;
1590 SCSITaskMgmt_t *pScsiTm;
1591 int ii;
1592 int retval;
1593
1594 /* Return Fail to calling function if no message frames available.
1595 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001596 if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1598 hd->ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001599 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 }
1601 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
1602 hd->ioc->name, mf));
1603
1604 /* Format the Request
1605 */
1606 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001607 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 pScsiTm->Bus = channel;
1609 pScsiTm->ChainOffset = 0;
1610 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1611
1612 pScsiTm->Reserved = 0;
1613 pScsiTm->TaskType = type;
1614 pScsiTm->Reserved1 = 0;
1615 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1616 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1617
Eric Moore793955f2007-01-29 09:42:20 -07001618 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620 for (ii=0; ii < 7; ii++)
1621 pScsiTm->Reserved2[ii] = 0;
1622
1623 pScsiTm->TaskMsgContext = ctx2abort;
1624
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001625 dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
1626 hd->ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
1628 DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
1629
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001630 if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
1632 CAN_SLEEP)) != 0) {
1633 dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
1634 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1635 hd->ioc, mf));
1636 mpt_free_msg_frame(hd->ioc, mf);
1637 return retval;
1638 }
1639
1640 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
1641 dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
1642 " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
1643 hd->ioc, mf));
1644 mpt_free_msg_frame(hd->ioc, mf);
1645 dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
1646 hd->ioc->name));
1647 retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
1648 }
1649
1650 return retval;
1651}
1652
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001653static int
1654mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1655{
1656 switch (ioc->bus_type) {
1657 case FC:
1658 return 40;
1659 case SAS:
1660 return 10;
1661 case SPI:
1662 default:
1663 return 2;
1664 }
1665}
1666
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1668/**
1669 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1670 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1671 *
1672 * (linux scsi_host_template.eh_abort_handler routine)
1673 *
1674 * Returns SUCCESS or FAILED.
1675 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001676int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677mptscsih_abort(struct scsi_cmnd * SCpnt)
1678{
1679 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 MPT_FRAME_HDR *mf;
1681 u32 ctx2abort;
1682 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001683 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001684 VirtDevice *vdev;
Eric Moore3dc0b032006-07-11 17:32:33 -06001685 ulong sn = SCpnt->serial_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 /* If we can't locate our host adapter structure, return FAILED status.
1688 */
1689 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1690 SCpnt->result = DID_RESET << 16;
1691 SCpnt->scsi_done(SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001692 dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 "Can't locate host! (sc=%p)\n",
1694 SCpnt));
1695 return FAILED;
1696 }
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 /* Find this command
1699 */
1700 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001701 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 * Do OS callback.
1703 */
1704 SCpnt->result = DID_RESET << 16;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001705 dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 "Command not in the active list! (sc=%p)\n",
1707 hd->ioc->name, SCpnt));
1708 return SUCCESS;
1709 }
1710
Moore, Eric65207fe2006-04-21 16:14:35 -06001711 if (hd->resetPending) {
1712 return FAILED;
1713 }
1714
1715 if (hd->timeouts < -1)
1716 hd->timeouts++;
1717
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001718 printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
1719 hd->ioc->name, SCpnt);
1720 scsi_print_command(SCpnt);
1721
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1723 * (the IO to be ABORT'd)
1724 *
1725 * NOTE: Since we do not byteswap MsgContext, we do not
1726 * swap it here either. It is an opaque cookie to
1727 * the controller, so it does not matter. -DaveM
1728 */
1729 mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
1730 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1731
1732 hd->abortSCpnt = SCpnt;
1733
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001734 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001735 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore793955f2007-01-29 09:42:20 -07001736 vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
Moore, Eric65207fe2006-04-21 16:14:35 -06001737 ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Eric Moore3dc0b032006-07-11 17:32:33 -06001739 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
1740 SCpnt->serial_number == sn) {
1741 retval = FAILED;
1742 }
1743
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001744 printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
1745 hd->ioc->name,
1746 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001748 if (retval == 0)
1749 return SUCCESS;
1750
1751 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 hd->tmPending = 0;
1753 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001755 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756}
1757
1758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1759/**
1760 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1761 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1762 *
1763 * (linux scsi_host_template.eh_dev_reset_handler routine)
1764 *
1765 * Returns SUCCESS or FAILED.
1766 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001767int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1769{
1770 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001771 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001772 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 /* If we can't locate our host adapter structure, return FAILED status.
1775 */
1776 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001777 dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 "Can't locate host! (sc=%p)\n",
1779 SCpnt));
1780 return FAILED;
1781 }
1782
1783 if (hd->resetPending)
1784 return FAILED;
1785
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001786 printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001788 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001790 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001791 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -07001792 vdev->vtarget->channel, vdev->vtarget->id,
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001793 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001794
1795 printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
1796 hd->ioc->name,
1797 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1798
1799 if (retval == 0)
1800 return SUCCESS;
1801
1802 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 hd->tmPending = 0;
1804 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001806 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807}
1808
1809/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1810/**
1811 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1812 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1813 *
1814 * (linux scsi_host_template.eh_bus_reset_handler routine)
1815 *
1816 * Returns SUCCESS or FAILED.
1817 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001818int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1820{
1821 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001822 int retval;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001823 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
1825 /* If we can't locate our host adapter structure, return FAILED status.
1826 */
1827 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001828 dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 "Can't locate host! (sc=%p)\n",
1830 SCpnt ) );
1831 return FAILED;
1832 }
1833
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001834 printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 hd->ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001836 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
1838 if (hd->timeouts < -1)
1839 hd->timeouts++;
1840
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001841 vdev = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001842 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moore793955f2007-01-29 09:42:20 -07001843 vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001845 printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
1846 hd->ioc->name,
1847 ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
1848
1849 if (retval == 0)
1850 return SUCCESS;
1851
1852 if(retval != FAILED ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 hd->tmPending = 0;
1854 hd->tmState = TM_STATE_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001856 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857}
1858
1859/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1860/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001861 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1863 *
1864 * (linux scsi_host_template.eh_host_reset_handler routine)
1865 *
1866 * Returns SUCCESS or FAILED.
1867 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001868int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1870{
1871 MPT_SCSI_HOST * hd;
1872 int status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 /* If we can't locate the host to reset, then we failed. */
1875 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001876 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 "Can't locate host! (sc=%p)\n",
1878 SCpnt ) );
1879 return FAILED;
1880 }
1881
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001882 printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 hd->ioc->name, SCpnt);
1884
1885 /* If our attempts to reset the host failed, then return a failed
1886 * status. The host will be taken off line by the SCSI mid-layer.
1887 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
1889 status = FAILED;
1890 } else {
1891 /* Make sure TM pending is cleared and TM state is set to
1892 * NONE.
1893 */
1894 hd->tmPending = 0;
1895 hd->tmState = TM_STATE_NONE;
1896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001898 dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 "Status = %s\n",
1900 (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
1901
1902 return status;
1903}
1904
1905/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1906/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001907 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 * @hd: Pointer to MPT host structure.
1909 *
1910 * Returns {SUCCESS,FAILED}.
1911 */
1912static int
1913mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1914{
1915 unsigned long flags;
1916 int loop_count = 4 * 10; /* Wait 10 seconds */
1917 int status = FAILED;
1918
1919 do {
1920 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1921 if (hd->tmState == TM_STATE_NONE) {
1922 hd->tmState = TM_STATE_IN_PROGRESS;
1923 hd->tmPending = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001925 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 break;
1927 }
1928 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
1929 msleep(250);
1930 } while (--loop_count);
1931
1932 return status;
1933}
1934
1935/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1936/**
1937 * mptscsih_tm_wait_for_completion - wait for completion of TM task
1938 * @hd: Pointer to MPT host structure.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001939 * @timeout: timeout in seconds
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 *
1941 * Returns {SUCCESS,FAILED}.
1942 */
1943static int
1944mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
1945{
1946 unsigned long flags;
1947 int loop_count = 4 * timeout;
1948 int status = FAILED;
1949
1950 do {
1951 spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
1952 if(hd->tmPending == 0) {
1953 status = SUCCESS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001954 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 break;
1956 }
1957 spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05001958 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 } while (--loop_count);
1960
1961 return status;
1962}
1963
1964/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07001965static void
1966mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1967{
1968 char *desc;
1969
1970 switch (response_code) {
1971 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1972 desc = "The task completed.";
1973 break;
1974 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1975 desc = "The IOC received an invalid frame status.";
1976 break;
1977 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1978 desc = "The task type is not supported.";
1979 break;
1980 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1981 desc = "The requested task failed.";
1982 break;
1983 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1984 desc = "The task completed successfully.";
1985 break;
1986 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1987 desc = "The LUN request is invalid.";
1988 break;
1989 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1990 desc = "The task is in the IOC queue and has not been sent to target.";
1991 break;
1992 default:
1993 desc = "unknown";
1994 break;
1995 }
1996 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
1997 ioc->name, response_code, desc);
1998}
1999
2000/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001/**
2002 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2003 * @ioc: Pointer to MPT_ADAPTER structure
2004 * @mf: Pointer to SCSI task mgmt request frame
2005 * @mr: Pointer to SCSI task mgmt reply frame
2006 *
2007 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2008 * of any SCSI task management request.
2009 * This routine is registered with the MPT (base) driver at driver
2010 * load/init time via the mpt_register() API call.
2011 *
2012 * Returns 1 indicating alloc'd request frame ptr should be freed.
2013 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002014int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2016{
2017 SCSITaskMgmtReply_t *pScsiTmReply;
2018 SCSITaskMgmt_t *pScsiTmReq;
2019 MPT_SCSI_HOST *hd;
2020 unsigned long flags;
2021 u16 iocstatus;
2022 u8 tmType;
2023
2024 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
2025 ioc->name, mf, mr));
2026 if (ioc->sh) {
2027 /* Depending on the thread, a timer is activated for
2028 * the TM request. Delete this timer on completion of TM.
2029 * Decrement count of outstanding TM requests.
2030 */
2031 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2032 } else {
2033 dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
2034 ioc->name));
2035 return 1;
2036 }
2037
2038 if (mr == NULL) {
2039 dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
2040 ioc->name, mf));
2041 return 1;
2042 } else {
2043 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2044 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2045
2046 /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
2047 tmType = pScsiTmReq->TaskType;
2048
Moore, Eric9f63bb72006-01-16 18:53:26 -07002049 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2050 pScsiTmReply->ResponseCode)
2051 mptscsih_taskmgmt_response_code(ioc,
2052 pScsiTmReply->ResponseCode);
2053
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
2055 ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
2056 DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
2057
2058 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore3dc0b032006-07-11 17:32:33 -06002059 hd->tm_iocstatus = iocstatus;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
2061 ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
2062 /* Error? (anything non-zero?) */
2063 if (iocstatus) {
2064
2065 /* clear flags and continue.
2066 */
2067 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2068 hd->abortSCpnt = NULL;
2069
2070 /* If an internal command is present
2071 * or the TM failed - reload the FW.
2072 * FC FW may respond FAILED to an ABORT
2073 */
2074 if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
2075 if ((hd->cmdPtr) ||
2076 (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
2077 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2078 printk((KERN_WARNING
2079 " Firmware Reload FAILED!!\n"));
2080 }
2081 }
2082 }
2083 } else {
2084 dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
2085
2086 hd->abortSCpnt = NULL;
2087
2088 }
2089 }
2090
2091 spin_lock_irqsave(&ioc->FreeQlock, flags);
2092 hd->tmPending = 0;
2093 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2094 hd->tmState = TM_STATE_NONE;
2095
2096 return 1;
2097}
2098
2099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2100/*
2101 * This is anyones guess quite frankly.
2102 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002103int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2105 sector_t capacity, int geom[])
2106{
2107 int heads;
2108 int sectors;
2109 sector_t cylinders;
2110 ulong dummy;
2111
2112 heads = 64;
2113 sectors = 32;
2114
2115 dummy = heads * sectors;
2116 cylinders = capacity;
2117 sector_div(cylinders,dummy);
2118
2119 /*
2120 * Handle extended translation size for logical drives
2121 * > 1Gb
2122 */
2123 if ((ulong)capacity >= 0x200000) {
2124 heads = 255;
2125 sectors = 63;
2126 dummy = heads * sectors;
2127 cylinders = capacity;
2128 sector_div(cylinders,dummy);
2129 }
2130
2131 /* return result */
2132 geom[0] = heads;
2133 geom[1] = sectors;
2134 geom[2] = cylinders;
2135
2136 dprintk((KERN_NOTICE
2137 ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
Eric Moore793955f2007-01-29 09:42:20 -07002138 sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
2140 return 0;
2141}
2142
Moore, Ericf44e5462006-03-14 09:14:21 -07002143/* Search IOC page 3 to determine if this is hidden physical disk
2144 *
2145 */
2146int
Eric Moore793955f2007-01-29 09:42:20 -07002147mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002148{
2149 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002150 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002151
Eric Moore793955f2007-01-29 09:42:20 -07002152 if (!ioc->raid_data.pIocPg3)
2153 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002154 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002155 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2156 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2157 rc = 1;
2158 goto out;
2159 }
2160 }
2161
2162 out:
2163 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002164}
2165EXPORT_SYMBOL(mptscsih_is_phys_disk);
2166
Eric Moore793955f2007-01-29 09:42:20 -07002167u8
2168mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002169{
2170 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002171 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002172
Eric Moore793955f2007-01-29 09:42:20 -07002173 if (!ioc->raid_data.pIocPg3)
2174 goto out;
2175 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2176 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2177 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2178 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2179 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002180 }
2181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
Eric Moore793955f2007-01-29 09:42:20 -07002183 out:
2184 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002185}
Eric Moore793955f2007-01-29 09:42:20 -07002186EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002187
2188/*
2189 * OS entry point to allow for host driver to free allocated memory
2190 * Called if no device present or device being unloaded
2191 */
2192void
2193mptscsih_slave_destroy(struct scsi_device *sdev)
2194{
2195 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002197 VirtTarget *vtarget;
2198 VirtDevice *vdevice;
2199 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002201 starget = scsi_target(sdev);
2202 vtarget = starget->hostdata;
2203 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002205 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002206 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002207 mptscsih_synchronize_cache(hd, vdevice);
2208 kfree(vdevice);
2209 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210}
2211
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2213/*
2214 * mptscsih_change_queue_depth - This function will set a devices queue depth
2215 * @sdev: per scsi_device pointer
2216 * @qdepth: requested queue depth
2217 *
2218 * Adding support for new 'change_queue_depth' api.
2219*/
2220int
2221mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002223 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2224 VirtTarget *vtarget;
2225 struct scsi_target *starget;
2226 int max_depth;
2227 int tagged;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002229 starget = scsi_target(sdev);
2230 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002231
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002232 if (hd->ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002233 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002235 else if (sdev->type == TYPE_DISK &&
2236 vtarget->minSyncFactor <= MPT_ULTRA160)
2237 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2238 else
2239 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 } else
2241 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2242
2243 if (qdepth > max_depth)
2244 qdepth = max_depth;
2245 if (qdepth == 1)
2246 tagged = 0;
2247 else
2248 tagged = MSG_SIMPLE_TAG;
2249
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002250 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2251 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254/*
2255 * OS entry point to adjust the queue_depths on a per-device basis.
2256 * Called once per device the bus scan. Use it to force the queue_depth
2257 * member to 1 if a device does not support Q tags.
2258 * Return non-zero if fails.
2259 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002260int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002261mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002263 struct Scsi_Host *sh = sdev->host;
2264 VirtTarget *vtarget;
2265 VirtDevice *vdevice;
2266 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
2268
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002269 starget = scsi_target(sdev);
2270 vtarget = starget->hostdata;
2271 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
2273 dsprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002274 "device @ %p, channel=%d, id=%d, lun=%d\n",
2275 hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002276 if (hd->ioc->bus_type == SPI)
2277 dsprintk((MYIOC_s_INFO_FMT
2278 "sdtr %d wdtr %d ppr %d inq length=%d\n",
2279 hd->ioc->name, sdev->sdtr, sdev->wdtr,
2280 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002282 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002284 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 goto slave_configure_exit;
2286 }
2287
Eric Moore793955f2007-01-29 09:42:20 -07002288 vdevice->configured_lun = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002289 mptscsih_initTarget(hd, vtarget, sdev);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002290 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 dsprintk((MYIOC_s_INFO_FMT
2293 "Queue depth=%d, tflags=%x\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002294 hd->ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002296 if (hd->ioc->bus_type == SPI)
2297 dsprintk((MYIOC_s_INFO_FMT
2298 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
2299 hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
2300 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
2302slave_configure_exit:
2303
2304 dsprintk((MYIOC_s_INFO_FMT
2305 "tagged %d, simple %d, ordered %d\n",
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002306 hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
2307 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 return 0;
2310}
2311
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2313/*
2314 * Private routines...
2315 */
2316
2317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2318/* Utility function to copy sense data from the scsi_cmnd buffer
2319 * to the FC and SCSI target structures.
2320 *
2321 */
2322static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002323mptscsih_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 -07002324{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002325 VirtDevice *vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 SCSIIORequest_t *pReq;
2327 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
2329 /* Get target structure
2330 */
2331 pReq = (SCSIIORequest_t *) mf;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002332 vdev = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
2334 if (sense_count) {
2335 u8 *sense_data;
2336 int req_index;
2337
2338 /* Copy the sense received into the scsi command block. */
2339 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2340 sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
2341 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2342
2343 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2344 */
2345 if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002346 if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 int idx;
2348 MPT_ADAPTER *ioc = hd->ioc;
2349
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002350 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2352 ioc->events[idx].eventContext = ioc->eventContext;
2353
2354 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
2355 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002356 (sc->device->channel << 8) || sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
2358 ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
2359
2360 ioc->eventContext++;
Eric Moore786899b2006-07-11 17:22:22 -06002361 if (hd->ioc->pcidev->vendor ==
2362 PCI_VENDOR_ID_IBM) {
2363 mptscsih_issue_sep_command(hd->ioc,
2364 vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2365 vdev->vtarget->tflags |=
2366 MPT_TARGET_FLAGS_LED_ON;
2367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 }
2369 }
2370 } else {
2371 dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
2372 hd->ioc->name));
2373 }
2374}
2375
Eric Moore3dc0b032006-07-11 17:32:33 -06002376static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2378{
2379 MPT_SCSI_HOST *hd;
2380 int i;
2381
2382 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2383
2384 for (i = 0; i < hd->ioc->req_depth; i++) {
2385 if (hd->ScsiLookup[i] == sc) {
2386 return i;
2387 }
2388 }
2389
2390 return -1;
2391}
2392
2393/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002394int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2396{
2397 MPT_SCSI_HOST *hd;
2398 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002399 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401 dtmprintk((KERN_WARNING MYNAM
2402 ": IOC %s_reset routed to SCSI host driver!\n",
2403 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2404 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
2405
2406 /* If a FW reload request arrives after base installed but
2407 * before all scsi hosts have been attached, then an alt_ioc
2408 * may have a NULL sh pointer.
2409 */
2410 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2411 return 0;
2412 else
2413 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2414
2415 if (reset_phase == MPT_IOC_SETUP_RESET) {
2416 dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
2417
2418 /* Clean Up:
2419 * 1. Set Hard Reset Pending Flag
2420 * All new commands go to doneQ
2421 */
2422 hd->resetPending = 1;
2423
2424 } else if (reset_phase == MPT_IOC_PRE_RESET) {
2425 dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
2426
2427 /* 2. Flush running commands
2428 * Clean ScsiLookup (and associated memory)
2429 * AND clean mytaskQ
2430 */
2431
2432 /* 2b. Reply to OS all known outstanding I/O commands.
2433 */
2434 mptscsih_flush_running_cmds(hd);
2435
2436 /* 2c. If there was an internal command that
2437 * has not completed, configuration or io request,
2438 * free these resources.
2439 */
2440 if (hd->cmdPtr) {
2441 del_timer(&hd->timer);
2442 mpt_free_msg_frame(ioc, hd->cmdPtr);
2443 }
2444
2445 dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
2446
2447 } else {
2448 dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
2449
2450 /* Once a FW reload begins, all new OS commands are
2451 * redirected to the doneQ w/ a reset status.
2452 * Init all control structures.
2453 */
2454
2455 /* ScsiLookup initialization
2456 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002457 for (ii=0; ii < hd->ioc->req_depth; ii++)
2458 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459
2460 /* 2. Chain Buffer initialization
2461 */
2462
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002463 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
2466 /* 5. Enable new commands to be posted
2467 */
2468 spin_lock_irqsave(&ioc->FreeQlock, flags);
2469 hd->tmPending = 0;
2470 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2471 hd->resetPending = 0;
2472 hd->tmState = TM_STATE_NONE;
2473
2474 /* 6. If there was an internal command,
2475 * wake this process up.
2476 */
2477 if (hd->cmdPtr) {
2478 /*
2479 * Wake up the original calling thread
2480 */
2481 hd->pLocal = &hd->localReply;
2482 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002483 hd->scandv_wait_done = 1;
2484 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 hd->cmdPtr = NULL;
2486 }
2487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
2489
2490 }
2491
2492 return 1; /* currently means nothing really */
2493}
2494
2495/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002496int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2498{
2499 MPT_SCSI_HOST *hd;
2500 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2501
Moore, Eric3a892be2006-03-14 09:14:03 -07002502 devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 ioc->name, event));
2504
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002505 if (ioc->sh == NULL ||
2506 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2507 return 1;
2508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 switch (event) {
2510 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2511 /* FIXME! */
2512 break;
2513 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2514 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002515 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002516 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 break;
2518 case MPI_EVENT_LOGOUT: /* 09 */
2519 /* FIXME! */
2520 break;
2521
Michael Reed05e8ec12006-01-13 14:31:54 -06002522 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002523 break;
2524
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 /*
2526 * CHECKME! Don't think we need to do
2527 * anything for these, but...
2528 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2530 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2531 /*
2532 * CHECKME! Falling thru...
2533 */
2534 break;
2535
2536 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002537 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 case MPI_EVENT_NONE: /* 00 */
2540 case MPI_EVENT_LOG_DATA: /* 01 */
2541 case MPI_EVENT_STATE_CHANGE: /* 02 */
2542 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2543 default:
2544 dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
2545 break;
2546 }
2547
2548 return 1; /* currently means nothing really */
2549}
2550
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2552/*
2553 * mptscsih_initTarget - Target, LUN alloc/free functionality.
2554 * @hd: Pointer to MPT_SCSI_HOST structure
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002555 * @vtarget: per target private data
James Bottomleyc92f2222006-03-01 09:02:49 -06002556 * @sdev: SCSI device
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 *
2558 * NOTE: It's only SAFE to call this routine if data points to
2559 * sane & valid STANDARD INQUIRY data!
2560 *
2561 * Allocate and initialize memory for this target.
2562 * Save inquiry data.
2563 *
2564 */
2565static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002566mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
2567 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568{
Eric Moore793955f2007-01-29 09:42:20 -07002569 dinitprintk((MYIOC_s_INFO_FMT "initTarget channel=%d id=%d lun=%d hd=%p\n",
2570 hd->ioc->name, vtarget->channel, vtarget->id,
Eric Mooref99be432007-01-04 20:46:54 -07002571 sdev->lun, hd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 /* Is LUN supported? If so, upper 2 bits will be 0
2574 * in first byte of inquiry data.
2575 */
James Bottomleyc92f2222006-03-01 09:02:49 -06002576 if (sdev->inq_periph_qual != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 return;
2578
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002579 if (vtarget == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
James Bottomleyc92f2222006-03-01 09:02:49 -06002582 vtarget->type = sdev->type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002584 if (hd->ioc->bus_type != SPI)
2585 return;
2586
James Bottomleyc92f2222006-03-01 09:02:49 -06002587 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002588 /* Treat all Processors as SAF-TE if
2589 * command line option is set */
2590 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
Eric Moore793955f2007-01-29 09:42:20 -07002591 mptscsih_writeIOCPage4(hd, vtarget->channel, vtarget->id);
James Bottomleyc92f2222006-03-01 09:02:49 -06002592 }else if ((sdev->type == TYPE_PROCESSOR) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002593 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002594 if (sdev->inquiry_len > 49 ) {
2595 if (sdev->inquiry[44] == 'S' &&
2596 sdev->inquiry[45] == 'A' &&
2597 sdev->inquiry[46] == 'F' &&
2598 sdev->inquiry[47] == '-' &&
2599 sdev->inquiry[48] == 'T' &&
2600 sdev->inquiry[49] == 'E' ) {
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002601 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
Eric Moore793955f2007-01-29 09:42:20 -07002602 mptscsih_writeIOCPage4(hd, vtarget->channel, vtarget->id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 }
2604 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002605 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002606 mptscsih_setTargetNegoParms(hd, vtarget, sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607}
2608
2609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2610/*
2611 * Update the target negotiation parameters based on the
2612 * the Inquiry data, adapter capabilities, and NVRAM settings.
2613 *
2614 */
2615static void
James Bottomleyc92f2222006-03-01 09:02:49 -06002616mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
2617 struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618{
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002619 SpiCfgData *pspi_data = &hd->ioc->spi_data;
Eric Moore793955f2007-01-29 09:42:20 -07002620 int id = (int) target->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 int nvram;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 u8 width = MPT_NARROW;
2623 u8 factor = MPT_ASYNC;
2624 u8 offset = 0;
James Bottomleyc92f2222006-03-01 09:02:49 -06002625 u8 nfactor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 u8 noQas = 1;
2627
2628 target->negoFlags = pspi_data->noQas;
2629
James Bottomleyc92f2222006-03-01 09:02:49 -06002630 /* noQas == 0 => device supports QAS. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631
James Bottomleyc92f2222006-03-01 09:02:49 -06002632 if (sdev->scsi_level < SCSI_2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 width = 0;
2634 factor = MPT_ULTRA2;
2635 offset = pspi_data->maxSyncOffset;
2636 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2637 } else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002638 if (scsi_device_wide(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 width = 1;
2640 }
2641
James Bottomleyc92f2222006-03-01 09:02:49 -06002642 if (scsi_device_sync(sdev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 factor = pspi_data->minSyncFactor;
James Bottomleyc92f2222006-03-01 09:02:49 -06002644 if (!scsi_device_dt(sdev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 factor = MPT_ULTRA2;
James Bottomleyc92f2222006-03-01 09:02:49 -06002646 else {
2647 if (!scsi_device_ius(sdev) &&
2648 !scsi_device_qas(sdev))
2649 factor = MPT_ULTRA160;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 else {
James Bottomleyc92f2222006-03-01 09:02:49 -06002651 factor = MPT_ULTRA320;
2652 if (scsi_device_qas(sdev)) {
Eric Mooref99be432007-01-04 20:46:54 -07002653 ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
James Bottomleyc92f2222006-03-01 09:02:49 -06002654 noQas = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 }
James Bottomleyc92f2222006-03-01 09:02:49 -06002656 if (sdev->type == TYPE_TAPE &&
2657 scsi_device_ius(sdev))
2658 target->negoFlags |= MPT_TAPE_NEGO_IDP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 offset = pspi_data->maxSyncOffset;
2662
2663 /* If RAID, never disable QAS
2664 * else if non RAID, do not disable
2665 * QAS if bit 1 is set
2666 * bit 1 QAS support, non-raid only
2667 * bit 0 IU support
2668 */
2669 if (target->raidVolume == 1) {
2670 noQas = 0;
2671 }
2672 } else {
2673 factor = MPT_ASYNC;
2674 offset = 0;
2675 }
2676 }
2677
James Bottomleyc92f2222006-03-01 09:02:49 -06002678 if (!sdev->tagged_supported) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
2680 }
2681
2682 /* Update tflags based on NVRAM settings. (SCSI only)
2683 */
2684 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
2685 nvram = pspi_data->nvram[id];
2686 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
2687
2688 if (width)
2689 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
2690
2691 if (offset > 0) {
2692 /* Ensure factor is set to the
2693 * maximum of: adapter, nvram, inquiry
2694 */
2695 if (nfactor) {
2696 if (nfactor < pspi_data->minSyncFactor )
2697 nfactor = pspi_data->minSyncFactor;
2698
2699 factor = max(factor, nfactor);
2700 if (factor == MPT_ASYNC)
2701 offset = 0;
2702 } else {
2703 offset = 0;
2704 factor = MPT_ASYNC;
2705 }
2706 } else {
2707 factor = MPT_ASYNC;
2708 }
2709 }
2710
2711 /* Make sure data is consistent
2712 */
2713 if ((!width) && (factor < MPT_ULTRA2)) {
2714 factor = MPT_ULTRA2;
2715 }
2716
2717 /* Save the data to the target structure.
2718 */
2719 target->minSyncFactor = factor;
2720 target->maxOffset = offset;
2721 target->maxWidth = width;
2722
2723 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2724
2725 /* Disable unused features.
2726 */
2727 if (!width)
2728 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2729
2730 if (!offset)
2731 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2732
2733 if ( factor > MPT_ULTRA320 )
2734 noQas = 0;
2735
James Bottomleyc92f2222006-03-01 09:02:49 -06002736 if (noQas && (pspi_data->noQas == 0)) {
2737 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2738 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
James Bottomleyc92f2222006-03-01 09:02:49 -06002740 /* Disable QAS in a mixed configuration case
2741 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
James Bottomleyc92f2222006-03-01 09:02:49 -06002743 ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 }
2745}
2746
2747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
2749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2750/*
2751 * SCSI Config Page functionality ...
2752 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
2754/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755/* mptscsih_writeIOCPage4 - write IOC Page 4
2756 * @hd: Pointer to a SCSI Host Structure
Eric Moore793955f2007-01-29 09:42:20 -07002757 * @channel: write IOC Page4 for this Bus
2758 * @id: write IOC Page4 for this ID
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 *
2760 * Return: -EAGAIN if unable to obtain a Message Frame
2761 * or 0 if success.
2762 *
2763 * Remark: We do not wait for a return, write pages sequentially.
2764 */
2765static int
Eric Moore793955f2007-01-29 09:42:20 -07002766mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int channel, int id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767{
2768 MPT_ADAPTER *ioc = hd->ioc;
2769 Config_t *pReq;
2770 IOCPage4_t *IOCPage4Ptr;
2771 MPT_FRAME_HDR *mf;
2772 dma_addr_t dataDma;
2773 u16 req_idx;
2774 u32 frameOffset;
2775 u32 flagsLength;
2776 int ii;
2777
2778 /* Get a MF for this command.
2779 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002780 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002781 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 ioc->name));
2783 return -EAGAIN;
2784 }
2785
2786 /* Set the request and the data pointers.
2787 * Place data at end of MF.
2788 */
2789 pReq = (Config_t *)mf;
2790
2791 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2792 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
2793
2794 /* Complete the request frame (same for all requests).
2795 */
2796 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2797 pReq->Reserved = 0;
2798 pReq->ChainOffset = 0;
2799 pReq->Function = MPI_FUNCTION_CONFIG;
2800 pReq->ExtPageLength = 0;
2801 pReq->ExtPageType = 0;
2802 pReq->MsgFlags = 0;
2803 for (ii=0; ii < 8; ii++) {
2804 pReq->Reserved2[ii] = 0;
2805 }
2806
Eric Moore793955f2007-01-29 09:42:20 -07002807 IOCPage4Ptr = ioc->spi_data.pIocPg4;
2808 dataDma = ioc->spi_data.IocPg4_dma;
2809 ii = IOCPage4Ptr->ActiveSEP++;
2810 IOCPage4Ptr->SEP[ii].SEPTargetID = id;
2811 IOCPage4Ptr->SEP[ii].SEPBus = channel;
2812 pReq->Header = IOCPage4Ptr->Header;
2813 pReq->PageAddress = cpu_to_le32(id | (channel << 8 ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
2815 /* Add a SGE to the config request.
2816 */
2817 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
2818 (IOCPage4Ptr->Header.PageLength + ii) * 4;
2819
2820 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
2821
2822 dinitprintk((MYIOC_s_INFO_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002823 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d channel=%d id=%d \n",
2824 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, channel, id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002826 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827
2828 return 0;
2829}
2830
2831/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2832/*
2833 * Bus Scan and Domain Validation functionality ...
2834 */
2835
2836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2837/*
2838 * mptscsih_scandv_complete - Scan and DV callback routine registered
2839 * to Fustion MPT (base) driver.
2840 *
2841 * @ioc: Pointer to MPT_ADAPTER structure
2842 * @mf: Pointer to original MPT request frame
2843 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2844 *
2845 * This routine is called from mpt.c::mpt_interrupt() at the completion
2846 * of any SCSI IO request.
2847 * This routine is registered with the Fusion MPT (base) driver at driver
2848 * load/init time via the mpt_register() API call.
2849 *
2850 * Returns 1 indicating alloc'd request frame ptr should be freed.
2851 *
2852 * Remark: Sets a completion code and (possibly) saves sense data
2853 * in the IOC member localReply structure.
2854 * Used ONLY for DV and other internal commands.
2855 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002856int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2858{
2859 MPT_SCSI_HOST *hd;
2860 SCSIIORequest_t *pReq;
2861 int completionCode;
2862 u16 req_idx;
2863
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002864 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2865
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 if ((mf == NULL) ||
2867 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2868 printk(MYIOC_s_ERR_FMT
2869 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2870 ioc->name, mf?"BAD":"NULL", (void *) mf);
2871 goto wakeup;
2872 }
2873
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 del_timer(&hd->timer);
2875 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2876 hd->ScsiLookup[req_idx] = NULL;
2877 pReq = (SCSIIORequest_t *) mf;
2878
2879 if (mf != hd->cmdPtr) {
2880 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
2881 hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
2882 }
2883 hd->cmdPtr = NULL;
2884
2885 ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
2886 hd->ioc->name, mf, mr, req_idx));
2887
2888 hd->pLocal = &hd->localReply;
2889 hd->pLocal->scsiStatus = 0;
2890
2891 /* If target struct exists, clear sense valid flag.
2892 */
2893 if (mr == NULL) {
2894 completionCode = MPT_SCANDV_GOOD;
2895 } else {
2896 SCSIIOReply_t *pReply;
2897 u16 status;
2898 u8 scsi_status;
2899
2900 pReply = (SCSIIOReply_t *) mr;
2901
2902 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2903 scsi_status = pReply->SCSIStatus;
2904
2905 ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
2906 status, pReply->SCSIState, scsi_status,
2907 le32_to_cpu(pReply->IOCLogInfo)));
2908
2909 switch(status) {
2910
2911 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2912 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2913 break;
2914
2915 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2916 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2917 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2918 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2919 completionCode = MPT_SCANDV_DID_RESET;
2920 break;
2921
2922 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2923 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2924 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2925 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2926 ConfigReply_t *pr = (ConfigReply_t *)mr;
2927 completionCode = MPT_SCANDV_GOOD;
2928 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2929 hd->pLocal->header.PageLength = pr->Header.PageLength;
2930 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2931 hd->pLocal->header.PageType = pr->Header.PageType;
2932
2933 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2934 /* If the RAID Volume request is successful,
2935 * return GOOD, else indicate that
2936 * some type of error occurred.
2937 */
2938 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002939 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 completionCode = MPT_SCANDV_GOOD;
2941 else
2942 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002943 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
2945 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2946 u8 *sense_data;
2947 int sz;
2948
2949 /* save sense data in global structure
2950 */
2951 completionCode = MPT_SCANDV_SENSE;
2952 hd->pLocal->scsiStatus = scsi_status;
2953 sense_data = ((u8 *)hd->ioc->sense_buf_pool +
2954 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2955
2956 sz = min_t(int, pReq->SenseBufferLength,
2957 SCSI_STD_SENSE_BYTES);
2958 memcpy(hd->pLocal->sense, sense_data, sz);
2959
2960 ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
2961 sense_data));
2962 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2963 if (pReq->CDB[0] == INQUIRY)
2964 completionCode = MPT_SCANDV_ISSUE_SENSE;
2965 else
2966 completionCode = MPT_SCANDV_DID_RESET;
2967 }
2968 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2969 completionCode = MPT_SCANDV_DID_RESET;
2970 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2971 completionCode = MPT_SCANDV_DID_RESET;
2972 else {
2973 completionCode = MPT_SCANDV_GOOD;
2974 hd->pLocal->scsiStatus = scsi_status;
2975 }
2976 break;
2977
2978 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2979 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2980 completionCode = MPT_SCANDV_DID_RESET;
2981 else
2982 completionCode = MPT_SCANDV_SOME_ERROR;
2983 break;
2984
2985 default:
2986 completionCode = MPT_SCANDV_SOME_ERROR;
2987 break;
2988
2989 } /* switch(status) */
2990
2991 ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
2992 completionCode));
2993 } /* end of address reply case */
2994
2995 hd->pLocal->completion = completionCode;
2996
2997 /* MF and RF are freed in mpt_interrupt
2998 */
2999wakeup:
3000 /* Free Chain buffers (will never chain) in scan or dv */
3001 //mptscsih_freeChainBuffers(ioc, req_idx);
3002
3003 /*
3004 * Wake up the original calling thread
3005 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003006 hd->scandv_wait_done = 1;
3007 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
3009 return 1;
3010}
3011
3012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3013/* mptscsih_timer_expired - Call back for timer process.
3014 * Used only for dv functionality.
3015 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
3016 *
3017 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003018void
3019mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020{
3021 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
3022
3023 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
3024
3025 if (hd->cmdPtr) {
3026 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
3027
3028 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
3029 /* Desire to issue a task management request here.
3030 * TM requests MUST be single threaded.
3031 * If old eh code and no TM current, issue request.
3032 * If new eh code, do nothing. Wait for OS cmd timeout
3033 * for bus reset.
3034 */
3035 ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
3036 } else {
3037 /* Perform a FW reload */
3038 if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
3039 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
3040 }
3041 }
3042 } else {
3043 /* This should NEVER happen */
3044 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
3045 }
3046
3047 /* No more processing.
3048 * TM call will generate an interrupt for SCSI TM Management.
3049 * The FW will reply to all outstanding commands, callback will finish cleanup.
3050 * Hard reset clean-up will free all resources.
3051 */
3052 ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
3053
3054 return;
3055}
3056
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
3058/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3059/**
3060 * mptscsih_do_cmd - Do internal command.
3061 * @hd: MPT_SCSI_HOST pointer
3062 * @io: INTERNAL_CMD pointer.
3063 *
3064 * Issue the specified internally generated command and do command
3065 * specific cleanup. For bus scan / DV only.
3066 * NOTES: If command is Inquiry and status is good,
3067 * initialize a target structure, save the data
3068 *
3069 * Remark: Single threaded access only.
3070 *
3071 * Return:
3072 * < 0 if an illegal command or no resources
3073 *
3074 * 0 if good
3075 *
3076 * > 0 if command complete but some type of completion error.
3077 */
3078static int
3079mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
3080{
3081 MPT_FRAME_HDR *mf;
3082 SCSIIORequest_t *pScsiReq;
3083 SCSIIORequest_t ReqCopy;
3084 int my_idx, ii, dir;
3085 int rc, cmdTimeout;
3086 int in_isr;
3087 char cmdLen;
3088 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3089 char cmd = io->cmd;
3090
3091 in_isr = in_interrupt();
3092 if (in_isr) {
3093 dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
3094 hd->ioc->name));
3095 return -EPERM;
3096 }
3097
3098
3099 /* Set command specific information
3100 */
3101 switch (cmd) {
3102 case INQUIRY:
3103 cmdLen = 6;
3104 dir = MPI_SCSIIO_CONTROL_READ;
3105 CDB[0] = cmd;
3106 CDB[4] = io->size;
3107 cmdTimeout = 10;
3108 break;
3109
3110 case TEST_UNIT_READY:
3111 cmdLen = 6;
3112 dir = MPI_SCSIIO_CONTROL_READ;
3113 cmdTimeout = 10;
3114 break;
3115
3116 case START_STOP:
3117 cmdLen = 6;
3118 dir = MPI_SCSIIO_CONTROL_READ;
3119 CDB[0] = cmd;
3120 CDB[4] = 1; /*Spin up the disk */
3121 cmdTimeout = 15;
3122 break;
3123
3124 case REQUEST_SENSE:
3125 cmdLen = 6;
3126 CDB[0] = cmd;
3127 CDB[4] = io->size;
3128 dir = MPI_SCSIIO_CONTROL_READ;
3129 cmdTimeout = 10;
3130 break;
3131
3132 case READ_BUFFER:
3133 cmdLen = 10;
3134 dir = MPI_SCSIIO_CONTROL_READ;
3135 CDB[0] = cmd;
3136 if (io->flags & MPT_ICFLAG_ECHO) {
3137 CDB[1] = 0x0A;
3138 } else {
3139 CDB[1] = 0x02;
3140 }
3141
3142 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3143 CDB[1] |= 0x01;
3144 }
3145 CDB[6] = (io->size >> 16) & 0xFF;
3146 CDB[7] = (io->size >> 8) & 0xFF;
3147 CDB[8] = io->size & 0xFF;
3148 cmdTimeout = 10;
3149 break;
3150
3151 case WRITE_BUFFER:
3152 cmdLen = 10;
3153 dir = MPI_SCSIIO_CONTROL_WRITE;
3154 CDB[0] = cmd;
3155 if (io->flags & MPT_ICFLAG_ECHO) {
3156 CDB[1] = 0x0A;
3157 } else {
3158 CDB[1] = 0x02;
3159 }
3160 CDB[6] = (io->size >> 16) & 0xFF;
3161 CDB[7] = (io->size >> 8) & 0xFF;
3162 CDB[8] = io->size & 0xFF;
3163 cmdTimeout = 10;
3164 break;
3165
3166 case RESERVE:
3167 cmdLen = 6;
3168 dir = MPI_SCSIIO_CONTROL_READ;
3169 CDB[0] = cmd;
3170 cmdTimeout = 10;
3171 break;
3172
3173 case RELEASE:
3174 cmdLen = 6;
3175 dir = MPI_SCSIIO_CONTROL_READ;
3176 CDB[0] = cmd;
3177 cmdTimeout = 10;
3178 break;
3179
3180 case SYNCHRONIZE_CACHE:
3181 cmdLen = 10;
3182 dir = MPI_SCSIIO_CONTROL_READ;
3183 CDB[0] = cmd;
3184// CDB[1] = 0x02; /* set immediate bit */
3185 cmdTimeout = 10;
3186 break;
3187
3188 default:
3189 /* Error Case */
3190 return -EFAULT;
3191 }
3192
3193 /* Get and Populate a free Frame
3194 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003195 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
3197 hd->ioc->name));
3198 return -EBUSY;
3199 }
3200
3201 pScsiReq = (SCSIIORequest_t *) mf;
3202
3203 /* Get the request index */
3204 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3205 ADD_INDEX_LOG(my_idx); /* for debug */
3206
3207 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3208 pScsiReq->TargetID = io->physDiskNum;
3209 pScsiReq->Bus = 0;
3210 pScsiReq->ChainOffset = 0;
3211 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3212 } else {
3213 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003214 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 pScsiReq->ChainOffset = 0;
3216 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3217 }
3218
3219 pScsiReq->CDBLength = cmdLen;
3220 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3221
3222 pScsiReq->Reserved = 0;
3223
3224 pScsiReq->MsgFlags = mpt_msg_flags();
3225 /* MsgContext set in mpt_get_msg_fram call */
3226
Eric Moore793955f2007-01-29 09:42:20 -07003227 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228
3229 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3230 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3231 else
3232 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3233
3234 if (cmd == REQUEST_SENSE) {
3235 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3236 ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
3237 hd->ioc->name, cmd));
3238 }
3239
3240 for (ii=0; ii < 16; ii++)
3241 pScsiReq->CDB[ii] = CDB[ii];
3242
3243 pScsiReq->DataLength = cpu_to_le32(io->size);
3244 pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
3245 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3246
3247 ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
Eric Moore793955f2007-01-29 09:42:20 -07003248 hd->ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
3250 if (dir == MPI_SCSIIO_CONTROL_READ) {
3251 mpt_add_sge((char *) &pScsiReq->SGL,
3252 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3253 io->data_dma);
3254 } else {
3255 mpt_add_sge((char *) &pScsiReq->SGL,
3256 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3257 io->data_dma);
3258 }
3259
3260 /* The ISR will free the request frame, but we need
3261 * the information to initialize the target. Duplicate.
3262 */
3263 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3264
3265 /* Issue this command after:
3266 * finish init
3267 * add timer
3268 * Wait until the reply has been received
3269 * ScsiScanDvCtx callback function will
3270 * set hd->pLocal;
3271 * set scandv_wait_done and call wake_up
3272 */
3273 hd->pLocal = NULL;
3274 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003275 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
3277 /* Save cmd pointer, for resource free if timeout or
3278 * FW reload occurs
3279 */
3280 hd->cmdPtr = mf;
3281
3282 add_timer(&hd->timer);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003283 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
3284 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
3286 if (hd->pLocal) {
3287 rc = hd->pLocal->completion;
3288 hd->pLocal->skip = 0;
3289
3290 /* Always set fatal error codes in some cases.
3291 */
3292 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3293 rc = -ENXIO;
3294 else if (rc == MPT_SCANDV_SOME_ERROR)
3295 rc = -rc;
3296 } else {
3297 rc = -EFAULT;
3298 /* This should never happen. */
3299 ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
3300 hd->ioc->name));
3301 }
3302
3303 return rc;
3304}
3305
3306/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3307/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003308 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3309 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003310 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003311 *
3312 * Uses the ISR, but with special processing.
3313 * MUST be single-threaded.
3314 *
3315 */
3316static void
3317mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3318{
3319 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320
3321 /* Following parameters will not change
3322 * in this routine.
3323 */
3324 iocmd.cmd = SYNCHRONIZE_CACHE;
3325 iocmd.flags = 0;
3326 iocmd.physDiskNum = -1;
3327 iocmd.data = NULL;
3328 iocmd.data_dma = -1;
3329 iocmd.size = 0;
3330 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003331 iocmd.channel = vdevice->vtarget->channel;
3332 iocmd.id = vdevice->vtarget->id;
3333 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
James Bottomleyc92f2222006-03-01 09:02:49 -06003335 if ((vdevice->vtarget->type == TYPE_DISK) &&
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003336 (vdevice->configured_lun))
3337 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338}
3339
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003340EXPORT_SYMBOL(mptscsih_remove);
3341EXPORT_SYMBOL(mptscsih_shutdown);
3342#ifdef CONFIG_PM
3343EXPORT_SYMBOL(mptscsih_suspend);
3344EXPORT_SYMBOL(mptscsih_resume);
3345#endif
3346EXPORT_SYMBOL(mptscsih_proc_info);
3347EXPORT_SYMBOL(mptscsih_info);
3348EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003349EXPORT_SYMBOL(mptscsih_slave_destroy);
3350EXPORT_SYMBOL(mptscsih_slave_configure);
3351EXPORT_SYMBOL(mptscsih_abort);
3352EXPORT_SYMBOL(mptscsih_dev_reset);
3353EXPORT_SYMBOL(mptscsih_bus_reset);
3354EXPORT_SYMBOL(mptscsih_host_reset);
3355EXPORT_SYMBOL(mptscsih_bios_param);
3356EXPORT_SYMBOL(mptscsih_io_done);
3357EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3358EXPORT_SYMBOL(mptscsih_scandv_complete);
3359EXPORT_SYMBOL(mptscsih_event_process);
3360EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003361EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003362EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003363EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003365/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/