blob: 17369f8ba88b74a8a3596ce1e02e9160adb1ab12 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05306 * Copyright (c) 1999-2007 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/workqueue.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060063#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "mptbase.h"
66#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060067#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*
81 * Other private/forward protos...
82 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040083int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040085int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
88 SCSIIORequest_t *pReq, int req_idx);
89static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040090static 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 -070091static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
92static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Eric Moore3dc0b032006-07-11 17:32:33 -060093static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Eric Moore793955f2007-01-29 09:42:20 -070095static 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 -070096
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040097int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
98int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400100int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700102static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400104void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700105void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400107int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
108int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#endif
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
114/**
115 * mptscsih_add_sge - Place a simple SGE at address pAddr.
116 * @pAddr: virtual address for SGE
117 * @flagslength: SGE flags and data transfer length
118 * @dma_addr: Physical address
119 *
120 * This routine places a MPT request frame back on the MPT adapter's
121 * FreeQ.
122 */
123static inline void
124mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
125{
126 if (sizeof(dma_addr_t) == sizeof(u64)) {
127 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
128 u32 tmp = dma_addr & 0xFFFFFFFF;
129
130 pSge->FlagsLength = cpu_to_le32(flagslength);
131 pSge->Address.Low = cpu_to_le32(tmp);
132 tmp = (u32) ((u64)dma_addr >> 32);
133 pSge->Address.High = cpu_to_le32(tmp);
134
135 } else {
136 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
137 pSge->FlagsLength = cpu_to_le32(flagslength);
138 pSge->Address = cpu_to_le32(dma_addr);
139 }
140} /* mptscsih_add_sge() */
141
142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
143/**
144 * mptscsih_add_chain - Place a chain SGE at address pAddr.
145 * @pAddr: virtual address for SGE
146 * @next: nextChainOffset value (u32's)
147 * @length: length of next SGL segment
148 * @dma_addr: Physical address
149 *
150 * This routine places a MPT request frame back on the MPT adapter's
151 * FreeQ.
152 */
153static inline void
154mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
155{
156 if (sizeof(dma_addr_t) == sizeof(u64)) {
157 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
158 u32 tmp = dma_addr & 0xFFFFFFFF;
159
160 pChain->Length = cpu_to_le16(length);
161 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
162
163 pChain->NextChainOffset = next;
164
165 pChain->Address.Low = cpu_to_le32(tmp);
166 tmp = (u32) ((u64)dma_addr >> 32);
167 pChain->Address.High = cpu_to_le32(tmp);
168 } else {
169 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
170 pChain->Length = cpu_to_le16(length);
171 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
172 pChain->NextChainOffset = next;
173 pChain->Address = cpu_to_le32(dma_addr);
174 }
175} /* mptscsih_add_chain() */
176
177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
178/*
179 * mptscsih_getFreeChainBuffer - Function to get a free chain
180 * from the MPT_SCSI_HOST FreeChainQ.
181 * @ioc: Pointer to MPT_ADAPTER structure
182 * @req_idx: Index of the SCSI IO request frame. (output)
183 *
184 * return SUCCESS or FAILED
185 */
186static inline int
187mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
188{
189 MPT_FRAME_HDR *chainBuf;
190 unsigned long flags;
191 int rc;
192 int chain_idx;
193
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530194 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600195 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 spin_lock_irqsave(&ioc->FreeQlock, flags);
197 if (!list_empty(&ioc->FreeChainQ)) {
198 int offset;
199
200 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
201 u.frame.linkage.list);
202 list_del(&chainBuf->u.frame.linkage.list);
203 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
204 chain_idx = offset / ioc->req_sz;
205 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600206 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
207 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
208 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 } else {
210 rc = FAILED;
211 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600212 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
213 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 }
215 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
216
217 *retIndex = chain_idx;
218 return rc;
219} /* mptscsih_getFreeChainBuffer() */
220
221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
222/*
223 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
224 * SCSIIORequest_t Message Frame.
225 * @ioc: Pointer to MPT_ADAPTER structure
226 * @SCpnt: Pointer to scsi_cmnd structure
227 * @pReq: Pointer to SCSIIORequest_t structure
228 *
229 * Returns ...
230 */
231static int
232mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
233 SCSIIORequest_t *pReq, int req_idx)
234{
235 char *psge;
236 char *chainSge;
237 struct scatterlist *sg;
238 int frm_sz;
239 int sges_left, sg_done;
240 int chain_idx = MPT_HOST_NO_CHAIN;
241 int sgeOffset;
242 int numSgeSlots, numSgeThisFrame;
243 u32 sgflags, sgdir, thisxfer = 0;
244 int chain_dma_off = 0;
245 int newIndex;
246 int ii;
247 dma_addr_t v2;
248 u32 RequestNB;
249
250 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
251 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
252 sgdir = MPT_TRANSFER_HOST_TO_IOC;
253 } else {
254 sgdir = MPT_TRANSFER_IOC_TO_HOST;
255 }
256
257 psge = (char *) &pReq->SGL;
258 frm_sz = ioc->req_sz;
259
260 /* Map the data portion, if any.
261 * sges_left = 0 if no data transfer.
262 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900263 sges_left = scsi_dma_map(SCpnt);
264 if (sges_left < 0)
265 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 /* Handle the SG case.
268 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900269 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sg_done = 0;
271 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
272 chainSge = NULL;
273
274 /* Prior to entering this loop - the following must be set
275 * current MF: sgeOffset (bytes)
276 * chainSge (Null if original MF is not a chain buffer)
277 * sg_done (num SGE done for this MF)
278 */
279
280nextSGEset:
281 numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
282 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
283
284 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
285
286 /* Get first (num - 1) SG elements
287 * Skip any SG entries with a length of 0
288 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
289 */
290 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
291 thisxfer = sg_dma_len(sg);
292 if (thisxfer == 0) {
293 sg ++; /* Get next SG element from the OS */
294 sg_done++;
295 continue;
296 }
297
298 v2 = sg_dma_address(sg);
299 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
300
301 sg++; /* Get next SG element from the OS */
302 psge += (sizeof(u32) + sizeof(dma_addr_t));
303 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
304 sg_done++;
305 }
306
307 if (numSgeThisFrame == sges_left) {
308 /* Add last element, end of buffer and end of list flags.
309 */
310 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
311 MPT_SGE_FLAGS_END_OF_BUFFER |
312 MPT_SGE_FLAGS_END_OF_LIST;
313
314 /* Add last SGE and set termination flags.
315 * Note: Last SGE may have a length of 0 - which should be ok.
316 */
317 thisxfer = sg_dma_len(sg);
318
319 v2 = sg_dma_address(sg);
320 mptscsih_add_sge(psge, sgflags | thisxfer, v2);
321 /*
322 sg++;
323 psge += (sizeof(u32) + sizeof(dma_addr_t));
324 */
325 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
326 sg_done++;
327
328 if (chainSge) {
329 /* The current buffer is a chain buffer,
330 * but there is not another one.
331 * Update the chain element
332 * Offset and Length fields.
333 */
334 mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
335 } else {
336 /* The current buffer is the original MF
337 * and there is no Chain buffer.
338 */
339 pReq->ChainOffset = 0;
340 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530341 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
343 ioc->RequestNB[req_idx] = RequestNB;
344 }
345 } else {
346 /* At least one chain buffer is needed.
347 * Complete the first MF
348 * - last SGE element, set the LastElement bit
349 * - set ChainOffset (words) for orig MF
350 * (OR finish previous MF chain buffer)
351 * - update MFStructPtr ChainIndex
352 * - Populate chain element
353 * Also
354 * Loop until done.
355 */
356
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530357 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 ioc->name, sg_done));
359
360 /* Set LAST_ELEMENT flag for last non-chain element
361 * in the buffer. Since psge points at the NEXT
362 * SGE element, go back one SGE element, update the flags
363 * and reset the pointer. (Note: sgflags & thisxfer are already
364 * set properly).
365 */
366 if (sg_done) {
367 u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
368 sgflags = le32_to_cpu(*ptmp);
369 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
370 *ptmp = cpu_to_le32(sgflags);
371 }
372
373 if (chainSge) {
374 /* The current buffer is a chain buffer.
375 * chainSge points to the previous Chain Element.
376 * Update its chain element Offset and Length (must
377 * include chain element size) fields.
378 * Old chain element is now complete.
379 */
380 u8 nextChain = (u8) (sgeOffset >> 2);
381 sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
382 mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off);
383 } else {
384 /* The original MF buffer requires a chain buffer -
385 * set the offset.
386 * Last element in this MF is a chain element.
387 */
388 pReq->ChainOffset = (u8) (sgeOffset >> 2);
389 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530390 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 ioc->RequestNB[req_idx] = RequestNB;
392 }
393
394 sges_left -= sg_done;
395
396
397 /* NOTE: psge points to the beginning of the chain element
398 * in current buffer. Get a chain buffer.
399 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200400 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530401 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200402 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
403 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 /* Update the tracking arrays.
408 * If chainSge == NULL, update ReqToChain, else ChainToChain
409 */
410 if (chainSge) {
411 ioc->ChainToChain[chain_idx] = newIndex;
412 } else {
413 ioc->ReqToChain[req_idx] = newIndex;
414 }
415 chain_idx = newIndex;
416 chain_dma_off = ioc->req_sz * chain_idx;
417
418 /* Populate the chainSGE for the current buffer.
419 * - Set chain buffer pointer to psge and fill
420 * out the Address and Flags fields.
421 */
422 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600423 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
424 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 /* Start the SGE for the next buffer
427 */
428 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
429 sgeOffset = 0;
430 sg_done = 0;
431
Eric Moore29dd3602007-09-14 18:46:51 -0600432 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
433 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 /* Start the SGE for the next buffer
436 */
437
438 goto nextSGEset;
439 }
440
441 return SUCCESS;
442} /* mptscsih_AddSGE() */
443
Eric Moore786899b2006-07-11 17:22:22 -0600444static void
445mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
446 U32 SlotStatus)
447{
448 MPT_FRAME_HDR *mf;
449 SEPRequest_t *SEPMsg;
450
Eric Moorecc78d302007-06-15 17:27:21 -0600451 if (ioc->bus_type != SAS)
452 return;
453
454 /* Not supported for hidden raid components
455 */
456 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600457 return;
458
459 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530460 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Eric Moore786899b2006-07-11 17:22:22 -0600461 ioc->name,__FUNCTION__));
462 return;
463 }
464
465 SEPMsg = (SEPRequest_t *)mf;
466 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700467 SEPMsg->Bus = vtarget->channel;
468 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600469 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
470 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530471 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700472 "Sending SEP cmd=%x channel=%d id=%d\n",
473 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600474 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
475}
476
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530477#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700478/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530479 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700480 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700481 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530482 * @pScsiReply: Pointer to MPT reply frame
483 *
484 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700485 *
486 * Refer to lsi/mpi.h.
487 **/
488static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530489mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700490{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530491 char *desc = NULL;
492 char *desc1 = NULL;
493 u16 ioc_status;
494 u8 skey, asc, ascq;
495
496 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700497
498 switch (ioc_status) {
499
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530500 case MPI_IOCSTATUS_SUCCESS:
501 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700502 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530503 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
504 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700505 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530506 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
507 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700508 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530509 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
510 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700511 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530512 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
513 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700514 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530515 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
516 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700517 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530518 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
519 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700520 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530521 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
522 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700523 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530524 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
525 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700526 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530527 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
528 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700529 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530530 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
531 desc = "task management failed";
532 break;
533 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
534 desc = "IOC terminated";
535 break;
536 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
537 desc = "ext terminated";
538 break;
539 default:
540 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700541 break;
542 }
543
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530544 switch (pScsiReply->SCSIStatus)
545 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700546
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530547 case MPI_SCSI_STATUS_SUCCESS:
548 desc1 = "success";
549 break;
550 case MPI_SCSI_STATUS_CHECK_CONDITION:
551 desc1 = "check condition";
552 break;
553 case MPI_SCSI_STATUS_CONDITION_MET:
554 desc1 = "condition met";
555 break;
556 case MPI_SCSI_STATUS_BUSY:
557 desc1 = "busy";
558 break;
559 case MPI_SCSI_STATUS_INTERMEDIATE:
560 desc1 = "intermediate";
561 break;
562 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
563 desc1 = "intermediate condmet";
564 break;
565 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
566 desc1 = "reservation conflict";
567 break;
568 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
569 desc1 = "command terminated";
570 break;
571 case MPI_SCSI_STATUS_TASK_SET_FULL:
572 desc1 = "task set full";
573 break;
574 case MPI_SCSI_STATUS_ACA_ACTIVE:
575 desc1 = "aca active";
576 break;
577 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
578 desc1 = "fcpext device logged out";
579 break;
580 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
581 desc1 = "fcpext no link";
582 break;
583 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
584 desc1 = "fcpext unassigned";
585 break;
586 default:
587 desc1 = "";
588 break;
589 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700590
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530591 scsi_print_command(sc);
Eric Moore29dd3602007-09-14 18:46:51 -0600592 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
593 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
594 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
595 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
596 scsi_get_resid(sc));
597 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
598 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530599 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Eric Moore29dd3602007-09-14 18:46:51 -0600600 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530601 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600602 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530603 pScsiReply->SCSIState);
604
605 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
606 skey = sc->sense_buffer[2] & 0x0F;
607 asc = sc->sense_buffer[12];
608 ascq = sc->sense_buffer[13];
609
Eric Moore29dd3602007-09-14 18:46:51 -0600610 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
611 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530612 }
613
614 /*
615 * Look for + dump FCP ResponseInfo[]!
616 */
617 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
618 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600619 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
620 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700621}
622#endif
623
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
625/*
626 * mptscsih_io_done - Main SCSI IO callback routine registered to
627 * Fusion MPT (base) driver
628 * @ioc: Pointer to MPT_ADAPTER structure
629 * @mf: Pointer to original MPT request frame
630 * @r: Pointer to MPT reply frame (NULL if TurboReply)
631 *
632 * This routine is called from mpt.c::mpt_interrupt() at the completion
633 * of any SCSI IO request.
634 * This routine is registered with the Fusion MPT (base) driver at driver
635 * load/init time via the mpt_register() API call.
636 *
637 * Returns 1 indicating alloc'd request frame ptr should be freed.
638 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400639int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
641{
642 struct scsi_cmnd *sc;
643 MPT_SCSI_HOST *hd;
644 SCSIIORequest_t *pScsiReq;
645 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700646 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600647 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600648 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
651
652 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700653 req_idx_MR = (mr != NULL) ?
654 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
655 if ((req_idx != req_idx_MR) ||
656 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
657 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
658 ioc->name);
659 printk (MYIOC_s_ERR_FMT
660 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
661 ioc->name, req_idx, req_idx_MR, mf, mr,
662 hd->ScsiLookup[req_idx_MR]);
663 return 0;
664 }
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 sc = hd->ScsiLookup[req_idx];
Eric Moore3dc0b032006-07-11 17:32:33 -0600667 hd->ScsiLookup[req_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (sc == NULL) {
669 MPIHeader_t *hdr = (MPIHeader_t *)mf;
670
671 /* Remark: writeSDP1 will use the ScsiDoneCtx
672 * If a SCSI I/O cmd, device disabled by OS and
673 * completion done. Cannot touch sc struct. Just free mem.
674 */
675 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
676 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
677 ioc->name);
678
679 mptscsih_freeChainBuffers(ioc, req_idx);
680 return 1;
681 }
682
Eric Moore3dc0b032006-07-11 17:32:33 -0600683 if ((unsigned char *)mf != sc->host_scribble) {
684 mptscsih_freeChainBuffers(ioc, req_idx);
685 return 1;
686 }
687
688 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 sc->result = DID_OK << 16; /* Set default reply as OK */
690 pScsiReq = (SCSIIORequest_t *) mf;
691 pScsiReply = (SCSIIOReply_t *) mr;
692
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200693 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530694 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200695 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
696 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
697 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530698 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200699 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
700 ioc->name, mf, mr, sc, req_idx));
701 }
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if (pScsiReply == NULL) {
704 /* special context reply handling */
705 ;
706 } else {
707 u32 xfer_cnt;
708 u16 status;
709 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700710 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
713 scsi_state = pScsiReply->SCSIState;
714 scsi_status = pScsiReply->SCSIStatus;
715 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900716 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700717 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600719 /*
720 * if we get a data underrun indication, yet no data was
721 * transferred and the SCSI status indicates that the
722 * command was never started, change the data underrun
723 * to success
724 */
725 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
726 (scsi_status == MPI_SCSI_STATUS_BUSY ||
727 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
728 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
729 status = MPI_IOCSTATUS_SUCCESS;
730 }
731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400733 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /*
736 * Look for + dump FCP ResponseInfo[]!
737 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600738 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
739 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600740 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
741 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700742 sc->device->host->host_no, sc->device->channel,
743 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 le32_to_cpu(pScsiReply->ResponseInfo));
745 }
746
747 switch(status) {
748 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
749 /* CHECKME!
750 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
751 * But not: DID_BUS_BUSY lest one risk
752 * killing interrupt handler:-(
753 */
754 sc->result = SAM_STAT_BUSY;
755 break;
756
757 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
758 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
759 sc->result = DID_BAD_TARGET << 16;
760 break;
761
762 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
763 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600764 if (ioc->bus_type != FC)
765 sc->result = DID_NO_CONNECT << 16;
766 /* else fibre, just stall until rescan event */
767 else
768 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
771 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600772
Eric Moorea69de502007-09-14 18:48:19 -0600773 vdevice = sc->device->hostdata;
774 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600775 break;
Eric Moorea69de502007-09-14 18:48:19 -0600776 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600777 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
778 mptscsih_issue_sep_command(ioc, vtarget,
779 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
780 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 break;
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600785 if ( ioc->bus_type == SAS ) {
786 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
787 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700788 if ((log_info & SAS_LOGINFO_MASK)
789 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600790 sc->result = (DID_BUS_BUSY << 16);
791 break;
792 }
793 }
Eric Moore86dd4242007-01-04 20:44:01 -0700794 } else if (ioc->bus_type == FC) {
795 /*
796 * The FC IOC may kill a request for variety of
797 * reasons, some of which may be recovered by a
798 * retry, some which are unlikely to be
799 * recovered. Return DID_ERROR instead of
800 * DID_RESET to permit retry of the command,
801 * just not an infinite number of them
802 */
803 sc->result = DID_ERROR << 16;
804 break;
Eric Moorebf451522006-07-11 17:25:35 -0600805 }
806
807 /*
808 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
809 */
810
811 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
813 /* Linux handles an unsolicited DID_RESET better
814 * than an unsolicited DID_ABORT.
815 */
816 sc->result = DID_RESET << 16;
817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 break;
819
820 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900821 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600822 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
823 sc->result=DID_SOFT_ERROR << 16;
824 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600826 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700827 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600828 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
832 /*
833 * Do upfront check for valid SenseData and give it
834 * precedence!
835 */
836 sc->result = (DID_OK << 16) | scsi_status;
837 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
838 /* Have already saved the status and sense data
839 */
840 ;
841 } else {
842 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600843 if (scsi_status == SAM_STAT_BUSY)
844 sc->result = SAM_STAT_BUSY;
845 else
846 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
849 /* What to do?
850 */
851 sc->result = DID_SOFT_ERROR << 16;
852 }
853 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
854 /* Not real sure here either... */
855 sc->result = DID_RESET << 16;
856 }
857 }
858
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530859
Eric Moore29dd3602007-09-14 18:46:51 -0600860 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
861 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
862 ioc->name, sc->underflow));
863 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
864 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /* Report Queue Full
867 */
868 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
869 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 break;
872
Moore, Eric7e551472006-01-16 18:53:21 -0700873 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900874 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
876 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600877 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (scsi_state == 0) {
879 ;
880 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
881 /*
882 * If running against circa 200003dd 909 MPT f/w,
883 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
884 * (QUEUE_FULL) returned from device! --> get 0x0000?128
885 * and with SenseBytes set to 0.
886 */
887 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
888 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
889
890 }
891 else if (scsi_state &
892 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
893 ) {
894 /*
895 * What to do?
896 */
897 sc->result = DID_SOFT_ERROR << 16;
898 }
899 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
900 /* Not real sure here either... */
901 sc->result = DID_RESET << 16;
902 }
903 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
904 /* Device Inq. data indicates that it supports
905 * QTags, but rejects QTag messages.
906 * This command completed OK.
907 *
908 * Not real sure here either so do nothing... */
909 }
910
911 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
912 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
913
914 /* Add handling of:
915 * Reservation Conflict, Busy,
916 * Command Terminated, CHECK
917 */
918 break;
919
920 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
921 sc->result = DID_SOFT_ERROR << 16;
922 break;
923
924 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
925 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
926 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
927 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
928 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
929 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
930 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
932 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
933 default:
934 /*
935 * What to do?
936 */
937 sc->result = DID_SOFT_ERROR << 16;
938 break;
939
940 } /* switch(status) */
941
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530942#ifdef CONFIG_FUSION_LOGGING
943 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
944 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700945#endif
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 } /* end of address reply case */
948
949 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900950 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 sc->scsi_done(sc); /* Issue the command callback */
953
954 /* Free Chain buffers */
955 mptscsih_freeChainBuffers(ioc, req_idx);
956 return 1;
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*
960 * mptscsih_flush_running_cmds - For each command found, search
961 * Scsi_Host instance taskQ and reply to OS.
962 * Called only if recovering from a FW reload.
963 * @hd: Pointer to a SCSI HOST structure
964 *
965 * Returns: None.
966 *
967 * Must be called while new I/Os are being queued.
968 */
969static void
970mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
971{
972 MPT_ADAPTER *ioc = hd->ioc;
973 struct scsi_cmnd *SCpnt;
974 MPT_FRAME_HDR *mf;
975 int ii;
976 int max = ioc->req_depth;
977
Eric Moore29dd3602007-09-14 18:46:51 -0600978 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": flush_ScsiLookup called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 for (ii= 0; ii < max; ii++) {
980 if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
981
982 /* Command found.
983 */
984
985 /* Null ScsiLookup index
986 */
987 hd->ScsiLookup[ii] = NULL;
988
989 mf = MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore29dd3602007-09-14 18:46:51 -0600990 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": flush: ScsiDone (mf=%p,sc=%p)\n",
991 ioc->name, mf, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Eric Moore3dc0b032006-07-11 17:32:33 -0600993 /* Free Chain buffers */
994 mptscsih_freeChainBuffers(ioc, ii);
995
996 /* Free Message frames */
997 mpt_free_msg_frame(ioc, mf);
998
999 if ((unsigned char *)mf != SCpnt->host_scribble)
1000 continue;
1001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 /* Set status, free OS resources (SG DMA buffers)
1003 * Do OS callback
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001005 scsi_dma_unmap(SCpnt);
1006
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 SCpnt->result = DID_RESET << 16;
1008 SCpnt->host_scribble = NULL;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 SCpnt->scsi_done(SCpnt); /* Issue the command callback */
1011 }
1012 }
1013
1014 return;
1015}
1016
1017/*
1018 * mptscsih_search_running_cmds - Delete any commands associated
1019 * with the specified target and lun. Function called only
1020 * when a lun is disable by mid-layer.
1021 * Do NOT access the referenced scsi_cmnd structure or
1022 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001023 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001024 * @hd: Pointer to a SCSI HOST structure
1025 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 *
1027 * Returns: None.
1028 *
1029 * Called from slave_destroy.
1030 */
1031static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001032mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
1034 SCSIIORequest_t *mf = NULL;
1035 int ii;
1036 int max = hd->ioc->req_depth;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001037 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001038 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -06001039 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Eric Mooree80b0022007-09-14 18:49:03 -06001041 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": search_running channel %d id %d lun %d max %d\n",
1042 ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 for (ii=0; ii < max; ii++) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001045 if ((sc = hd->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Eric Mooree80b0022007-09-14 18:49:03 -06001047 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001048 if (mf == NULL)
1049 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001050 /* If the device is a hidden raid component, then its
1051 * expected that the mf->function will be RAID_SCSI_IO
1052 */
1053 if (vdevice->vtarget->tflags &
1054 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1055 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1056 continue;
1057
Eric Moore793955f2007-01-29 09:42:20 -07001058 int_to_scsilun(vdevice->lun, &lun);
1059 if ((mf->Bus != vdevice->vtarget->channel) ||
1060 (mf->TargetID != vdevice->vtarget->id) ||
1061 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 continue;
1063
1064 /* Cleanup
1065 */
1066 hd->ScsiLookup[ii] = NULL;
Eric Mooree80b0022007-09-14 18:49:03 -06001067 mptscsih_freeChainBuffers(ioc, ii);
1068 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
Eric Moore3dc0b032006-07-11 17:32:33 -06001069 if ((unsigned char *)mf != sc->host_scribble)
1070 continue;
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001071 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001072 sc->host_scribble = NULL;
1073 sc->result = DID_NO_CONNECT << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001074 sdev_printk(MYIOC_s_INFO_FMT, sc->device, "completing cmds: fw_channel %d,"
Eric Mooree80b0022007-09-14 18:49:03 -06001075 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301076 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001077 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 }
1079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 return;
1081}
1082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1086/*
1087 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1088 * from a SCSI target device.
1089 * @sc: Pointer to scsi_cmnd structure
1090 * @pScsiReply: Pointer to SCSIIOReply_t
1091 * @pScsiReq: Pointer to original SCSI request
1092 *
1093 * This routine periodically reports QUEUE_FULL status returned from a
1094 * SCSI target device. It reports this to the console via kernel
1095 * printk() API call, not more than once every 10 seconds.
1096 */
1097static void
1098mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1099{
1100 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001102 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001104 if (sc->device == NULL)
1105 return;
1106 if (sc->device->host == NULL)
1107 return;
1108 if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
1109 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001110 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001111 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001112 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1113 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001114 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116}
1117
1118/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1119/*
1120 * mptscsih_remove - Removed scsi devices
1121 * @pdev: Pointer to pci_dev structure
1122 *
1123 *
1124 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001125void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126mptscsih_remove(struct pci_dev *pdev)
1127{
1128 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1129 struct Scsi_Host *host = ioc->sh;
1130 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001131 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001133 if(!host) {
1134 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 scsi_remove_host(host);
1139
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001140 if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
1141 return;
1142
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001143 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001145 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001147 if (hd->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001148 sz1 = ioc->req_depth * sizeof(void *);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001149 kfree(hd->ScsiLookup);
1150 hd->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152
Eric Mooree80b0022007-09-14 18:49:03 -06001153 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001154 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001155 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001157 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001158
1159 /* NULL the Scsi_Host pointer
1160 */
Eric Mooree80b0022007-09-14 18:49:03 -06001161 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001162
1163 scsi_host_put(host);
1164
1165 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167}
1168
1169/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1170/*
1171 * mptscsih_shutdown - reboot notifier
1172 *
1173 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001174void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001175mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001177 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 struct Scsi_Host *host = ioc->sh;
1179 MPT_SCSI_HOST *hd;
1180
1181 if(!host)
1182 return;
1183
1184 hd = (MPT_SCSI_HOST *)host->hostdata;
1185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186}
1187
1188#ifdef CONFIG_PM
1189/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1190/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001191 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 *
1193 *
1194 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001195int
Pavel Machek8d189f72005-04-16 15:25:28 -07001196mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001198 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001199 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200}
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/*
1204 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1205 *
1206 *
1207 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001208int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209mptscsih_resume(struct pci_dev *pdev)
1210{
Hormsb364fd52007-03-19 15:06:44 +09001211 return mpt_resume(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
1214#endif
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1217/**
1218 * mptscsih_info - Return information about MPT adapter
1219 * @SChost: Pointer to Scsi_Host structure
1220 *
1221 * (linux scsi_host_template.info routine)
1222 *
1223 * Returns pointer to buffer where information was written.
1224 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001225const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226mptscsih_info(struct Scsi_Host *SChost)
1227{
1228 MPT_SCSI_HOST *h;
1229 int size = 0;
1230
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 h = (MPT_SCSI_HOST *)SChost->hostdata;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001234 if (h->info_kbuf == NULL)
1235 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1236 return h->info_kbuf;
1237 h->info_kbuf[0] = '\0';
1238
1239 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1240 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 }
1242
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001243 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244}
1245
1246struct info_str {
1247 char *buffer;
1248 int length;
1249 int offset;
1250 int pos;
1251};
1252
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001253static void
1254mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
1256 if (info->pos + len > info->length)
1257 len = info->length - info->pos;
1258
1259 if (info->pos + len < info->offset) {
1260 info->pos += len;
1261 return;
1262 }
1263
1264 if (info->pos < info->offset) {
1265 data += (info->offset - info->pos);
1266 len -= (info->offset - info->pos);
1267 }
1268
1269 if (len > 0) {
1270 memcpy(info->buffer + info->pos, data, len);
1271 info->pos += len;
1272 }
1273}
1274
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001275static int
1276mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277{
1278 va_list args;
1279 char buf[81];
1280 int len;
1281
1282 va_start(args, fmt);
1283 len = vsprintf(buf, fmt, args);
1284 va_end(args);
1285
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001286 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 return len;
1288}
1289
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001290static int
1291mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
1293 struct info_str info;
1294
1295 info.buffer = pbuf;
1296 info.length = len;
1297 info.offset = offset;
1298 info.pos = 0;
1299
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001300 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1301 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1302 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1303 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1306}
1307
1308/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1309/**
1310 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001311 * @host: scsi host struct
1312 * @buffer: if write, user data; if read, buffer for user
1313 * @start: returns the buffer address
1314 * @offset: if write, 0; if read, the current offset into the buffer from
1315 * the previous read.
1316 * @length: if write, return length;
1317 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 *
1319 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001321int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1323 int length, int func)
1324{
1325 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1326 MPT_ADAPTER *ioc = hd->ioc;
1327 int size = 0;
1328
1329 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001330 /*
1331 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 */
1333 } else {
1334 if (start)
1335 *start = buffer;
1336
1337 size = mptscsih_host_info(ioc, buffer, offset, length);
1338 }
1339
1340 return size;
1341}
1342
1343/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1344#define ADD_INDEX_LOG(req_ent) do { } while(0)
1345
1346/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1347/**
1348 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1349 * @SCpnt: Pointer to scsi_cmnd structure
1350 * @done: Pointer SCSI mid-layer IO completion function
1351 *
1352 * (linux scsi_host_template.queuecommand routine)
1353 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1354 * from a linux scsi_cmnd request and send it to the IOC.
1355 *
1356 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1357 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001358int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1360{
1361 MPT_SCSI_HOST *hd;
1362 MPT_FRAME_HDR *mf;
1363 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001364 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 int lun;
1366 u32 datalen;
1367 u32 scsictl;
1368 u32 scsidir;
1369 u32 cmd_len;
1370 int my_idx;
1371 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301372 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301375 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 lun = SCpnt->device->lun;
1377 SCpnt->scsi_done = done;
1378
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301379 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1380 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
1382 if (hd->resetPending) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301383 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1384 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 return SCSI_MLQUEUE_HOST_BUSY;
1386 }
1387
1388 /*
1389 * Put together a MPT SCSI request...
1390 */
Eric Mooree80b0022007-09-14 18:49:03 -06001391 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301392 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1393 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 return SCSI_MLQUEUE_HOST_BUSY;
1395 }
1396
1397 pScsiReq = (SCSIIORequest_t *) mf;
1398
1399 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1400
1401 ADD_INDEX_LOG(my_idx);
1402
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001403 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 * Seems we may receive a buffer (datalen>0) even when there
1405 * will be no data transfer! GRRRRR...
1406 */
1407 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001408 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1410 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001411 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1413 } else {
1414 datalen = 0;
1415 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1416 }
1417
1418 /* Default to untagged. Once a target structure has been allocated,
1419 * use the Inquiry data to determine if device supports tagged.
1420 */
Eric Moorea69de502007-09-14 18:48:19 -06001421 if (vdevice
1422 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 && (SCpnt->device->tagged_supported)) {
1424 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1425 } else {
1426 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1427 }
1428
1429 /* Use the above information to set up the message frame
1430 */
Eric Moorea69de502007-09-14 18:48:19 -06001431 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1432 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001434 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001435 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1436 else
1437 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 pScsiReq->CDBLength = SCpnt->cmd_len;
1439 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1440 pScsiReq->Reserved = 0;
1441 pScsiReq->MsgFlags = mpt_msg_flags();
Eric Moore793955f2007-01-29 09:42:20 -07001442 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 pScsiReq->Control = cpu_to_le32(scsictl);
1444
1445 /*
1446 * Write SCSI CDB into the message
1447 */
1448 cmd_len = SCpnt->cmd_len;
1449 for (ii=0; ii < cmd_len; ii++)
1450 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1451
1452 for (ii=cmd_len; ii < 16; ii++)
1453 pScsiReq->CDB[ii] = 0;
1454
1455 /* DataLength */
1456 pScsiReq->DataLength = cpu_to_le32(datalen);
1457
1458 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001459 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1461
1462 /* Now add the SG list
1463 * Always have a SGE even if null length.
1464 */
1465 if (datalen == 0) {
1466 /* Add a NULL SGE */
1467 mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
1468 (dma_addr_t) -1);
1469 } else {
1470 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001471 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 goto fail;
1473 }
1474
Eric Moore3dc0b032006-07-11 17:32:33 -06001475 SCpnt->host_scribble = (unsigned char *)mf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 hd->ScsiLookup[my_idx] = SCpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Eric Mooree80b0022007-09-14 18:49:03 -06001478 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301479 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1480 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001481 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 return 0;
1483
1484 fail:
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001485 hd->ScsiLookup[my_idx] = NULL;
Eric Mooree80b0022007-09-14 18:49:03 -06001486 mptscsih_freeChainBuffers(ioc, my_idx);
1487 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 return SCSI_MLQUEUE_HOST_BUSY;
1489}
1490
1491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1492/*
1493 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1494 * with a SCSI IO request
1495 * @hd: Pointer to the MPT_SCSI_HOST instance
1496 * @req_idx: Index of the SCSI IO request frame.
1497 *
1498 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1499 * No return.
1500 */
1501static void
1502mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1503{
1504 MPT_FRAME_HDR *chain;
1505 unsigned long flags;
1506 int chain_idx;
1507 int next;
1508
1509 /* Get the first chain index and reset
1510 * tracker state.
1511 */
1512 chain_idx = ioc->ReqToChain[req_idx];
1513 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1514
1515 while (chain_idx != MPT_HOST_NO_CHAIN) {
1516
1517 /* Save the next chain buffer index */
1518 next = ioc->ChainToChain[chain_idx];
1519
1520 /* Free this chain buffer and reset
1521 * tracker
1522 */
1523 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1524
1525 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1526 + (chain_idx * ioc->req_sz));
1527
1528 spin_lock_irqsave(&ioc->FreeQlock, flags);
1529 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1530 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1531
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301532 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 ioc->name, chain_idx));
1534
1535 /* handle next */
1536 chain_idx = next;
1537 }
1538 return;
1539}
1540
1541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1542/*
1543 * Reset Handling
1544 */
1545
1546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001547/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001549 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001551 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001552 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 * @lun: Logical Unit for reset (if appropriate)
1554 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001555 * @timeout: timeout for task management control
1556 *
1557 * Fall through to mpt_HardResetHandler if: not operational, too many
1558 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 *
1560 * Remark: Currently invoked from a non-interrupt thread (_bh).
1561 *
1562 * Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
1563 * will be active.
1564 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001565 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001566 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001567int
Eric Moore793955f2007-01-29 09:42:20 -07001568mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569{
1570 MPT_ADAPTER *ioc;
1571 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 u32 ioc_raw_state;
1573 unsigned long flags;
1574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 ioc = hd->ioc;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301576 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
1578 // SJR - CHECKME - Can we avoid this here?
1579 // (mpt_HardResetHandler has this check...)
1580 spin_lock_irqsave(&ioc->diagLock, flags);
1581 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1582 spin_unlock_irqrestore(&ioc->diagLock, flags);
1583 return FAILED;
1584 }
1585 spin_unlock_irqrestore(&ioc->diagLock, flags);
1586
1587 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001588 * If we time out and not bus reset, then we return a FAILED status
1589 * to the caller.
1590 * The call to mptscsih_tm_pending_wait() will set the pending flag
1591 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 * successful. Otherwise, reload the FW.
1593 */
1594 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1595 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Eric Moore29dd3602007-09-14 18:46:51 -06001596 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301598 ioc->name, hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 return FAILED;
1600 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06001601 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
Eric Moorecd2c6192007-01-29 09:47:47 -07001602 "reset: Timed out waiting for last TM (%d) "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301603 "to complete! \n", ioc->name,
Eric Moorecd2c6192007-01-29 09:47:47 -07001604 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return FAILED;
1606 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001607 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301609 ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001610 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06001613 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 hd->tmPending |= (1 << type);
Eric Mooree80b0022007-09-14 18:49:03 -06001615 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 }
1617
Eric Mooree80b0022007-09-14 18:49:03 -06001618 ioc_raw_state = mpt_GetIocState(ioc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1621 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001622 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1623 ioc->name, type, ioc_raw_state);
Eric Moore29dd3602007-09-14 18:46:51 -06001624 printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001625 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06001626 printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
1627 "FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001628 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 }
1630
Eric Moorecd2c6192007-01-29 09:47:47 -07001631 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1632 printk(MYIOC_s_WARN_FMT
1633 "TM Handler for type=%x: ioc_state: "
1634 "DOORBELL_ACTIVE (0x%x)!\n",
1635 ioc->name, type, ioc_raw_state);
1636 return FAILED;
1637 }
1638
1639 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001641 if (hd->hard_resets < -1)
1642 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Eric Moorecd2c6192007-01-29 09:47:47 -07001644 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1645 ctx2abort, timeout);
1646 if (rc)
1647 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301648 ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001649 else
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301650 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1651 ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001652
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301653 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1654 "TMHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 return rc;
1657}
1658
1659
1660/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001661/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1663 * @hd: Pointer to MPT_SCSI_HOST structure
1664 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001665 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001666 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 * @lun: Logical Unit for reset (if appropriate)
1668 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001669 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 *
1671 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1672 * or a non-interrupt thread. In the former, must not call schedule().
1673 *
1674 * Not all fields are meaningfull for all task types.
1675 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001676 * Returns 0 for SUCCESS, or FAILED.
1677 *
1678 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679static int
Eric Moore793955f2007-01-29 09:42:20 -07001680mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681{
1682 MPT_FRAME_HDR *mf;
1683 SCSITaskMgmt_t *pScsiTm;
1684 int ii;
1685 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001686 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 /* Return Fail to calling function if no message frames available.
1689 */
Eric Mooree80b0022007-09-14 18:49:03 -06001690 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
1691 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1692 ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001693 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 }
Eric Mooree80b0022007-09-14 18:49:03 -06001695 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
1696 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
1698 /* Format the Request
1699 */
1700 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001701 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 pScsiTm->Bus = channel;
1703 pScsiTm->ChainOffset = 0;
1704 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1705
1706 pScsiTm->Reserved = 0;
1707 pScsiTm->TaskType = type;
1708 pScsiTm->Reserved1 = 0;
1709 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1710 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1711
Eric Moore793955f2007-01-29 09:42:20 -07001712 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 for (ii=0; ii < 7; ii++)
1715 pScsiTm->Reserved2[ii] = 0;
1716
1717 pScsiTm->TaskMsgContext = ctx2abort;
1718
Eric Mooree80b0022007-09-14 18:49:03 -06001719 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1720 "type=%d\n", ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301722 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
Eric Mooree80b0022007-09-14 18:49:03 -06001724 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1725 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1726 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301727 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001728 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301729 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1730 if (retval) {
Eric Mooree80b0022007-09-14 18:49:03 -06001731 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
1732 " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
1733 ioc, mf, retval));
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301734 goto fail_out;
1735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 }
1737
1738 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Mooree80b0022007-09-14 18:49:03 -06001739 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
1740 " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
1741 ioc, mf));
1742 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
1743 ioc->name));
1744 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1745 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
1746 ioc->name, retval));
Eric Moorecd2c6192007-01-29 09:47:47 -07001747 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 }
1749
Eric Moorecd2c6192007-01-29 09:47:47 -07001750 /*
1751 * Handle success case, see if theres a non-zero ioc_status.
1752 */
1753 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1754 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1755 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1756 retval = 0;
1757 else
1758 retval = FAILED;
1759
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001761
1762 fail_out:
1763
1764 /*
1765 * Free task managment mf, and corresponding tm flags
1766 */
Eric Mooree80b0022007-09-14 18:49:03 -06001767 mpt_free_msg_frame(ioc, mf);
Eric Moorecd2c6192007-01-29 09:47:47 -07001768 hd->tmPending = 0;
1769 hd->tmState = TM_STATE_NONE;
1770 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771}
1772
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001773static int
1774mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1775{
1776 switch (ioc->bus_type) {
1777 case FC:
1778 return 40;
1779 case SAS:
1780 return 10;
1781 case SPI:
1782 default:
1783 return 2;
1784 }
1785}
1786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1788/**
1789 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1790 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1791 *
1792 * (linux scsi_host_template.eh_abort_handler routine)
1793 *
1794 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001795 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001796int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797mptscsih_abort(struct scsi_cmnd * SCpnt)
1798{
1799 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 MPT_FRAME_HDR *mf;
1801 u32 ctx2abort;
1802 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001803 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001804 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001805 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001806 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
1808 /* If we can't locate our host adapter structure, return FAILED status.
1809 */
1810 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
1811 SCpnt->result = DID_RESET << 16;
1812 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001813 printk(KERN_ERR MYNAM ": task abort: "
1814 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 return FAILED;
1816 }
1817
Eric Moore958d4a32007-06-15 17:24:14 -06001818 ioc = hd->ioc;
1819 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1820 ioc->name, SCpnt);
1821 scsi_print_command(SCpnt);
1822
1823 vdevice = SCpnt->device->hostdata;
1824 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001825 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1826 "task abort: device has been deleted (sc=%p)\n",
1827 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001828 SCpnt->result = DID_NO_CONNECT << 16;
1829 SCpnt->scsi_done(SCpnt);
1830 retval = 0;
1831 goto out;
1832 }
1833
Eric Moorecc78d302007-06-15 17:27:21 -06001834 /* Task aborts are not supported for hidden raid components.
1835 */
1836 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001837 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1838 "task abort: hidden raid component (sc=%p)\n",
1839 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001840 SCpnt->result = DID_RESET << 16;
1841 retval = FAILED;
1842 goto out;
1843 }
1844
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 /* Find this command
1846 */
1847 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001848 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 * Do OS callback.
1850 */
1851 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001852 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001853 "Command not in the active list! (sc=%p)\n", ioc->name,
1854 SCpnt));
1855 retval = 0;
1856 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 }
1858
Eric Moore958d4a32007-06-15 17:24:14 -06001859 if (hd->resetPending) {
1860 retval = FAILED;
1861 goto out;
1862 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001863
1864 if (hd->timeouts < -1)
1865 hd->timeouts++;
1866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1868 * (the IO to be ABORT'd)
1869 *
1870 * NOTE: Since we do not byteswap MsgContext, we do not
1871 * swap it here either. It is an opaque cookie to
1872 * the controller, so it does not matter. -DaveM
1873 */
Eric Mooree80b0022007-09-14 18:49:03 -06001874 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1876
1877 hd->abortSCpnt = SCpnt;
1878
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001879 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001880 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1881 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
Eric Moore3dc0b032006-07-11 17:32:33 -06001883 if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001884 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001885 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001886
Eric Moore958d4a32007-06-15 17:24:14 -06001887 out:
1888 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1889 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001891 if (retval == 0)
1892 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001893 else
1894 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895}
1896
1897/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1898/**
1899 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1900 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1901 *
1902 * (linux scsi_host_template.eh_dev_reset_handler routine)
1903 *
1904 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001905 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001906int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1908{
1909 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001910 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001911 VirtDevice *vdevice;
1912 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
1914 /* If we can't locate our host adapter structure, return FAILED status.
1915 */
1916 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001917 printk(KERN_ERR MYNAM ": target reset: "
1918 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 return FAILED;
1920 }
1921
Eric Moore958d4a32007-06-15 17:24:14 -06001922 ioc = hd->ioc;
1923 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1924 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001925 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Eric Moore958d4a32007-06-15 17:24:14 -06001927 if (hd->resetPending) {
1928 retval = FAILED;
1929 goto out;
1930 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001931
Eric Moore958d4a32007-06-15 17:24:14 -06001932 vdevice = SCpnt->device->hostdata;
1933 if (!vdevice || !vdevice->vtarget) {
1934 retval = 0;
1935 goto out;
1936 }
1937
Eric Moorecc78d302007-06-15 17:27:21 -06001938 /* Target reset to hidden raid component is not supported
1939 */
1940 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1941 retval = FAILED;
1942 goto out;
1943 }
1944
Eric Moore958d4a32007-06-15 17:24:14 -06001945 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1946 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1947 mptscsih_get_tm_timeout(ioc));
1948
1949 out:
1950 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1951 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001952
1953 if (retval == 0)
1954 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001955 else
1956 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
Eric Moorecd2c6192007-01-29 09:47:47 -07001959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1961/**
1962 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1963 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1964 *
1965 * (linux scsi_host_template.eh_bus_reset_handler routine)
1966 *
1967 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001968 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001969int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1971{
1972 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001973 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001974 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001975 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 /* If we can't locate our host adapter structure, return FAILED status.
1978 */
1979 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001980 printk(KERN_ERR MYNAM ": bus reset: "
1981 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return FAILED;
1983 }
1984
Eric Moore958d4a32007-06-15 17:24:14 -06001985 ioc = hd->ioc;
1986 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1987 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001988 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
1990 if (hd->timeouts < -1)
1991 hd->timeouts++;
1992
Eric Moorea69de502007-09-14 18:48:19 -06001993 vdevice = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001994 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moorea69de502007-09-14 18:48:19 -06001995 vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Eric Moore958d4a32007-06-15 17:24:14 -06001997 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1998 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001999
2000 if (retval == 0)
2001 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07002002 else
2003 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004}
2005
2006/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2007/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002008 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
2010 *
2011 * (linux scsi_host_template.eh_host_reset_handler routine)
2012 *
2013 * Returns SUCCESS or FAILED.
2014 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002015int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2017{
2018 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06002019 int retval;
2020 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
2022 /* If we can't locate the host to reset, then we failed. */
2023 if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06002024 printk(KERN_ERR MYNAM ": host reset: "
2025 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 return FAILED;
2027 }
2028
Eric Moore958d4a32007-06-15 17:24:14 -06002029 ioc = hd->ioc;
2030 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2031 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033 /* If our attempts to reset the host failed, then return a failed
2034 * status. The host will be taken off line by the SCSI mid-layer.
2035 */
Eric Mooree80b0022007-09-14 18:49:03 -06002036 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06002037 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 } else {
2039 /* Make sure TM pending is cleared and TM state is set to
2040 * NONE.
2041 */
Eric Moore958d4a32007-06-15 17:24:14 -06002042 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 hd->tmPending = 0;
2044 hd->tmState = TM_STATE_NONE;
2045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
Eric Moore958d4a32007-06-15 17:24:14 -06002047 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2048 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Eric Moore958d4a32007-06-15 17:24:14 -06002050 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051}
2052
2053/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2054/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002055 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 * @hd: Pointer to MPT host structure.
2057 *
2058 * Returns {SUCCESS,FAILED}.
2059 */
2060static int
2061mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
2062{
2063 unsigned long flags;
2064 int loop_count = 4 * 10; /* Wait 10 seconds */
2065 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06002066 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
2068 do {
Eric Mooree80b0022007-09-14 18:49:03 -06002069 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (hd->tmState == TM_STATE_NONE) {
2071 hd->tmState = TM_STATE_IN_PROGRESS;
2072 hd->tmPending = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06002073 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002074 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 break;
2076 }
Eric Mooree80b0022007-09-14 18:49:03 -06002077 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 msleep(250);
2079 } while (--loop_count);
2080
2081 return status;
2082}
2083
2084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2085/**
2086 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2087 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002088 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 *
2090 * Returns {SUCCESS,FAILED}.
2091 */
2092static int
2093mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2094{
2095 unsigned long flags;
2096 int loop_count = 4 * timeout;
2097 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06002098 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
2100 do {
Eric Mooree80b0022007-09-14 18:49:03 -06002101 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 if(hd->tmPending == 0) {
2103 status = SUCCESS;
Eric Mooree80b0022007-09-14 18:49:03 -06002104 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 break;
2106 }
Eric Mooree80b0022007-09-14 18:49:03 -06002107 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002108 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 } while (--loop_count);
2110
2111 return status;
2112}
2113
2114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002115static void
2116mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2117{
2118 char *desc;
2119
2120 switch (response_code) {
2121 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2122 desc = "The task completed.";
2123 break;
2124 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2125 desc = "The IOC received an invalid frame status.";
2126 break;
2127 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2128 desc = "The task type is not supported.";
2129 break;
2130 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2131 desc = "The requested task failed.";
2132 break;
2133 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2134 desc = "The task completed successfully.";
2135 break;
2136 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2137 desc = "The LUN request is invalid.";
2138 break;
2139 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2140 desc = "The task is in the IOC queue and has not been sent to target.";
2141 break;
2142 default:
2143 desc = "unknown";
2144 break;
2145 }
2146 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2147 ioc->name, response_code, desc);
2148}
2149
2150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151/**
2152 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2153 * @ioc: Pointer to MPT_ADAPTER structure
2154 * @mf: Pointer to SCSI task mgmt request frame
2155 * @mr: Pointer to SCSI task mgmt reply frame
2156 *
2157 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2158 * of any SCSI task management request.
2159 * This routine is registered with the MPT (base) driver at driver
2160 * load/init time via the mpt_register() API call.
2161 *
2162 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002163 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002164int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2166{
2167 SCSITaskMgmtReply_t *pScsiTmReply;
2168 SCSITaskMgmt_t *pScsiTmReq;
2169 MPT_SCSI_HOST *hd;
2170 unsigned long flags;
2171 u16 iocstatus;
2172 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002173 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302175 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002176 ioc->name, mf, mr));
2177 if (!ioc->sh) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302178 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002179 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 return 1;
2181 }
2182
2183 if (mr == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302184 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002185 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 }
2188
Eric Moorecd2c6192007-01-29 09:47:47 -07002189 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
2190 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2191 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2192 tmType = pScsiTmReq->TaskType;
2193 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2194 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2195
2196 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2197 pScsiTmReply->ResponseCode)
2198 mptscsih_taskmgmt_response_code(ioc,
2199 pScsiTmReply->ResponseCode);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302200 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Eric Moorecd2c6192007-01-29 09:47:47 -07002201
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302202#ifdef CONFIG_FUSION_LOGGING
2203 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2204 (ioc->debug_level & MPT_DEBUG_TM ))
2205 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2206 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
2207 "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
2208 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2209 le16_to_cpu(pScsiTmReply->IOCStatus),
2210 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2211 le32_to_cpu(pScsiTmReply->TerminationCount));
Eric Moorecd2c6192007-01-29 09:47:47 -07002212#endif
2213 if (!iocstatus) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302214 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
Eric Moorecd2c6192007-01-29 09:47:47 -07002215 hd->abortSCpnt = NULL;
2216 goto out;
2217 }
2218
2219 /* Error? (anything non-zero?) */
2220
2221 /* clear flags and continue.
2222 */
2223 switch (tmType) {
2224
2225 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2226 if (termination_count == 1)
2227 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2228 hd->abortSCpnt = NULL;
2229 break;
2230
2231 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2232
2233 /* If an internal command is present
2234 * or the TM failed - reload the FW.
2235 * FC FW may respond FAILED to an ABORT
2236 */
2237 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2238 hd->cmdPtr)
2239 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06002240 printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07002241 break;
2242
2243 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2244 default:
2245 break;
2246 }
2247
2248 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 spin_lock_irqsave(&ioc->FreeQlock, flags);
2250 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002252 hd->tm_iocstatus = iocstatus;
2253 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 return 1;
2256}
2257
2258/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2259/*
2260 * This is anyones guess quite frankly.
2261 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002262int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2264 sector_t capacity, int geom[])
2265{
2266 int heads;
2267 int sectors;
2268 sector_t cylinders;
2269 ulong dummy;
2270
2271 heads = 64;
2272 sectors = 32;
2273
2274 dummy = heads * sectors;
2275 cylinders = capacity;
2276 sector_div(cylinders,dummy);
2277
2278 /*
2279 * Handle extended translation size for logical drives
2280 * > 1Gb
2281 */
2282 if ((ulong)capacity >= 0x200000) {
2283 heads = 255;
2284 sectors = 63;
2285 dummy = heads * sectors;
2286 cylinders = capacity;
2287 sector_div(cylinders,dummy);
2288 }
2289
2290 /* return result */
2291 geom[0] = heads;
2292 geom[1] = sectors;
2293 geom[2] = cylinders;
2294
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 return 0;
2296}
2297
Moore, Ericf44e5462006-03-14 09:14:21 -07002298/* Search IOC page 3 to determine if this is hidden physical disk
2299 *
2300 */
2301int
Eric Moore793955f2007-01-29 09:42:20 -07002302mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002303{
Eric Mooreb506ade2007-01-29 09:45:37 -07002304 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002305 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002306 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002307
Eric Moore793955f2007-01-29 09:42:20 -07002308 if (!ioc->raid_data.pIocPg3)
2309 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002310 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002311 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2312 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2313 rc = 1;
2314 goto out;
2315 }
2316 }
2317
Eric Mooreb506ade2007-01-29 09:45:37 -07002318 /*
2319 * Check inactive list for matching phys disks
2320 */
2321 if (list_empty(&ioc->raid_data.inactive_list))
2322 goto out;
2323
2324 down(&ioc->raid_data.inactive_list_mutex);
2325 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2326 list) {
2327 if ((component_info->d.PhysDiskID == id) &&
2328 (component_info->d.PhysDiskBus == channel))
2329 rc = 1;
2330 }
2331 up(&ioc->raid_data.inactive_list_mutex);
2332
Eric Moore793955f2007-01-29 09:42:20 -07002333 out:
2334 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002335}
2336EXPORT_SYMBOL(mptscsih_is_phys_disk);
2337
Eric Moore793955f2007-01-29 09:42:20 -07002338u8
2339mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002340{
Eric Mooreb506ade2007-01-29 09:45:37 -07002341 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002342 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002343 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002344
Eric Moore793955f2007-01-29 09:42:20 -07002345 if (!ioc->raid_data.pIocPg3)
2346 goto out;
2347 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2348 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2349 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2350 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2351 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002352 }
2353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
Eric Mooreb506ade2007-01-29 09:45:37 -07002355 /*
2356 * Check inactive list for matching phys disks
2357 */
2358 if (list_empty(&ioc->raid_data.inactive_list))
2359 goto out;
2360
2361 down(&ioc->raid_data.inactive_list_mutex);
2362 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2363 list) {
2364 if ((component_info->d.PhysDiskID == id) &&
2365 (component_info->d.PhysDiskBus == channel))
2366 rc = component_info->d.PhysDiskNum;
2367 }
2368 up(&ioc->raid_data.inactive_list_mutex);
2369
Eric Moore793955f2007-01-29 09:42:20 -07002370 out:
2371 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002372}
Eric Moore793955f2007-01-29 09:42:20 -07002373EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002374
2375/*
2376 * OS entry point to allow for host driver to free allocated memory
2377 * Called if no device present or device being unloaded
2378 */
2379void
2380mptscsih_slave_destroy(struct scsi_device *sdev)
2381{
2382 struct Scsi_Host *host = sdev->host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002384 VirtTarget *vtarget;
2385 VirtDevice *vdevice;
2386 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002388 starget = scsi_target(sdev);
2389 vtarget = starget->hostdata;
2390 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002392 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002393 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002394 mptscsih_synchronize_cache(hd, vdevice);
2395 kfree(vdevice);
2396 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397}
2398
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002399/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2400/*
2401 * mptscsih_change_queue_depth - This function will set a devices queue depth
2402 * @sdev: per scsi_device pointer
2403 * @qdepth: requested queue depth
2404 *
2405 * Adding support for new 'change_queue_depth' api.
2406*/
2407int
2408mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002410 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
2411 VirtTarget *vtarget;
2412 struct scsi_target *starget;
2413 int max_depth;
2414 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002415 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002417 starget = scsi_target(sdev);
2418 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002419
Eric Mooree80b0022007-09-14 18:49:03 -06002420 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002421 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002423 else if (sdev->type == TYPE_DISK &&
2424 vtarget->minSyncFactor <= MPT_ULTRA160)
2425 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2426 else
2427 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 } else
2429 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2430
2431 if (qdepth > max_depth)
2432 qdepth = max_depth;
2433 if (qdepth == 1)
2434 tagged = 0;
2435 else
2436 tagged = MSG_SIMPLE_TAG;
2437
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002438 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2439 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440}
2441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442/*
2443 * OS entry point to adjust the queue_depths on a per-device basis.
2444 * Called once per device the bus scan. Use it to force the queue_depth
2445 * member to 1 if a device does not support Q tags.
2446 * Return non-zero if fails.
2447 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002448int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002449mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002451 struct Scsi_Host *sh = sdev->host;
2452 VirtTarget *vtarget;
2453 VirtDevice *vdevice;
2454 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
Eric Mooree80b0022007-09-14 18:49:03 -06002456 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002458 starget = scsi_target(sdev);
2459 vtarget = starget->hostdata;
2460 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Eric Mooree80b0022007-09-14 18:49:03 -06002462 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002463 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002464 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2465 if (ioc->bus_type == SPI)
2466 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002467 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002468 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002469 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002471 if (sdev->id > sh->max_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 /* error case, should never happen */
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002473 scsi_adjust_queue_depth(sdev, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 goto slave_configure_exit;
2475 }
2476
Eric Moore793955f2007-01-29 09:42:20 -07002477 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002478 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
Eric Mooree80b0022007-09-14 18:49:03 -06002480 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002482 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
Eric Mooree80b0022007-09-14 18:49:03 -06002484 if (ioc->bus_type == SPI)
2485 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002486 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002487 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002488 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490slave_configure_exit:
2491
Eric Mooree80b0022007-09-14 18:49:03 -06002492 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002494 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002495 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
2497 return 0;
2498}
2499
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2501/*
2502 * Private routines...
2503 */
2504
2505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2506/* Utility function to copy sense data from the scsi_cmnd buffer
2507 * to the FC and SCSI target structures.
2508 *
2509 */
2510static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002511mptscsih_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 -07002512{
Eric Moorea69de502007-09-14 18:48:19 -06002513 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 SCSIIORequest_t *pReq;
2515 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002516 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
2518 /* Get target structure
2519 */
2520 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002521 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 if (sense_count) {
2524 u8 *sense_data;
2525 int req_index;
2526
2527 /* Copy the sense received into the scsi command block. */
2528 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002529 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2531
2532 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2533 */
Eric Mooree80b0022007-09-14 18:49:03 -06002534 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002535 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002538 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2540 ioc->events[idx].eventContext = ioc->eventContext;
2541
Dave Jones3d9780b2007-05-21 20:59:47 -04002542 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2543 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2544 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
Dave Jones3d9780b2007-05-21 20:59:47 -04002546 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
2548 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002549 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002550 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002551 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002552 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2553 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002554 MPT_TARGET_FLAGS_LED_ON;
2555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 }
2557 }
2558 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002559 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2560 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 }
2562}
2563
Eric Moore3dc0b032006-07-11 17:32:33 -06002564static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
2566{
2567 MPT_SCSI_HOST *hd;
2568 int i;
2569
2570 hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
2571
2572 for (i = 0; i < hd->ioc->req_depth; i++) {
2573 if (hd->ScsiLookup[i] == sc) {
2574 return i;
2575 }
2576 }
2577
2578 return -1;
2579}
2580
2581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002582int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2584{
2585 MPT_SCSI_HOST *hd;
2586 unsigned long flags;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002587 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
Eric Moore29dd3602007-09-14 18:46:51 -06002589 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2590 ": IOC %s_reset routed to SCSI host driver!\n",
2591 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2592 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 /* If a FW reload request arrives after base installed but
2595 * before all scsi hosts have been attached, then an alt_ioc
2596 * may have a NULL sh pointer.
2597 */
2598 if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
2599 return 0;
2600 else
2601 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2602
2603 if (reset_phase == MPT_IOC_SETUP_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302604 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
2606 /* Clean Up:
2607 * 1. Set Hard Reset Pending Flag
2608 * All new commands go to doneQ
2609 */
2610 hd->resetPending = 1;
2611
2612 } else if (reset_phase == MPT_IOC_PRE_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302613 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 /* 2. Flush running commands
2616 * Clean ScsiLookup (and associated memory)
2617 * AND clean mytaskQ
2618 */
2619
2620 /* 2b. Reply to OS all known outstanding I/O commands.
2621 */
2622 mptscsih_flush_running_cmds(hd);
2623
2624 /* 2c. If there was an internal command that
2625 * has not completed, configuration or io request,
2626 * free these resources.
2627 */
2628 if (hd->cmdPtr) {
2629 del_timer(&hd->timer);
2630 mpt_free_msg_frame(ioc, hd->cmdPtr);
2631 }
2632
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302633 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
2635 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302636 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
2638 /* Once a FW reload begins, all new OS commands are
2639 * redirected to the doneQ w/ a reset status.
2640 * Init all control structures.
2641 */
2642
2643 /* ScsiLookup initialization
2644 */
Eric Mooree80b0022007-09-14 18:49:03 -06002645 for (ii=0; ii < ioc->req_depth; ii++)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002646 hd->ScsiLookup[ii] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
2648 /* 2. Chain Buffer initialization
2649 */
2650
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002651 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
2654 /* 5. Enable new commands to be posted
2655 */
2656 spin_lock_irqsave(&ioc->FreeQlock, flags);
2657 hd->tmPending = 0;
2658 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2659 hd->resetPending = 0;
2660 hd->tmState = TM_STATE_NONE;
2661
2662 /* 6. If there was an internal command,
2663 * wake this process up.
2664 */
2665 if (hd->cmdPtr) {
2666 /*
2667 * Wake up the original calling thread
2668 */
2669 hd->pLocal = &hd->localReply;
2670 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002671 hd->scandv_wait_done = 1;
2672 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 hd->cmdPtr = NULL;
2674 }
2675
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302676 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
2678 }
2679
2680 return 1; /* currently means nothing really */
2681}
2682
2683/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002684int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2686{
2687 MPT_SCSI_HOST *hd;
2688 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2689
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302690 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 ioc->name, event));
2692
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002693 if (ioc->sh == NULL ||
2694 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
2695 return 1;
2696
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 switch (event) {
2698 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2699 /* FIXME! */
2700 break;
2701 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2702 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002703 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002704 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 break;
2706 case MPI_EVENT_LOGOUT: /* 09 */
2707 /* FIXME! */
2708 break;
2709
Michael Reed05e8ec12006-01-13 14:31:54 -06002710 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002711 break;
2712
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 /*
2714 * CHECKME! Don't think we need to do
2715 * anything for these, but...
2716 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2718 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2719 /*
2720 * CHECKME! Falling thru...
2721 */
2722 break;
2723
2724 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002725 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 case MPI_EVENT_NONE: /* 00 */
2728 case MPI_EVENT_LOG_DATA: /* 01 */
2729 case MPI_EVENT_STATE_CHANGE: /* 02 */
2730 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2731 default:
Eric Moore29dd3602007-09-14 18:46:51 -06002732 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
2733 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 break;
2735 }
2736
2737 return 1; /* currently means nothing really */
2738}
2739
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2741/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 * Bus Scan and Domain Validation functionality ...
2743 */
2744
2745/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2746/*
2747 * mptscsih_scandv_complete - Scan and DV callback routine registered
2748 * to Fustion MPT (base) driver.
2749 *
2750 * @ioc: Pointer to MPT_ADAPTER structure
2751 * @mf: Pointer to original MPT request frame
2752 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2753 *
2754 * This routine is called from mpt.c::mpt_interrupt() at the completion
2755 * of any SCSI IO request.
2756 * This routine is registered with the Fusion MPT (base) driver at driver
2757 * load/init time via the mpt_register() API call.
2758 *
2759 * Returns 1 indicating alloc'd request frame ptr should be freed.
2760 *
2761 * Remark: Sets a completion code and (possibly) saves sense data
2762 * in the IOC member localReply structure.
2763 * Used ONLY for DV and other internal commands.
2764 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002765int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2767{
2768 MPT_SCSI_HOST *hd;
2769 SCSIIORequest_t *pReq;
2770 int completionCode;
2771 u16 req_idx;
2772
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002773 hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
2774
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 if ((mf == NULL) ||
2776 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2777 printk(MYIOC_s_ERR_FMT
2778 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2779 ioc->name, mf?"BAD":"NULL", (void *) mf);
2780 goto wakeup;
2781 }
2782
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 del_timer(&hd->timer);
2784 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2785 hd->ScsiLookup[req_idx] = NULL;
2786 pReq = (SCSIIORequest_t *) mf;
2787
2788 if (mf != hd->cmdPtr) {
2789 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002790 ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 }
2792 hd->cmdPtr = NULL;
2793
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302794 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002795 ioc->name, mf, mr, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797 hd->pLocal = &hd->localReply;
2798 hd->pLocal->scsiStatus = 0;
2799
2800 /* If target struct exists, clear sense valid flag.
2801 */
2802 if (mr == NULL) {
2803 completionCode = MPT_SCANDV_GOOD;
2804 } else {
2805 SCSIIOReply_t *pReply;
2806 u16 status;
2807 u8 scsi_status;
2808
2809 pReply = (SCSIIOReply_t *) mr;
2810
2811 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2812 scsi_status = pReply->SCSIStatus;
2813
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
2815 switch(status) {
2816
2817 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2818 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2819 break;
2820
2821 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2822 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2823 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2824 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2825 completionCode = MPT_SCANDV_DID_RESET;
2826 break;
2827
2828 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2829 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2830 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2831 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2832 ConfigReply_t *pr = (ConfigReply_t *)mr;
2833 completionCode = MPT_SCANDV_GOOD;
2834 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2835 hd->pLocal->header.PageLength = pr->Header.PageLength;
2836 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2837 hd->pLocal->header.PageType = pr->Header.PageType;
2838
2839 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2840 /* If the RAID Volume request is successful,
2841 * return GOOD, else indicate that
2842 * some type of error occurred.
2843 */
2844 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002845 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 completionCode = MPT_SCANDV_GOOD;
2847 else
2848 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002849 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
2851 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2852 u8 *sense_data;
2853 int sz;
2854
2855 /* save sense data in global structure
2856 */
2857 completionCode = MPT_SCANDV_SENSE;
2858 hd->pLocal->scsiStatus = scsi_status;
Eric Mooree80b0022007-09-14 18:49:03 -06002859 sense_data = ((u8 *)ioc->sense_buf_pool +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2861
2862 sz = min_t(int, pReq->SenseBufferLength,
2863 SCSI_STD_SENSE_BYTES);
2864 memcpy(hd->pLocal->sense, sense_data, sz);
2865
Eric Moore29dd3602007-09-14 18:46:51 -06002866 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
2867 ioc->name, sense_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2869 if (pReq->CDB[0] == INQUIRY)
2870 completionCode = MPT_SCANDV_ISSUE_SENSE;
2871 else
2872 completionCode = MPT_SCANDV_DID_RESET;
2873 }
2874 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2875 completionCode = MPT_SCANDV_DID_RESET;
2876 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2877 completionCode = MPT_SCANDV_DID_RESET;
2878 else {
2879 completionCode = MPT_SCANDV_GOOD;
2880 hd->pLocal->scsiStatus = scsi_status;
2881 }
2882 break;
2883
2884 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2885 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2886 completionCode = MPT_SCANDV_DID_RESET;
2887 else
2888 completionCode = MPT_SCANDV_SOME_ERROR;
2889 break;
2890
2891 default:
2892 completionCode = MPT_SCANDV_SOME_ERROR;
2893 break;
2894
2895 } /* switch(status) */
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 } /* end of address reply case */
2898
2899 hd->pLocal->completion = completionCode;
2900
2901 /* MF and RF are freed in mpt_interrupt
2902 */
2903wakeup:
2904 /* Free Chain buffers (will never chain) in scan or dv */
2905 //mptscsih_freeChainBuffers(ioc, req_idx);
2906
2907 /*
2908 * Wake up the original calling thread
2909 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002910 hd->scandv_wait_done = 1;
2911 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913 return 1;
2914}
2915
2916/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2917/* mptscsih_timer_expired - Call back for timer process.
2918 * Used only for dv functionality.
2919 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2920 *
2921 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002922void
2923mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924{
2925 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002926 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
Eric Mooree80b0022007-09-14 18:49:03 -06002928 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
2930 if (hd->cmdPtr) {
2931 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2932
2933 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2934 /* Desire to issue a task management request here.
2935 * TM requests MUST be single threaded.
2936 * If old eh code and no TM current, issue request.
2937 * If new eh code, do nothing. Wait for OS cmd timeout
2938 * for bus reset.
2939 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 } else {
2941 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002942 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2943 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 }
2945 }
2946 } else {
2947 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002948 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 }
2950
2951 /* No more processing.
2952 * TM call will generate an interrupt for SCSI TM Management.
2953 * The FW will reply to all outstanding commands, callback will finish cleanup.
2954 * Hard reset clean-up will free all resources.
2955 */
Eric Mooree80b0022007-09-14 18:49:03 -06002956 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957
2958 return;
2959}
2960
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
2962/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2963/**
2964 * mptscsih_do_cmd - Do internal command.
2965 * @hd: MPT_SCSI_HOST pointer
2966 * @io: INTERNAL_CMD pointer.
2967 *
2968 * Issue the specified internally generated command and do command
2969 * specific cleanup. For bus scan / DV only.
2970 * NOTES: If command is Inquiry and status is good,
2971 * initialize a target structure, save the data
2972 *
2973 * Remark: Single threaded access only.
2974 *
2975 * Return:
2976 * < 0 if an illegal command or no resources
2977 *
2978 * 0 if good
2979 *
2980 * > 0 if command complete but some type of completion error.
2981 */
2982static int
2983mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2984{
2985 MPT_FRAME_HDR *mf;
2986 SCSIIORequest_t *pScsiReq;
2987 SCSIIORequest_t ReqCopy;
2988 int my_idx, ii, dir;
2989 int rc, cmdTimeout;
2990 int in_isr;
2991 char cmdLen;
2992 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2993 char cmd = io->cmd;
Eric Mooree80b0022007-09-14 18:49:03 -06002994 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 in_isr = in_interrupt();
2997 if (in_isr) {
Eric Mooree80b0022007-09-14 18:49:03 -06002998 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2999 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 return -EPERM;
3001 }
3002
3003
3004 /* Set command specific information
3005 */
3006 switch (cmd) {
3007 case INQUIRY:
3008 cmdLen = 6;
3009 dir = MPI_SCSIIO_CONTROL_READ;
3010 CDB[0] = cmd;
3011 CDB[4] = io->size;
3012 cmdTimeout = 10;
3013 break;
3014
3015 case TEST_UNIT_READY:
3016 cmdLen = 6;
3017 dir = MPI_SCSIIO_CONTROL_READ;
3018 cmdTimeout = 10;
3019 break;
3020
3021 case START_STOP:
3022 cmdLen = 6;
3023 dir = MPI_SCSIIO_CONTROL_READ;
3024 CDB[0] = cmd;
3025 CDB[4] = 1; /*Spin up the disk */
3026 cmdTimeout = 15;
3027 break;
3028
3029 case REQUEST_SENSE:
3030 cmdLen = 6;
3031 CDB[0] = cmd;
3032 CDB[4] = io->size;
3033 dir = MPI_SCSIIO_CONTROL_READ;
3034 cmdTimeout = 10;
3035 break;
3036
3037 case READ_BUFFER:
3038 cmdLen = 10;
3039 dir = MPI_SCSIIO_CONTROL_READ;
3040 CDB[0] = cmd;
3041 if (io->flags & MPT_ICFLAG_ECHO) {
3042 CDB[1] = 0x0A;
3043 } else {
3044 CDB[1] = 0x02;
3045 }
3046
3047 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3048 CDB[1] |= 0x01;
3049 }
3050 CDB[6] = (io->size >> 16) & 0xFF;
3051 CDB[7] = (io->size >> 8) & 0xFF;
3052 CDB[8] = io->size & 0xFF;
3053 cmdTimeout = 10;
3054 break;
3055
3056 case WRITE_BUFFER:
3057 cmdLen = 10;
3058 dir = MPI_SCSIIO_CONTROL_WRITE;
3059 CDB[0] = cmd;
3060 if (io->flags & MPT_ICFLAG_ECHO) {
3061 CDB[1] = 0x0A;
3062 } else {
3063 CDB[1] = 0x02;
3064 }
3065 CDB[6] = (io->size >> 16) & 0xFF;
3066 CDB[7] = (io->size >> 8) & 0xFF;
3067 CDB[8] = io->size & 0xFF;
3068 cmdTimeout = 10;
3069 break;
3070
3071 case RESERVE:
3072 cmdLen = 6;
3073 dir = MPI_SCSIIO_CONTROL_READ;
3074 CDB[0] = cmd;
3075 cmdTimeout = 10;
3076 break;
3077
3078 case RELEASE:
3079 cmdLen = 6;
3080 dir = MPI_SCSIIO_CONTROL_READ;
3081 CDB[0] = cmd;
3082 cmdTimeout = 10;
3083 break;
3084
3085 case SYNCHRONIZE_CACHE:
3086 cmdLen = 10;
3087 dir = MPI_SCSIIO_CONTROL_READ;
3088 CDB[0] = cmd;
3089// CDB[1] = 0x02; /* set immediate bit */
3090 cmdTimeout = 10;
3091 break;
3092
3093 default:
3094 /* Error Case */
3095 return -EFAULT;
3096 }
3097
3098 /* Get and Populate a free Frame
3099 */
Eric Mooree80b0022007-09-14 18:49:03 -06003100 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
3101 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
3102 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 return -EBUSY;
3104 }
3105
3106 pScsiReq = (SCSIIORequest_t *) mf;
3107
3108 /* Get the request index */
3109 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3110 ADD_INDEX_LOG(my_idx); /* for debug */
3111
3112 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3113 pScsiReq->TargetID = io->physDiskNum;
3114 pScsiReq->Bus = 0;
3115 pScsiReq->ChainOffset = 0;
3116 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3117 } else {
3118 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003119 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 pScsiReq->ChainOffset = 0;
3121 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3122 }
3123
3124 pScsiReq->CDBLength = cmdLen;
3125 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3126
3127 pScsiReq->Reserved = 0;
3128
3129 pScsiReq->MsgFlags = mpt_msg_flags();
3130 /* MsgContext set in mpt_get_msg_fram call */
3131
Eric Moore793955f2007-01-29 09:42:20 -07003132 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3135 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3136 else
3137 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3138
3139 if (cmd == REQUEST_SENSE) {
3140 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Eric Mooree80b0022007-09-14 18:49:03 -06003141 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
3142 ioc->name, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 }
3144
3145 for (ii=0; ii < 16; ii++)
3146 pScsiReq->CDB[ii] = CDB[ii];
3147
3148 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003149 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3151
Eric Mooree80b0022007-09-14 18:49:03 -06003152 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3153 ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154
3155 if (dir == MPI_SCSIIO_CONTROL_READ) {
3156 mpt_add_sge((char *) &pScsiReq->SGL,
3157 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3158 io->data_dma);
3159 } else {
3160 mpt_add_sge((char *) &pScsiReq->SGL,
3161 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3162 io->data_dma);
3163 }
3164
3165 /* The ISR will free the request frame, but we need
3166 * the information to initialize the target. Duplicate.
3167 */
3168 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3169
3170 /* Issue this command after:
3171 * finish init
3172 * add timer
3173 * Wait until the reply has been received
3174 * ScsiScanDvCtx callback function will
3175 * set hd->pLocal;
3176 * set scandv_wait_done and call wake_up
3177 */
3178 hd->pLocal = NULL;
3179 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003180 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
3182 /* Save cmd pointer, for resource free if timeout or
3183 * FW reload occurs
3184 */
3185 hd->cmdPtr = mf;
3186
3187 add_timer(&hd->timer);
Eric Mooree80b0022007-09-14 18:49:03 -06003188 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003189 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191 if (hd->pLocal) {
3192 rc = hd->pLocal->completion;
3193 hd->pLocal->skip = 0;
3194
3195 /* Always set fatal error codes in some cases.
3196 */
3197 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3198 rc = -ENXIO;
3199 else if (rc == MPT_SCANDV_SOME_ERROR)
3200 rc = -rc;
3201 } else {
3202 rc = -EFAULT;
3203 /* This should never happen. */
Eric Mooree80b0022007-09-14 18:49:03 -06003204 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
3205 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
3207
3208 return rc;
3209}
3210
3211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3212/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003213 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3214 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003215 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003216 *
3217 * Uses the ISR, but with special processing.
3218 * MUST be single-threaded.
3219 *
3220 */
3221static void
3222mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3223{
3224 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225
Eric Moorecc78d302007-06-15 17:27:21 -06003226 /* Ignore hidden raid components, this is handled when the command
3227 * is sent to the volume
3228 */
3229 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3230 return;
3231
3232 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3233 !vdevice->configured_lun)
3234 return;
3235
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 /* Following parameters will not change
3237 * in this routine.
3238 */
3239 iocmd.cmd = SYNCHRONIZE_CACHE;
3240 iocmd.flags = 0;
3241 iocmd.physDiskNum = -1;
3242 iocmd.data = NULL;
3243 iocmd.data_dma = -1;
3244 iocmd.size = 0;
3245 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003246 iocmd.channel = vdevice->vtarget->channel;
3247 iocmd.id = vdevice->vtarget->id;
3248 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
Eric Moorecc78d302007-06-15 17:27:21 -06003250 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251}
3252
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303253static ssize_t
3254mptscsih_version_fw_show(struct class_device *cdev, char *buf)
3255{
3256 struct Scsi_Host *host = class_to_shost(cdev);
3257 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3258 MPT_ADAPTER *ioc = hd->ioc;
3259
3260 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3261 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3262 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3263 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3264 ioc->facts.FWVersion.Word & 0x000000FF);
3265}
3266static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
3267
3268static ssize_t
3269mptscsih_version_bios_show(struct class_device *cdev, char *buf)
3270{
3271 struct Scsi_Host *host = class_to_shost(cdev);
3272 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3273 MPT_ADAPTER *ioc = hd->ioc;
3274
3275 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3276 (ioc->biosVersion & 0xFF000000) >> 24,
3277 (ioc->biosVersion & 0x00FF0000) >> 16,
3278 (ioc->biosVersion & 0x0000FF00) >> 8,
3279 ioc->biosVersion & 0x000000FF);
3280}
3281static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
3282
3283static ssize_t
3284mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
3285{
3286 struct Scsi_Host *host = class_to_shost(cdev);
3287 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3288 MPT_ADAPTER *ioc = hd->ioc;
3289
3290 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3291}
3292static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
3293
3294static ssize_t
3295mptscsih_version_product_show(struct class_device *cdev, char *buf)
3296{
3297 struct Scsi_Host *host = class_to_shost(cdev);
3298 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3299 MPT_ADAPTER *ioc = hd->ioc;
3300
3301 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3302}
3303static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
3304 mptscsih_version_product_show, NULL);
3305
3306static ssize_t
3307mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
3308{
3309 struct Scsi_Host *host = class_to_shost(cdev);
3310 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3311 MPT_ADAPTER *ioc = hd->ioc;
3312
3313 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3314 ioc->nvdata_version_persistent);
3315}
3316static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
3317 mptscsih_version_nvdata_persistent_show, NULL);
3318
3319static ssize_t
3320mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
3321{
3322 struct Scsi_Host *host = class_to_shost(cdev);
3323 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3324 MPT_ADAPTER *ioc = hd->ioc;
3325
3326 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3327}
3328static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
3329 mptscsih_version_nvdata_default_show, NULL);
3330
3331static ssize_t
3332mptscsih_board_name_show(struct class_device *cdev, char *buf)
3333{
3334 struct Scsi_Host *host = class_to_shost(cdev);
3335 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3336 MPT_ADAPTER *ioc = hd->ioc;
3337
3338 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3339}
3340static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
3341
3342static ssize_t
3343mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
3344{
3345 struct Scsi_Host *host = class_to_shost(cdev);
3346 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3347 MPT_ADAPTER *ioc = hd->ioc;
3348
3349 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3350}
3351static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
3352 mptscsih_board_assembly_show, NULL);
3353
3354static ssize_t
3355mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
3356{
3357 struct Scsi_Host *host = class_to_shost(cdev);
3358 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3359 MPT_ADAPTER *ioc = hd->ioc;
3360
3361 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3362}
3363static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
3364 mptscsih_board_tracer_show, NULL);
3365
3366static ssize_t
3367mptscsih_io_delay_show(struct class_device *cdev, char *buf)
3368{
3369 struct Scsi_Host *host = class_to_shost(cdev);
3370 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3371 MPT_ADAPTER *ioc = hd->ioc;
3372
3373 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3374}
3375static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
3376 mptscsih_io_delay_show, NULL);
3377
3378static ssize_t
3379mptscsih_device_delay_show(struct class_device *cdev, char *buf)
3380{
3381 struct Scsi_Host *host = class_to_shost(cdev);
3382 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3383 MPT_ADAPTER *ioc = hd->ioc;
3384
3385 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3386}
3387static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
3388 mptscsih_device_delay_show, NULL);
3389
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303390static ssize_t
3391mptscsih_debug_level_show(struct class_device *cdev, char *buf)
3392{
3393 struct Scsi_Host *host = class_to_shost(cdev);
3394 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3395 MPT_ADAPTER *ioc = hd->ioc;
3396
3397 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3398}
3399static ssize_t
3400mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
3401 size_t count)
3402{
3403 struct Scsi_Host *host = class_to_shost(cdev);
3404 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
3405 MPT_ADAPTER *ioc = hd->ioc;
3406 int val = 0;
3407
3408 if (sscanf(buf, "%x", &val) != 1)
3409 return -EINVAL;
3410
3411 ioc->debug_level = val;
3412 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3413 ioc->name, ioc->debug_level);
3414 return strlen(buf);
3415}
3416static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3417 mptscsih_debug_level_show, mptscsih_debug_level_store);
3418
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303419struct class_device_attribute *mptscsih_host_attrs[] = {
3420 &class_device_attr_version_fw,
3421 &class_device_attr_version_bios,
3422 &class_device_attr_version_mpi,
3423 &class_device_attr_version_product,
3424 &class_device_attr_version_nvdata_persistent,
3425 &class_device_attr_version_nvdata_default,
3426 &class_device_attr_board_name,
3427 &class_device_attr_board_assembly,
3428 &class_device_attr_board_tracer,
3429 &class_device_attr_io_delay,
3430 &class_device_attr_device_delay,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303431 &class_device_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303432 NULL,
3433};
3434EXPORT_SYMBOL(mptscsih_host_attrs);
3435
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003436EXPORT_SYMBOL(mptscsih_remove);
3437EXPORT_SYMBOL(mptscsih_shutdown);
3438#ifdef CONFIG_PM
3439EXPORT_SYMBOL(mptscsih_suspend);
3440EXPORT_SYMBOL(mptscsih_resume);
3441#endif
3442EXPORT_SYMBOL(mptscsih_proc_info);
3443EXPORT_SYMBOL(mptscsih_info);
3444EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003445EXPORT_SYMBOL(mptscsih_slave_destroy);
3446EXPORT_SYMBOL(mptscsih_slave_configure);
3447EXPORT_SYMBOL(mptscsih_abort);
3448EXPORT_SYMBOL(mptscsih_dev_reset);
3449EXPORT_SYMBOL(mptscsih_bus_reset);
3450EXPORT_SYMBOL(mptscsih_host_reset);
3451EXPORT_SYMBOL(mptscsih_bios_param);
3452EXPORT_SYMBOL(mptscsih_io_done);
3453EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3454EXPORT_SYMBOL(mptscsih_scandv_complete);
3455EXPORT_SYMBOL(mptscsih_event_process);
3456EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003457EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003458EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003459EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003461/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/