blob: 477f6f8251e540453676aab26abddcd198a9438a [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, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 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 */
Eric Mooree8206382007-09-29 10:16:53 -060083static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
84static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
85static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
86static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040087int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040089int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
92 SCSIIORequest_t *pReq, int req_idx);
93static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040094static 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 -070095
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +053096int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
97 int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040099int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
100int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530102void
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530103mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530104static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
105 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400106int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700108static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530110static int
111mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
112 SCSITaskMgmtReply_t *pScsiTmReply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400113void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700114void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400116int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
117int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#endif
119
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900120#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
124/*
125 * mptscsih_getFreeChainBuffer - Function to get a free chain
126 * from the MPT_SCSI_HOST FreeChainQ.
127 * @ioc: Pointer to MPT_ADAPTER structure
128 * @req_idx: Index of the SCSI IO request frame. (output)
129 *
130 * return SUCCESS or FAILED
131 */
132static inline int
133mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
134{
135 MPT_FRAME_HDR *chainBuf;
136 unsigned long flags;
137 int rc;
138 int chain_idx;
139
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530140 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600141 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 spin_lock_irqsave(&ioc->FreeQlock, flags);
143 if (!list_empty(&ioc->FreeChainQ)) {
144 int offset;
145
146 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
147 u.frame.linkage.list);
148 list_del(&chainBuf->u.frame.linkage.list);
149 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
150 chain_idx = offset / ioc->req_sz;
151 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600152 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
153 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
154 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 } else {
156 rc = FAILED;
157 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600158 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
159 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
162
163 *retIndex = chain_idx;
164 return rc;
165} /* mptscsih_getFreeChainBuffer() */
166
167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
168/*
169 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
170 * SCSIIORequest_t Message Frame.
171 * @ioc: Pointer to MPT_ADAPTER structure
172 * @SCpnt: Pointer to scsi_cmnd structure
173 * @pReq: Pointer to SCSIIORequest_t structure
174 *
175 * Returns ...
176 */
177static int
178mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
179 SCSIIORequest_t *pReq, int req_idx)
180{
181 char *psge;
182 char *chainSge;
183 struct scatterlist *sg;
184 int frm_sz;
185 int sges_left, sg_done;
186 int chain_idx = MPT_HOST_NO_CHAIN;
187 int sgeOffset;
188 int numSgeSlots, numSgeThisFrame;
189 u32 sgflags, sgdir, thisxfer = 0;
190 int chain_dma_off = 0;
191 int newIndex;
192 int ii;
193 dma_addr_t v2;
194 u32 RequestNB;
195
196 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
197 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
198 sgdir = MPT_TRANSFER_HOST_TO_IOC;
199 } else {
200 sgdir = MPT_TRANSFER_IOC_TO_HOST;
201 }
202
203 psge = (char *) &pReq->SGL;
204 frm_sz = ioc->req_sz;
205
206 /* Map the data portion, if any.
207 * sges_left = 0 if no data transfer.
208 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900209 sges_left = scsi_dma_map(SCpnt);
210 if (sges_left < 0)
211 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 /* Handle the SG case.
214 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900215 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 sg_done = 0;
217 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
218 chainSge = NULL;
219
220 /* Prior to entering this loop - the following must be set
221 * current MF: sgeOffset (bytes)
222 * chainSge (Null if original MF is not a chain buffer)
223 * sg_done (num SGE done for this MF)
224 */
225
226nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530227 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
229
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530230 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 /* Get first (num - 1) SG elements
233 * Skip any SG entries with a length of 0
234 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
235 */
236 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
237 thisxfer = sg_dma_len(sg);
238 if (thisxfer == 0) {
Jens Axboeed17b032007-07-16 15:30:33 +0200239 sg = sg_next(sg); /* Get next SG element from the OS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 sg_done++;
241 continue;
242 }
243
244 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530245 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Jens Axboeed17b032007-07-16 15:30:33 +0200247 sg = sg_next(sg); /* Get next SG element from the OS */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530248 psge += ioc->SGE_size;
249 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 sg_done++;
251 }
252
253 if (numSgeThisFrame == sges_left) {
254 /* Add last element, end of buffer and end of list flags.
255 */
256 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
257 MPT_SGE_FLAGS_END_OF_BUFFER |
258 MPT_SGE_FLAGS_END_OF_LIST;
259
260 /* Add last SGE and set termination flags.
261 * Note: Last SGE may have a length of 0 - which should be ok.
262 */
263 thisxfer = sg_dma_len(sg);
264
265 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530266 ioc->add_sge(psge, sgflags | thisxfer, v2);
267 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 sg_done++;
269
270 if (chainSge) {
271 /* The current buffer is a chain buffer,
272 * but there is not another one.
273 * Update the chain element
274 * Offset and Length fields.
275 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530276 ioc->add_chain((char *)chainSge, 0, sgeOffset,
277 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 } else {
279 /* The current buffer is the original MF
280 * and there is no Chain buffer.
281 */
282 pReq->ChainOffset = 0;
283 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530284 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
286 ioc->RequestNB[req_idx] = RequestNB;
287 }
288 } else {
289 /* At least one chain buffer is needed.
290 * Complete the first MF
291 * - last SGE element, set the LastElement bit
292 * - set ChainOffset (words) for orig MF
293 * (OR finish previous MF chain buffer)
294 * - update MFStructPtr ChainIndex
295 * - Populate chain element
296 * Also
297 * Loop until done.
298 */
299
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530300 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 ioc->name, sg_done));
302
303 /* Set LAST_ELEMENT flag for last non-chain element
304 * in the buffer. Since psge points at the NEXT
305 * SGE element, go back one SGE element, update the flags
306 * and reset the pointer. (Note: sgflags & thisxfer are already
307 * set properly).
308 */
309 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530310 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 sgflags = le32_to_cpu(*ptmp);
312 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
313 *ptmp = cpu_to_le32(sgflags);
314 }
315
316 if (chainSge) {
317 /* The current buffer is a chain buffer.
318 * chainSge points to the previous Chain Element.
319 * Update its chain element Offset and Length (must
320 * include chain element size) fields.
321 * Old chain element is now complete.
322 */
323 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530324 sgeOffset += ioc->SGE_size;
325 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
326 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 } else {
328 /* The original MF buffer requires a chain buffer -
329 * set the offset.
330 * Last element in this MF is a chain element.
331 */
332 pReq->ChainOffset = (u8) (sgeOffset >> 2);
333 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530334 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 -0700335 ioc->RequestNB[req_idx] = RequestNB;
336 }
337
338 sges_left -= sg_done;
339
340
341 /* NOTE: psge points to the beginning of the chain element
342 * in current buffer. Get a chain buffer.
343 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200344 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530345 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200346 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
347 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 /* Update the tracking arrays.
352 * If chainSge == NULL, update ReqToChain, else ChainToChain
353 */
354 if (chainSge) {
355 ioc->ChainToChain[chain_idx] = newIndex;
356 } else {
357 ioc->ReqToChain[req_idx] = newIndex;
358 }
359 chain_idx = newIndex;
360 chain_dma_off = ioc->req_sz * chain_idx;
361
362 /* Populate the chainSGE for the current buffer.
363 * - Set chain buffer pointer to psge and fill
364 * out the Address and Flags fields.
365 */
366 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600367 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
368 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370 /* Start the SGE for the next buffer
371 */
372 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
373 sgeOffset = 0;
374 sg_done = 0;
375
Eric Moore29dd3602007-09-14 18:46:51 -0600376 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
377 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 /* Start the SGE for the next buffer
380 */
381
382 goto nextSGEset;
383 }
384
385 return SUCCESS;
386} /* mptscsih_AddSGE() */
387
Eric Moore786899b2006-07-11 17:22:22 -0600388static void
389mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
390 U32 SlotStatus)
391{
392 MPT_FRAME_HDR *mf;
393 SEPRequest_t *SEPMsg;
394
Eric Moorecc78d302007-06-15 17:27:21 -0600395 if (ioc->bus_type != SAS)
396 return;
397
398 /* Not supported for hidden raid components
399 */
400 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600401 return;
402
403 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530404 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700405 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600406 return;
407 }
408
409 SEPMsg = (SEPRequest_t *)mf;
410 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700411 SEPMsg->Bus = vtarget->channel;
412 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600413 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
414 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530415 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700416 "Sending SEP cmd=%x channel=%d id=%d\n",
417 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600418 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
419}
420
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530421#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700422/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530423 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700424 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700425 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530426 * @pScsiReply: Pointer to MPT reply frame
427 *
428 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700429 *
430 * Refer to lsi/mpi.h.
431 **/
432static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530433mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700434{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530435 char *desc = NULL;
436 char *desc1 = NULL;
437 u16 ioc_status;
438 u8 skey, asc, ascq;
439
440 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700441
442 switch (ioc_status) {
443
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530444 case MPI_IOCSTATUS_SUCCESS:
445 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700446 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530447 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
448 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700449 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530450 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
451 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700452 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530453 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
454 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700455 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530456 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
457 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700458 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530459 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
460 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700461 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530462 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
463 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700464 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530465 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
466 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700467 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530468 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
469 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700470 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530471 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
472 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700473 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530474 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
475 desc = "task management failed";
476 break;
477 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
478 desc = "IOC terminated";
479 break;
480 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
481 desc = "ext terminated";
482 break;
483 default:
484 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700485 break;
486 }
487
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530488 switch (pScsiReply->SCSIStatus)
489 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700490
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530491 case MPI_SCSI_STATUS_SUCCESS:
492 desc1 = "success";
493 break;
494 case MPI_SCSI_STATUS_CHECK_CONDITION:
495 desc1 = "check condition";
496 break;
497 case MPI_SCSI_STATUS_CONDITION_MET:
498 desc1 = "condition met";
499 break;
500 case MPI_SCSI_STATUS_BUSY:
501 desc1 = "busy";
502 break;
503 case MPI_SCSI_STATUS_INTERMEDIATE:
504 desc1 = "intermediate";
505 break;
506 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
507 desc1 = "intermediate condmet";
508 break;
509 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
510 desc1 = "reservation conflict";
511 break;
512 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
513 desc1 = "command terminated";
514 break;
515 case MPI_SCSI_STATUS_TASK_SET_FULL:
516 desc1 = "task set full";
517 break;
518 case MPI_SCSI_STATUS_ACA_ACTIVE:
519 desc1 = "aca active";
520 break;
521 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
522 desc1 = "fcpext device logged out";
523 break;
524 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
525 desc1 = "fcpext no link";
526 break;
527 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
528 desc1 = "fcpext unassigned";
529 break;
530 default:
531 desc1 = "";
532 break;
533 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700534
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530535 scsi_print_command(sc);
Eric Moore29dd3602007-09-14 18:46:51 -0600536 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
537 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
538 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
539 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
540 scsi_get_resid(sc));
541 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
542 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530543 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Eric Moore29dd3602007-09-14 18:46:51 -0600544 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530545 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600546 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530547 pScsiReply->SCSIState);
548
549 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
550 skey = sc->sense_buffer[2] & 0x0F;
551 asc = sc->sense_buffer[12];
552 ascq = sc->sense_buffer[13];
553
Eric Moore29dd3602007-09-14 18:46:51 -0600554 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
555 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530556 }
557
558 /*
559 * Look for + dump FCP ResponseInfo[]!
560 */
561 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
562 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600563 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
564 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700565}
566#endif
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
569/*
570 * mptscsih_io_done - Main SCSI IO callback routine registered to
571 * Fusion MPT (base) driver
572 * @ioc: Pointer to MPT_ADAPTER structure
573 * @mf: Pointer to original MPT request frame
574 * @r: Pointer to MPT reply frame (NULL if TurboReply)
575 *
576 * This routine is called from mpt.c::mpt_interrupt() at the completion
577 * of any SCSI IO request.
578 * This routine is registered with the Fusion MPT (base) driver at driver
579 * load/init time via the mpt_register() API call.
580 *
581 * Returns 1 indicating alloc'd request frame ptr should be freed.
582 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400583int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
585{
586 struct scsi_cmnd *sc;
587 MPT_SCSI_HOST *hd;
588 SCSIIORequest_t *pScsiReq;
589 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700590 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600591 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600592 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Eric Mooree7eae9f2007-09-29 10:15:59 -0600594 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700596 req_idx_MR = (mr != NULL) ?
597 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
598 if ((req_idx != req_idx_MR) ||
599 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
600 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
601 ioc->name);
602 printk (MYIOC_s_ERR_FMT
603 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
604 ioc->name, req_idx, req_idx_MR, mf, mr,
Eric Mooree8206382007-09-29 10:16:53 -0600605 mptscsih_get_scsi_lookup(ioc, req_idx_MR));
Moore, Eric2254c862006-01-17 17:06:29 -0700606 return 0;
607 }
608
Eric Mooree8206382007-09-29 10:16:53 -0600609 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (sc == NULL) {
611 MPIHeader_t *hdr = (MPIHeader_t *)mf;
612
613 /* Remark: writeSDP1 will use the ScsiDoneCtx
614 * If a SCSI I/O cmd, device disabled by OS and
615 * completion done. Cannot touch sc struct. Just free mem.
616 */
617 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
618 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
619 ioc->name);
620
621 mptscsih_freeChainBuffers(ioc, req_idx);
622 return 1;
623 }
624
Eric Moore3dc0b032006-07-11 17:32:33 -0600625 if ((unsigned char *)mf != sc->host_scribble) {
626 mptscsih_freeChainBuffers(ioc, req_idx);
627 return 1;
628 }
629
630 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 sc->result = DID_OK << 16; /* Set default reply as OK */
632 pScsiReq = (SCSIIORequest_t *) mf;
633 pScsiReply = (SCSIIOReply_t *) mr;
634
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200635 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530636 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200637 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
638 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
639 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530640 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200641 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
642 ioc->name, mf, mr, sc, req_idx));
643 }
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (pScsiReply == NULL) {
646 /* special context reply handling */
647 ;
648 } else {
649 u32 xfer_cnt;
650 u16 status;
651 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700652 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
655 scsi_state = pScsiReply->SCSIState;
656 scsi_status = pScsiReply->SCSIStatus;
657 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900658 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700659 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600661 /*
662 * if we get a data underrun indication, yet no data was
663 * transferred and the SCSI status indicates that the
664 * command was never started, change the data underrun
665 * to success
666 */
667 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
668 (scsi_status == MPI_SCSI_STATUS_BUSY ||
669 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
670 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
671 status = MPI_IOCSTATUS_SUCCESS;
672 }
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400675 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 /*
678 * Look for + dump FCP ResponseInfo[]!
679 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600680 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
681 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600682 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
683 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700684 sc->device->host->host_no, sc->device->channel,
685 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 le32_to_cpu(pScsiReply->ResponseInfo));
687 }
688
689 switch(status) {
690 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
691 /* CHECKME!
692 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
693 * But not: DID_BUS_BUSY lest one risk
694 * killing interrupt handler:-(
695 */
696 sc->result = SAM_STAT_BUSY;
697 break;
698
699 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
700 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
701 sc->result = DID_BAD_TARGET << 16;
702 break;
703
704 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
705 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600706 if (ioc->bus_type != FC)
707 sc->result = DID_NO_CONNECT << 16;
708 /* else fibre, just stall until rescan event */
709 else
710 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
713 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600714
Eric Moorea69de502007-09-14 18:48:19 -0600715 vdevice = sc->device->hostdata;
716 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600717 break;
Eric Moorea69de502007-09-14 18:48:19 -0600718 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600719 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
720 mptscsih_issue_sep_command(ioc, vtarget,
721 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
722 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 break;
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600727 if ( ioc->bus_type == SAS ) {
728 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
729 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700730 if ((log_info & SAS_LOGINFO_MASK)
731 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600732 sc->result = (DID_BUS_BUSY << 16);
733 break;
734 }
735 }
Eric Moore86dd4242007-01-04 20:44:01 -0700736 } else if (ioc->bus_type == FC) {
737 /*
738 * The FC IOC may kill a request for variety of
739 * reasons, some of which may be recovered by a
740 * retry, some which are unlikely to be
741 * recovered. Return DID_ERROR instead of
742 * DID_RESET to permit retry of the command,
743 * just not an infinite number of them
744 */
745 sc->result = DID_ERROR << 16;
746 break;
Eric Moorebf451522006-07-11 17:25:35 -0600747 }
748
749 /*
750 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
751 */
752
753 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
755 /* Linux handles an unsolicited DID_RESET better
756 * than an unsolicited DID_ABORT.
757 */
758 sc->result = DID_RESET << 16;
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 break;
761
762 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900763 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600764 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
765 sc->result=DID_SOFT_ERROR << 16;
766 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600768 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700769 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600770 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
774 /*
775 * Do upfront check for valid SenseData and give it
776 * precedence!
777 */
778 sc->result = (DID_OK << 16) | scsi_status;
779 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
780 /* Have already saved the status and sense data
781 */
782 ;
783 } else {
784 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600785 if (scsi_status == SAM_STAT_BUSY)
786 sc->result = SAM_STAT_BUSY;
787 else
788 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
791 /* What to do?
792 */
793 sc->result = DID_SOFT_ERROR << 16;
794 }
795 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
796 /* Not real sure here either... */
797 sc->result = DID_RESET << 16;
798 }
799 }
800
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530801
Eric Moore29dd3602007-09-14 18:46:51 -0600802 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
803 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
804 ioc->name, sc->underflow));
805 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
806 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 /* Report Queue Full
809 */
810 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
811 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 break;
814
Moore, Eric7e551472006-01-16 18:53:21 -0700815 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900816 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
818 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600819 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (scsi_state == 0) {
821 ;
822 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
823 /*
824 * If running against circa 200003dd 909 MPT f/w,
825 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
826 * (QUEUE_FULL) returned from device! --> get 0x0000?128
827 * and with SenseBytes set to 0.
828 */
829 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
830 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
831
832 }
833 else if (scsi_state &
834 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
835 ) {
836 /*
837 * What to do?
838 */
839 sc->result = DID_SOFT_ERROR << 16;
840 }
841 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
842 /* Not real sure here either... */
843 sc->result = DID_RESET << 16;
844 }
845 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
846 /* Device Inq. data indicates that it supports
847 * QTags, but rejects QTag messages.
848 * This command completed OK.
849 *
850 * Not real sure here either so do nothing... */
851 }
852
853 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
854 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
855
856 /* Add handling of:
857 * Reservation Conflict, Busy,
858 * Command Terminated, CHECK
859 */
860 break;
861
862 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
863 sc->result = DID_SOFT_ERROR << 16;
864 break;
865
866 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
867 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
868 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
869 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
870 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
871 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
872 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
874 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
875 default:
876 /*
877 * What to do?
878 */
879 sc->result = DID_SOFT_ERROR << 16;
880 break;
881
882 } /* switch(status) */
883
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530884#ifdef CONFIG_FUSION_LOGGING
885 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
886 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700887#endif
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 } /* end of address reply case */
890
891 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900892 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 sc->scsi_done(sc); /* Issue the command callback */
895
896 /* Free Chain buffers */
897 mptscsih_freeChainBuffers(ioc, req_idx);
898 return 1;
899}
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901/*
902 * mptscsih_flush_running_cmds - For each command found, search
903 * Scsi_Host instance taskQ and reply to OS.
904 * Called only if recovering from a FW reload.
905 * @hd: Pointer to a SCSI HOST structure
906 *
907 * Returns: None.
908 *
909 * Must be called while new I/Os are being queued.
910 */
911static void
912mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
913{
914 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600915 struct scsi_cmnd *sc;
916 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 int ii;
Eric Mooree8206382007-09-29 10:16:53 -0600918 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Eric Mooree8206382007-09-29 10:16:53 -0600920 for (ii= 0; ii < ioc->req_depth; ii++) {
921 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
922 if (!sc)
923 continue;
924 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
925 if (!mf)
926 continue;
927 channel = mf->Bus;
928 id = mf->TargetID;
929 mptscsih_freeChainBuffers(ioc, ii);
930 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
931 if ((unsigned char *)mf != sc->host_scribble)
932 continue;
933 scsi_dma_unmap(sc);
934 sc->result = DID_RESET << 16;
935 sc->host_scribble = NULL;
Eric Moorec51d0be2007-09-29 10:17:21 -0600936 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
Eric Mooree8206382007-09-29 10:16:53 -0600937 "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
938 " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
939 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
943/*
944 * mptscsih_search_running_cmds - Delete any commands associated
945 * with the specified target and lun. Function called only
946 * when a lun is disable by mid-layer.
947 * Do NOT access the referenced scsi_cmnd structure or
948 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600949 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700950 * @hd: Pointer to a SCSI HOST structure
951 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 *
953 * Returns: None.
954 *
955 * Called from slave_destroy.
956 */
957static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700958mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 SCSIIORequest_t *mf = NULL;
961 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600962 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700963 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -0600964 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600965 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Eric Mooree8206382007-09-29 10:16:53 -0600967 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
968 for (ii = 0; ii < ioc->req_depth; ii++) {
969 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Eric Mooree80b0022007-09-14 18:49:03 -0600971 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600972 if (mf == NULL)
973 continue;
Eric Moorecc78d302007-06-15 17:27:21 -0600974 /* If the device is a hidden raid component, then its
975 * expected that the mf->function will be RAID_SCSI_IO
976 */
977 if (vdevice->vtarget->tflags &
978 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
979 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
980 continue;
981
Eric Moore793955f2007-01-29 09:42:20 -0700982 int_to_scsilun(vdevice->lun, &lun);
983 if ((mf->Bus != vdevice->vtarget->channel) ||
984 (mf->TargetID != vdevice->vtarget->id) ||
985 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 continue;
987
Eric Moore3dc0b032006-07-11 17:32:33 -0600988 if ((unsigned char *)mf != sc->host_scribble)
989 continue;
Eric Mooree8206382007-09-29 10:16:53 -0600990 ioc->ScsiLookup[ii] = NULL;
991 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
992 mptscsih_freeChainBuffers(ioc, ii);
993 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900994 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600995 sc->host_scribble = NULL;
996 sc->result = DID_NO_CONNECT << 16;
Eric Moorec51d0be2007-09-29 10:17:21 -0600997 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
Eric Mooree80b0022007-09-14 18:49:03 -0600998 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530999 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001000 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001001 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 }
1003 }
Eric Mooree8206382007-09-29 10:16:53 -06001004 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return;
1006}
1007
1008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1011/*
1012 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1013 * from a SCSI target device.
1014 * @sc: Pointer to scsi_cmnd structure
1015 * @pScsiReply: Pointer to SCSIIOReply_t
1016 * @pScsiReq: Pointer to original SCSI request
1017 *
1018 * This routine periodically reports QUEUE_FULL status returned from a
1019 * SCSI target device. It reports this to the console via kernel
1020 * printk() API call, not more than once every 10 seconds.
1021 */
1022static void
1023mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1024{
1025 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001027 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001029 if (sc->device == NULL)
1030 return;
1031 if (sc->device->host == NULL)
1032 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001033 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001035 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001036 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001037 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1038 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001039 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041}
1042
1043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1044/*
1045 * mptscsih_remove - Removed scsi devices
1046 * @pdev: Pointer to pci_dev structure
1047 *
1048 *
1049 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001050void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051mptscsih_remove(struct pci_dev *pdev)
1052{
1053 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1054 struct Scsi_Host *host = ioc->sh;
1055 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001056 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001058 if(!host) {
1059 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063 scsi_remove_host(host);
1064
Eric Mooree7eae9f2007-09-29 10:15:59 -06001065 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001066 return;
1067
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001068 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001070 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Eric Mooree8206382007-09-29 10:16:53 -06001072 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001073 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001074 kfree(ioc->ScsiLookup);
1075 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077
Eric Mooree80b0022007-09-14 18:49:03 -06001078 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001079 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001080 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001081
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001082 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001083
1084 /* NULL the Scsi_Host pointer
1085 */
Eric Mooree80b0022007-09-14 18:49:03 -06001086 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001087
1088 scsi_host_put(host);
1089
1090 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
1094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1095/*
1096 * mptscsih_shutdown - reboot notifier
1097 *
1098 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001099void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001100mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102}
1103
1104#ifdef CONFIG_PM
1105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1106/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001107 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 *
1109 *
1110 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001111int
Pavel Machek8d189f72005-04-16 15:25:28 -07001112mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301114 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1115
1116 scsi_block_requests(ioc->sh);
1117 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001118 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001119 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
1122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1123/*
1124 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1125 *
1126 *
1127 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129mptscsih_resume(struct pci_dev *pdev)
1130{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301131 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1132 int rc;
1133
1134 rc = mpt_resume(pdev);
1135 scsi_unblock_requests(ioc->sh);
1136 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
1139#endif
1140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1142/**
1143 * mptscsih_info - Return information about MPT adapter
1144 * @SChost: Pointer to Scsi_Host structure
1145 *
1146 * (linux scsi_host_template.info routine)
1147 *
1148 * Returns pointer to buffer where information was written.
1149 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001150const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151mptscsih_info(struct Scsi_Host *SChost)
1152{
1153 MPT_SCSI_HOST *h;
1154 int size = 0;
1155
Eric Mooree7eae9f2007-09-29 10:15:59 -06001156 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159 if (h->info_kbuf == NULL)
1160 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1161 return h->info_kbuf;
1162 h->info_kbuf[0] = '\0';
1163
1164 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1165 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001168 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169}
1170
1171struct info_str {
1172 char *buffer;
1173 int length;
1174 int offset;
1175 int pos;
1176};
1177
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001178static void
1179mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
1181 if (info->pos + len > info->length)
1182 len = info->length - info->pos;
1183
1184 if (info->pos + len < info->offset) {
1185 info->pos += len;
1186 return;
1187 }
1188
1189 if (info->pos < info->offset) {
1190 data += (info->offset - info->pos);
1191 len -= (info->offset - info->pos);
1192 }
1193
1194 if (len > 0) {
1195 memcpy(info->buffer + info->pos, data, len);
1196 info->pos += len;
1197 }
1198}
1199
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001200static int
1201mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 va_list args;
1204 char buf[81];
1205 int len;
1206
1207 va_start(args, fmt);
1208 len = vsprintf(buf, fmt, args);
1209 va_end(args);
1210
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return len;
1213}
1214
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001215static int
1216mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
1218 struct info_str info;
1219
1220 info.buffer = pbuf;
1221 info.length = len;
1222 info.offset = offset;
1223 info.pos = 0;
1224
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001225 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1226 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1227 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1228 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1231}
1232
1233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1234/**
1235 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001236 * @host: scsi host struct
1237 * @buffer: if write, user data; if read, buffer for user
1238 * @start: returns the buffer address
1239 * @offset: if write, 0; if read, the current offset into the buffer from
1240 * the previous read.
1241 * @length: if write, return length;
1242 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 *
1244 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001246int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1248 int length, int func)
1249{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001250 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 MPT_ADAPTER *ioc = hd->ioc;
1252 int size = 0;
1253
1254 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001255 /*
1256 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 */
1258 } else {
1259 if (start)
1260 *start = buffer;
1261
1262 size = mptscsih_host_info(ioc, buffer, offset, length);
1263 }
1264
1265 return size;
1266}
1267
1268/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1269#define ADD_INDEX_LOG(req_ent) do { } while(0)
1270
1271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1272/**
1273 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1274 * @SCpnt: Pointer to scsi_cmnd structure
1275 * @done: Pointer SCSI mid-layer IO completion function
1276 *
1277 * (linux scsi_host_template.queuecommand routine)
1278 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1279 * from a linux scsi_cmnd request and send it to the IOC.
1280 *
1281 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1282 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1285{
1286 MPT_SCSI_HOST *hd;
1287 MPT_FRAME_HDR *mf;
1288 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001289 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 int lun;
1291 u32 datalen;
1292 u32 scsictl;
1293 u32 scsidir;
1294 u32 cmd_len;
1295 int my_idx;
1296 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301297 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Eric Mooree7eae9f2007-09-29 10:15:59 -06001299 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301300 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 lun = SCpnt->device->lun;
1302 SCpnt->scsi_done = done;
1303
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301304 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1305 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301307 if (ioc->taskmgmt_quiesce_io) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301308 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1309 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 return SCSI_MLQUEUE_HOST_BUSY;
1311 }
1312
1313 /*
1314 * Put together a MPT SCSI request...
1315 */
Eric Mooree80b0022007-09-14 18:49:03 -06001316 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301317 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1318 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 return SCSI_MLQUEUE_HOST_BUSY;
1320 }
1321
1322 pScsiReq = (SCSIIORequest_t *) mf;
1323
1324 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1325
1326 ADD_INDEX_LOG(my_idx);
1327
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001328 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 * Seems we may receive a buffer (datalen>0) even when there
1330 * will be no data transfer! GRRRRR...
1331 */
1332 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001333 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1335 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001336 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1338 } else {
1339 datalen = 0;
1340 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1341 }
1342
1343 /* Default to untagged. Once a target structure has been allocated,
1344 * use the Inquiry data to determine if device supports tagged.
1345 */
Eric Moorea69de502007-09-14 18:48:19 -06001346 if (vdevice
1347 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 && (SCpnt->device->tagged_supported)) {
1349 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1350 } else {
1351 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1352 }
1353
1354 /* Use the above information to set up the message frame
1355 */
Eric Moorea69de502007-09-14 18:48:19 -06001356 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1357 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001359 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001360 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1361 else
1362 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pScsiReq->CDBLength = SCpnt->cmd_len;
1364 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1365 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301366 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001367 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 pScsiReq->Control = cpu_to_le32(scsictl);
1369
1370 /*
1371 * Write SCSI CDB into the message
1372 */
1373 cmd_len = SCpnt->cmd_len;
1374 for (ii=0; ii < cmd_len; ii++)
1375 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1376
1377 for (ii=cmd_len; ii < 16; ii++)
1378 pScsiReq->CDB[ii] = 0;
1379
1380 /* DataLength */
1381 pScsiReq->DataLength = cpu_to_le32(datalen);
1382
1383 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001384 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1386
1387 /* Now add the SG list
1388 * Always have a SGE even if null length.
1389 */
1390 if (datalen == 0) {
1391 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301392 ioc->add_sge((char *)&pScsiReq->SGL,
1393 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 (dma_addr_t) -1);
1395 } else {
1396 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001397 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 goto fail;
1399 }
1400
Eric Moore3dc0b032006-07-11 17:32:33 -06001401 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001402 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Eric Mooree80b0022007-09-14 18:49:03 -06001404 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301405 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1406 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001407 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 return 0;
1409
1410 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001411 mptscsih_freeChainBuffers(ioc, my_idx);
1412 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 return SCSI_MLQUEUE_HOST_BUSY;
1414}
1415
1416/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1417/*
1418 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1419 * with a SCSI IO request
1420 * @hd: Pointer to the MPT_SCSI_HOST instance
1421 * @req_idx: Index of the SCSI IO request frame.
1422 *
1423 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1424 * No return.
1425 */
1426static void
1427mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1428{
1429 MPT_FRAME_HDR *chain;
1430 unsigned long flags;
1431 int chain_idx;
1432 int next;
1433
1434 /* Get the first chain index and reset
1435 * tracker state.
1436 */
1437 chain_idx = ioc->ReqToChain[req_idx];
1438 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1439
1440 while (chain_idx != MPT_HOST_NO_CHAIN) {
1441
1442 /* Save the next chain buffer index */
1443 next = ioc->ChainToChain[chain_idx];
1444
1445 /* Free this chain buffer and reset
1446 * tracker
1447 */
1448 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1449
1450 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1451 + (chain_idx * ioc->req_sz));
1452
1453 spin_lock_irqsave(&ioc->FreeQlock, flags);
1454 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1455 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1456
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301457 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 ioc->name, chain_idx));
1459
1460 /* handle next */
1461 chain_idx = next;
1462 }
1463 return;
1464}
1465
1466/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1467/*
1468 * Reset Handling
1469 */
1470
1471/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001472/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1474 * @hd: Pointer to MPT_SCSI_HOST structure
1475 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001476 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001477 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 * @lun: Logical Unit for reset (if appropriate)
1479 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001480 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 *
1482 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1483 * or a non-interrupt thread. In the former, must not call schedule().
1484 *
1485 * Not all fields are meaningfull for all task types.
1486 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001487 * Returns 0 for SUCCESS, or FAILED.
1488 *
1489 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301490int
1491mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1492 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 MPT_FRAME_HDR *mf;
1495 SCSITaskMgmt_t *pScsiTm;
1496 int ii;
1497 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001498 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301499 unsigned long timeleft;
1500 u8 issue_hard_reset;
1501 u32 ioc_raw_state;
1502 unsigned long time_count;
1503
1504 issue_hard_reset = 0;
1505 ioc_raw_state = mpt_GetIocState(ioc, 0);
1506
1507 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1508 printk(MYIOC_s_WARN_FMT
1509 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1510 ioc->name, type, ioc_raw_state);
1511 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1512 ioc->name, __func__);
1513 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1514 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1515 "FAILED!!\n", ioc->name);
1516 return 0;
1517 }
1518
1519 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1520 printk(MYIOC_s_WARN_FMT
1521 "TaskMgmt type=%x: ioc_state: "
1522 "DOORBELL_ACTIVE (0x%x)!\n",
1523 ioc->name, type, ioc_raw_state);
1524 return FAILED;
1525 }
1526
1527 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1528 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1529 mf = NULL;
1530 retval = FAILED;
1531 goto out;
1532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534 /* Return Fail to calling function if no message frames available.
1535 */
Eric Mooree80b0022007-09-14 18:49:03 -06001536 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301537 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1538 "TaskMgmt no msg frames!!\n", ioc->name));
1539 retval = FAILED;
1540 mpt_clear_taskmgmt_in_progress_flag(ioc);
1541 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301543 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001544 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
1546 /* Format the Request
1547 */
1548 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001549 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 pScsiTm->Bus = channel;
1551 pScsiTm->ChainOffset = 0;
1552 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1553
1554 pScsiTm->Reserved = 0;
1555 pScsiTm->TaskType = type;
1556 pScsiTm->Reserved1 = 0;
1557 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1558 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1559
Eric Moore793955f2007-01-29 09:42:20 -07001560 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 for (ii=0; ii < 7; ii++)
1563 pScsiTm->Reserved2[ii] = 0;
1564
1565 pScsiTm->TaskMsgContext = ctx2abort;
1566
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301567 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1568 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1569 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301571 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301573 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1574 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001575 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1576 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1577 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301578 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001579 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301580 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1581 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301582 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1583 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1584 ioc->name, mf, retval));
1585 mpt_free_msg_frame(ioc, mf);
1586 mpt_clear_taskmgmt_in_progress_flag(ioc);
1587 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 }
1590
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301591 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1592 timeout*HZ);
1593 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1594 retval = FAILED;
1595 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1596 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1597 mpt_clear_taskmgmt_in_progress_flag(ioc);
1598 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1599 goto out;
1600 issue_hard_reset = 1;
1601 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 }
1603
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301604 retval = mptscsih_taskmgmt_reply(ioc, type,
1605 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001606
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301607 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1608 "TaskMgmt completed (%d seconds)\n",
1609 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1610
1611 out:
1612
1613 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1614 if (issue_hard_reset) {
1615 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
1616 ioc->name, __func__);
1617 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1618 mpt_free_msg_frame(ioc, mf);
1619 }
1620
1621 retval = (retval == 0) ? 0 : FAILED;
1622 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return retval;
1624}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301625EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001627static int
1628mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1629{
1630 switch (ioc->bus_type) {
1631 case FC:
1632 return 40;
1633 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001634 case SPI:
1635 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001636 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001637 }
1638}
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1641/**
1642 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1643 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1644 *
1645 * (linux scsi_host_template.eh_abort_handler routine)
1646 *
1647 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001648 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001649int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650mptscsih_abort(struct scsi_cmnd * SCpnt)
1651{
1652 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 MPT_FRAME_HDR *mf;
1654 u32 ctx2abort;
1655 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001656 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001657 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001658 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001659 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 /* If we can't locate our host adapter structure, return FAILED status.
1662 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001663 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 SCpnt->result = DID_RESET << 16;
1665 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001666 printk(KERN_ERR MYNAM ": task abort: "
1667 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 return FAILED;
1669 }
1670
Eric Moore958d4a32007-06-15 17:24:14 -06001671 ioc = hd->ioc;
1672 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1673 ioc->name, SCpnt);
1674 scsi_print_command(SCpnt);
1675
1676 vdevice = SCpnt->device->hostdata;
1677 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001678 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1679 "task abort: device has been deleted (sc=%p)\n",
1680 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001681 SCpnt->result = DID_NO_CONNECT << 16;
1682 SCpnt->scsi_done(SCpnt);
1683 retval = 0;
1684 goto out;
1685 }
1686
Eric Moorecc78d302007-06-15 17:27:21 -06001687 /* Task aborts are not supported for hidden raid components.
1688 */
1689 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001690 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1691 "task abort: hidden raid component (sc=%p)\n",
1692 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001693 SCpnt->result = DID_RESET << 16;
1694 retval = FAILED;
1695 goto out;
1696 }
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 /* Find this command
1699 */
Eric Mooree8206382007-09-29 10:16:53 -06001700 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001701 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 * Do OS callback.
1703 */
1704 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001705 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001706 "Command not in the active list! (sc=%p)\n", ioc->name,
1707 SCpnt));
1708 retval = 0;
1709 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
1711
Moore, Eric65207fe2006-04-21 16:14:35 -06001712 if (hd->timeouts < -1)
1713 hd->timeouts++;
1714
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301715 if (mpt_fwfault_debug)
1716 mpt_halt_firmware(ioc);
1717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1719 * (the IO to be ABORT'd)
1720 *
1721 * NOTE: Since we do not byteswap MsgContext, we do not
1722 * swap it here either. It is an opaque cookie to
1723 * the controller, so it does not matter. -DaveM
1724 */
Eric Mooree80b0022007-09-14 18:49:03 -06001725 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1727
1728 hd->abortSCpnt = SCpnt;
1729
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301730 retval = mptscsih_IssueTaskMgmt(hd,
1731 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1732 vdevice->vtarget->channel,
1733 vdevice->vtarget->id, vdevice->lun,
1734 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Eric Mooree8206382007-09-29 10:16:53 -06001736 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001737 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001738 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001739
Eric Moore958d4a32007-06-15 17:24:14 -06001740 out:
1741 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1742 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001744 if (retval == 0)
1745 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001746 else
1747 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748}
1749
1750/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1751/**
1752 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1753 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1754 *
1755 * (linux scsi_host_template.eh_dev_reset_handler routine)
1756 *
1757 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001758 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001759int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1761{
1762 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001763 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001764 VirtDevice *vdevice;
1765 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 /* If we can't locate our host adapter structure, return FAILED status.
1768 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001769 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001770 printk(KERN_ERR MYNAM ": target reset: "
1771 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return FAILED;
1773 }
1774
Eric Moore958d4a32007-06-15 17:24:14 -06001775 ioc = hd->ioc;
1776 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1777 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001778 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Eric Moore958d4a32007-06-15 17:24:14 -06001780 vdevice = SCpnt->device->hostdata;
1781 if (!vdevice || !vdevice->vtarget) {
1782 retval = 0;
1783 goto out;
1784 }
1785
Eric Moorecc78d302007-06-15 17:27:21 -06001786 /* Target reset to hidden raid component is not supported
1787 */
1788 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1789 retval = FAILED;
1790 goto out;
1791 }
1792
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301793 retval = mptscsih_IssueTaskMgmt(hd,
1794 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1795 vdevice->vtarget->channel,
1796 vdevice->vtarget->id, 0, 0,
1797 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001798
1799 out:
1800 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1801 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001802
1803 if (retval == 0)
1804 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001805 else
1806 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807}
1808
Eric Moorecd2c6192007-01-29 09:47:47 -07001809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1811/**
1812 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1813 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1814 *
1815 * (linux scsi_host_template.eh_bus_reset_handler routine)
1816 *
1817 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001818 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001819int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1821{
1822 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001823 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001824 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001825 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
1827 /* If we can't locate our host adapter structure, return FAILED status.
1828 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001829 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001830 printk(KERN_ERR MYNAM ": bus reset: "
1831 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 return FAILED;
1833 }
1834
Eric Moore958d4a32007-06-15 17:24:14 -06001835 ioc = hd->ioc;
1836 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1837 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001838 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
1840 if (hd->timeouts < -1)
1841 hd->timeouts++;
1842
Eric Moorea69de502007-09-14 18:48:19 -06001843 vdevice = SCpnt->device->hostdata;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301844 retval = mptscsih_IssueTaskMgmt(hd,
1845 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1846 vdevice->vtarget->channel, 0, 0, 0,
1847 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Eric Moore958d4a32007-06-15 17:24:14 -06001849 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1850 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001851
1852 if (retval == 0)
1853 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001854 else
1855 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856}
1857
1858/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1859/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001860 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1862 *
1863 * (linux scsi_host_template.eh_host_reset_handler routine)
1864 *
1865 * Returns SUCCESS or FAILED.
1866 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001867int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1869{
1870 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001871 int retval;
1872 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001875 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001876 printk(KERN_ERR MYNAM ": host reset: "
1877 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 return FAILED;
1879 }
1880
James Bottomleya6da74c2008-12-15 14:13:27 -06001881 /* make sure we have no outstanding commands at this stage */
1882 mptscsih_flush_running_cmds(hd);
1883
Eric Moore958d4a32007-06-15 17:24:14 -06001884 ioc = hd->ioc;
1885 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1886 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 /* If our attempts to reset the host failed, then return a failed
1889 * status. The host will be taken off line by the SCSI mid-layer.
1890 */
Eric Mooree80b0022007-09-14 18:49:03 -06001891 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06001892 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 } else {
1894 /* Make sure TM pending is cleared and TM state is set to
1895 * NONE.
1896 */
Eric Moore958d4a32007-06-15 17:24:14 -06001897 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Eric Moore958d4a32007-06-15 17:24:14 -06001900 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1901 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
Eric Moore958d4a32007-06-15 17:24:14 -06001903 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904}
1905
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301907mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
1908 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301910 u16 iocstatus;
1911 u32 termination_count;
1912 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301914 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
1915 retval = FAILED;
1916 goto out;
1917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301919 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301921 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
1922 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301924 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1925 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
1926 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
1927 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
1928 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
1929 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
1930 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301932 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
1933 pScsiTmReply->ResponseCode)
1934 mptscsih_taskmgmt_response_code(ioc,
1935 pScsiTmReply->ResponseCode);
1936
1937 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
1938 retval = 0;
1939 goto out;
1940 }
1941
1942 retval = FAILED;
1943 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
1944 if (termination_count == 1)
1945 retval = 0;
1946 goto out;
1947 }
1948
1949 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1950 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1951 retval = 0;
1952
1953 out:
1954 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955}
1956
1957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301958void
Moore, Eric9f63bb72006-01-16 18:53:26 -07001959mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1960{
1961 char *desc;
1962
1963 switch (response_code) {
1964 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1965 desc = "The task completed.";
1966 break;
1967 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1968 desc = "The IOC received an invalid frame status.";
1969 break;
1970 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1971 desc = "The task type is not supported.";
1972 break;
1973 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1974 desc = "The requested task failed.";
1975 break;
1976 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1977 desc = "The task completed successfully.";
1978 break;
1979 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1980 desc = "The LUN request is invalid.";
1981 break;
1982 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1983 desc = "The task is in the IOC queue and has not been sent to target.";
1984 break;
1985 default:
1986 desc = "unknown";
1987 break;
1988 }
1989 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
1990 ioc->name, response_code, desc);
1991}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301992EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07001993
1994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995/**
1996 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
1997 * @ioc: Pointer to MPT_ADAPTER structure
1998 * @mf: Pointer to SCSI task mgmt request frame
1999 * @mr: Pointer to SCSI task mgmt reply frame
2000 *
2001 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2002 * of any SCSI task management request.
2003 * This routine is registered with the MPT (base) driver at driver
2004 * load/init time via the mpt_register() API call.
2005 *
2006 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002007 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002008int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302009mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2010 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302012 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2013 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302015 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302017 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002018 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002019
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302020 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2021 memcpy(ioc->taskmgmt_cmds.reply, mr,
2022 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002023 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302024 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2025 mpt_clear_taskmgmt_in_progress_flag(ioc);
2026 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2027 complete(&ioc->taskmgmt_cmds.done);
2028 return 1;
2029 }
2030 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031}
2032
2033/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2034/*
2035 * This is anyones guess quite frankly.
2036 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002037int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2039 sector_t capacity, int geom[])
2040{
2041 int heads;
2042 int sectors;
2043 sector_t cylinders;
2044 ulong dummy;
2045
2046 heads = 64;
2047 sectors = 32;
2048
2049 dummy = heads * sectors;
2050 cylinders = capacity;
2051 sector_div(cylinders,dummy);
2052
2053 /*
2054 * Handle extended translation size for logical drives
2055 * > 1Gb
2056 */
2057 if ((ulong)capacity >= 0x200000) {
2058 heads = 255;
2059 sectors = 63;
2060 dummy = heads * sectors;
2061 cylinders = capacity;
2062 sector_div(cylinders,dummy);
2063 }
2064
2065 /* return result */
2066 geom[0] = heads;
2067 geom[1] = sectors;
2068 geom[2] = cylinders;
2069
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 return 0;
2071}
2072
Moore, Ericf44e5462006-03-14 09:14:21 -07002073/* Search IOC page 3 to determine if this is hidden physical disk
2074 *
2075 */
2076int
Eric Moore793955f2007-01-29 09:42:20 -07002077mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002078{
Eric Mooreb506ade2007-01-29 09:45:37 -07002079 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002080 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002081 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002082
Eric Moore793955f2007-01-29 09:42:20 -07002083 if (!ioc->raid_data.pIocPg3)
2084 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002085 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002086 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2087 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2088 rc = 1;
2089 goto out;
2090 }
2091 }
2092
Eric Mooreb506ade2007-01-29 09:45:37 -07002093 /*
2094 * Check inactive list for matching phys disks
2095 */
2096 if (list_empty(&ioc->raid_data.inactive_list))
2097 goto out;
2098
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002099 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002100 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2101 list) {
2102 if ((component_info->d.PhysDiskID == id) &&
2103 (component_info->d.PhysDiskBus == channel))
2104 rc = 1;
2105 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002106 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002107
Eric Moore793955f2007-01-29 09:42:20 -07002108 out:
2109 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002110}
2111EXPORT_SYMBOL(mptscsih_is_phys_disk);
2112
Eric Moore793955f2007-01-29 09:42:20 -07002113u8
2114mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002115{
Eric Mooreb506ade2007-01-29 09:45:37 -07002116 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002117 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002118 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002119
Eric Moore793955f2007-01-29 09:42:20 -07002120 if (!ioc->raid_data.pIocPg3)
2121 goto out;
2122 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2123 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2124 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2125 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2126 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002127 }
2128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
Eric Mooreb506ade2007-01-29 09:45:37 -07002130 /*
2131 * Check inactive list for matching phys disks
2132 */
2133 if (list_empty(&ioc->raid_data.inactive_list))
2134 goto out;
2135
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002136 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002137 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2138 list) {
2139 if ((component_info->d.PhysDiskID == id) &&
2140 (component_info->d.PhysDiskBus == channel))
2141 rc = component_info->d.PhysDiskNum;
2142 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002143 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002144
Eric Moore793955f2007-01-29 09:42:20 -07002145 out:
2146 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002147}
Eric Moore793955f2007-01-29 09:42:20 -07002148EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002149
2150/*
2151 * OS entry point to allow for host driver to free allocated memory
2152 * Called if no device present or device being unloaded
2153 */
2154void
2155mptscsih_slave_destroy(struct scsi_device *sdev)
2156{
2157 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002158 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002159 VirtTarget *vtarget;
2160 VirtDevice *vdevice;
2161 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002163 starget = scsi_target(sdev);
2164 vtarget = starget->hostdata;
2165 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002167 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002168 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002169 mptscsih_synchronize_cache(hd, vdevice);
2170 kfree(vdevice);
2171 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172}
2173
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002174/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2175/*
2176 * mptscsih_change_queue_depth - This function will set a devices queue depth
2177 * @sdev: per scsi_device pointer
2178 * @qdepth: requested queue depth
2179 *
2180 * Adding support for new 'change_queue_depth' api.
2181*/
2182int
2183mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002185 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002186 VirtTarget *vtarget;
2187 struct scsi_target *starget;
2188 int max_depth;
2189 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002190 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002192 starget = scsi_target(sdev);
2193 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002194
Eric Mooree80b0022007-09-14 18:49:03 -06002195 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002196 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002198 else if (sdev->type == TYPE_DISK &&
2199 vtarget->minSyncFactor <= MPT_ULTRA160)
2200 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2201 else
2202 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 } else
2204 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2205
2206 if (qdepth > max_depth)
2207 qdepth = max_depth;
2208 if (qdepth == 1)
2209 tagged = 0;
2210 else
2211 tagged = MSG_SIMPLE_TAG;
2212
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002213 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2214 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215}
2216
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217/*
2218 * OS entry point to adjust the queue_depths on a per-device basis.
2219 * Called once per device the bus scan. Use it to force the queue_depth
2220 * member to 1 if a device does not support Q tags.
2221 * Return non-zero if fails.
2222 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002223int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002224mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002226 struct Scsi_Host *sh = sdev->host;
2227 VirtTarget *vtarget;
2228 VirtDevice *vdevice;
2229 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002230 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002231 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002233 starget = scsi_target(sdev);
2234 vtarget = starget->hostdata;
2235 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Eric Mooree80b0022007-09-14 18:49:03 -06002237 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002238 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002239 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2240 if (ioc->bus_type == SPI)
2241 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002242 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002243 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002244 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
Eric Moore793955f2007-01-29 09:42:20 -07002246 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002247 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
Eric Mooree80b0022007-09-14 18:49:03 -06002249 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002251 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Eric Mooree80b0022007-09-14 18:49:03 -06002253 if (ioc->bus_type == SPI)
2254 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002255 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002256 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002257 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Eric Mooree80b0022007-09-14 18:49:03 -06002259 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002261 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002262 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
2264 return 0;
2265}
2266
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2268/*
2269 * Private routines...
2270 */
2271
2272/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2273/* Utility function to copy sense data from the scsi_cmnd buffer
2274 * to the FC and SCSI target structures.
2275 *
2276 */
2277static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002278mptscsih_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 -07002279{
Eric Moorea69de502007-09-14 18:48:19 -06002280 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 SCSIIORequest_t *pReq;
2282 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002283 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
2285 /* Get target structure
2286 */
2287 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002288 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 if (sense_count) {
2291 u8 *sense_data;
2292 int req_index;
2293
2294 /* Copy the sense received into the scsi command block. */
2295 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002296 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2298
2299 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2300 */
Eric Mooree80b0022007-09-14 18:49:03 -06002301 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002302 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002305 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2307 ioc->events[idx].eventContext = ioc->eventContext;
2308
Dave Jones3d9780b2007-05-21 20:59:47 -04002309 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2310 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2311 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
Dave Jones3d9780b2007-05-21 20:59:47 -04002313 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002316 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002317 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002318 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002319 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2320 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002321 MPT_TARGET_FLAGS_LED_ON;
2322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
2324 }
2325 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002326 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2327 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 }
2329}
2330
Eric Mooree8206382007-09-29 10:16:53 -06002331/**
2332 * mptscsih_get_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002333 * @ioc: Pointer to MPT_ADAPTER structure
2334 * @i: index into the array
2335 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002336 * retrieves scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002337 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002338 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002339 **/
2340static struct scsi_cmnd *
2341mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342{
Eric Mooree8206382007-09-29 10:16:53 -06002343 unsigned long flags;
2344 struct scsi_cmnd *scmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Eric Mooree8206382007-09-29 10:16:53 -06002346 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2347 scmd = ioc->ScsiLookup[i];
2348 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
Eric Mooree8206382007-09-29 10:16:53 -06002350 return scmd;
2351}
2352
2353/**
2354 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002355 * @ioc: Pointer to MPT_ADAPTER structure
2356 * @i: index into the array
2357 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002358 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002359 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002360 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002361 **/
2362static struct scsi_cmnd *
2363mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2364{
2365 unsigned long flags;
2366 struct scsi_cmnd *scmd;
2367
2368 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2369 scmd = ioc->ScsiLookup[i];
2370 ioc->ScsiLookup[i] = NULL;
2371 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2372
2373 return scmd;
2374}
2375
2376/**
2377 * mptscsih_set_scsi_lookup
2378 *
2379 * writes a scmd entry into the ScsiLookup[] array list
2380 *
2381 * @ioc: Pointer to MPT_ADAPTER structure
2382 * @i: index into the array
2383 * @scmd: scsi_cmnd pointer
2384 *
2385 **/
2386static void
2387mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2388{
2389 unsigned long flags;
2390
2391 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2392 ioc->ScsiLookup[i] = scmd;
2393 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2394}
2395
2396/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002397 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002398 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002399 * @sc: scsi_cmnd pointer
2400 */
Eric Mooree8206382007-09-29 10:16:53 -06002401static int
2402SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2403{
2404 unsigned long flags;
2405 int i, index=-1;
2406
2407 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2408 for (i = 0; i < ioc->req_depth; i++) {
2409 if (ioc->ScsiLookup[i] == sc) {
2410 index = i;
2411 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 }
2413 }
2414
Eric Mooree8206382007-09-29 10:16:53 -06002415 out:
2416 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2417 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418}
2419
2420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002421int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2423{
2424 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
Eric Mooree7eae9f2007-09-29 10:15:59 -06002426 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302429 hd = shost_priv(ioc->sh);
2430 switch (reset_phase) {
2431 case MPT_IOC_SETUP_RESET:
2432 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2433 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302434 break;
2435 case MPT_IOC_PRE_RESET:
2436 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2437 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302438 mptscsih_flush_running_cmds(hd);
2439 break;
2440 case MPT_IOC_POST_RESET:
2441 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2442 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2443 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2444 ioc->internal_cmds.status |=
2445 MPT_MGMT_STATUS_DID_IOCRESET;
2446 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302448 break;
2449 default:
2450 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 return 1; /* currently means nothing really */
2453}
2454
2455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002456int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2458{
2459 MPT_SCSI_HOST *hd;
2460 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2461
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302462 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2463 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2464 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002466 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06002467 ((hd = shost_priv(ioc->sh)) == NULL))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002468 return 1;
2469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 switch (event) {
2471 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2472 /* FIXME! */
2473 break;
2474 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2475 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002476 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002477 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 break;
2479 case MPI_EVENT_LOGOUT: /* 09 */
2480 /* FIXME! */
2481 break;
2482
Michael Reed05e8ec12006-01-13 14:31:54 -06002483 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002484 break;
2485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 /*
2487 * CHECKME! Don't think we need to do
2488 * anything for these, but...
2489 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2491 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2492 /*
2493 * CHECKME! Falling thru...
2494 */
2495 break;
2496
2497 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002498 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 case MPI_EVENT_NONE: /* 00 */
2501 case MPI_EVENT_LOG_DATA: /* 01 */
2502 case MPI_EVENT_STATE_CHANGE: /* 02 */
2503 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2504 default:
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302505 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2506 ": Ignoring event (=%02Xh)\n",
2507 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 break;
2509 }
2510
2511 return 1; /* currently means nothing really */
2512}
2513
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2515/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 * Bus Scan and Domain Validation functionality ...
2517 */
2518
2519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2520/*
2521 * mptscsih_scandv_complete - Scan and DV callback routine registered
2522 * to Fustion MPT (base) driver.
2523 *
2524 * @ioc: Pointer to MPT_ADAPTER structure
2525 * @mf: Pointer to original MPT request frame
2526 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2527 *
2528 * This routine is called from mpt.c::mpt_interrupt() at the completion
2529 * of any SCSI IO request.
2530 * This routine is registered with the Fusion MPT (base) driver at driver
2531 * load/init time via the mpt_register() API call.
2532 *
2533 * Returns 1 indicating alloc'd request frame ptr should be freed.
2534 *
2535 * Remark: Sets a completion code and (possibly) saves sense data
2536 * in the IOC member localReply structure.
2537 * Used ONLY for DV and other internal commands.
2538 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002539int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302540mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2541 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302544 SCSIIOReply_t *pReply;
2545 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302547 u8 *sense_data;
2548 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302550 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2551 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2552 if (!reply)
2553 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002554
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302555 pReply = (SCSIIOReply_t *) reply;
2556 pReq = (SCSIIORequest_t *) req;
2557 ioc->internal_cmds.completion_code =
2558 mptscsih_get_completion_code(ioc, req, reply);
2559 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2560 memcpy(ioc->internal_cmds.reply, reply,
2561 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2562 cmd = reply->u.hdr.Function;
2563 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2564 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2565 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2566 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2567 sense_data = ((u8 *)ioc->sense_buf_pool +
2568 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2569 sz = min_t(int, pReq->SenseBufferLength,
2570 MPT_SENSE_BUFFER_ALLOC);
2571 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302573 out:
2574 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2575 return 0;
2576 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2577 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 return 1;
2579}
2580
2581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2582/* mptscsih_timer_expired - Call back for timer process.
2583 * Used only for dv functionality.
2584 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2585 *
2586 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002587void
2588mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589{
2590 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002591 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
Eric Mooree80b0022007-09-14 18:49:03 -06002593 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595 if (hd->cmdPtr) {
2596 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2597
2598 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2599 /* Desire to issue a task management request here.
2600 * TM requests MUST be single threaded.
2601 * If old eh code and no TM current, issue request.
2602 * If new eh code, do nothing. Wait for OS cmd timeout
2603 * for bus reset.
2604 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 } else {
2606 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002607 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2608 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 }
2610 }
2611 } else {
2612 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002613 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 }
2615
2616 /* No more processing.
2617 * TM call will generate an interrupt for SCSI TM Management.
2618 * The FW will reply to all outstanding commands, callback will finish cleanup.
2619 * Hard reset clean-up will free all resources.
2620 */
Eric Mooree80b0022007-09-14 18:49:03 -06002621 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
2623 return;
2624}
2625
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302626/**
2627 * mptscsih_get_completion_code -
2628 * @ioc: Pointer to MPT_ADAPTER structure
2629 * @reply:
2630 * @cmd:
2631 *
2632 **/
2633static int
2634mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2635 MPT_FRAME_HDR *reply)
2636{
2637 SCSIIOReply_t *pReply;
2638 MpiRaidActionReply_t *pr;
2639 u8 scsi_status;
2640 u16 status;
2641 int completion_code;
2642
2643 pReply = (SCSIIOReply_t *)reply;
2644 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2645 scsi_status = pReply->SCSIStatus;
2646
2647 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2648 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2649 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2650 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2651
2652 switch (status) {
2653
2654 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2655 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2656 break;
2657
2658 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2659 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2660 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2661 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2662 completion_code = MPT_SCANDV_DID_RESET;
2663 break;
2664
2665 case MPI_IOCSTATUS_BUSY:
2666 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2667 completion_code = MPT_SCANDV_BUSY;
2668 break;
2669
2670 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2671 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2672 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2673 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2674 completion_code = MPT_SCANDV_GOOD;
2675 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2676 pr = (MpiRaidActionReply_t *)reply;
2677 if (le16_to_cpu(pr->ActionStatus) ==
2678 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2679 completion_code = MPT_SCANDV_GOOD;
2680 else
2681 completion_code = MPT_SCANDV_SOME_ERROR;
2682 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2683 completion_code = MPT_SCANDV_SENSE;
2684 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2685 if (req->u.scsireq.CDB[0] == INQUIRY)
2686 completion_code = MPT_SCANDV_ISSUE_SENSE;
2687 else
2688 completion_code = MPT_SCANDV_DID_RESET;
2689 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2690 completion_code = MPT_SCANDV_DID_RESET;
2691 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2692 completion_code = MPT_SCANDV_DID_RESET;
2693 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2694 completion_code = MPT_SCANDV_BUSY;
2695 else
2696 completion_code = MPT_SCANDV_GOOD;
2697 break;
2698
2699 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2700 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2701 completion_code = MPT_SCANDV_DID_RESET;
2702 else
2703 completion_code = MPT_SCANDV_SOME_ERROR;
2704 break;
2705 default:
2706 completion_code = MPT_SCANDV_SOME_ERROR;
2707 break;
2708
2709 } /* switch(status) */
2710
2711 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2712 " completionCode set to %08xh\n", ioc->name, completion_code));
2713 return completion_code;
2714}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
2716/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2717/**
2718 * mptscsih_do_cmd - Do internal command.
2719 * @hd: MPT_SCSI_HOST pointer
2720 * @io: INTERNAL_CMD pointer.
2721 *
2722 * Issue the specified internally generated command and do command
2723 * specific cleanup. For bus scan / DV only.
2724 * NOTES: If command is Inquiry and status is good,
2725 * initialize a target structure, save the data
2726 *
2727 * Remark: Single threaded access only.
2728 *
2729 * Return:
2730 * < 0 if an illegal command or no resources
2731 *
2732 * 0 if good
2733 *
2734 * > 0 if command complete but some type of completion error.
2735 */
2736static int
2737mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2738{
2739 MPT_FRAME_HDR *mf;
2740 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302742 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 char cmdLen;
2744 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302745 u8 cmd = io->cmd;
2746 MPT_ADAPTER *ioc = hd->ioc;
2747 int ret = 0;
2748 unsigned long timeleft;
2749 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302751 /* don't send internal command during diag reset */
2752 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2753 if (ioc->ioc_reset_in_progress) {
2754 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2755 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2756 "%s: busy with host reset\n", ioc->name, __func__));
2757 return MPT_SCANDV_BUSY;
2758 }
2759 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2760
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302761 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
2763 /* Set command specific information
2764 */
2765 switch (cmd) {
2766 case INQUIRY:
2767 cmdLen = 6;
2768 dir = MPI_SCSIIO_CONTROL_READ;
2769 CDB[0] = cmd;
2770 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302771 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 break;
2773
2774 case TEST_UNIT_READY:
2775 cmdLen = 6;
2776 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302777 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 break;
2779
2780 case START_STOP:
2781 cmdLen = 6;
2782 dir = MPI_SCSIIO_CONTROL_READ;
2783 CDB[0] = cmd;
2784 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302785 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 break;
2787
2788 case REQUEST_SENSE:
2789 cmdLen = 6;
2790 CDB[0] = cmd;
2791 CDB[4] = io->size;
2792 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302793 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 break;
2795
2796 case READ_BUFFER:
2797 cmdLen = 10;
2798 dir = MPI_SCSIIO_CONTROL_READ;
2799 CDB[0] = cmd;
2800 if (io->flags & MPT_ICFLAG_ECHO) {
2801 CDB[1] = 0x0A;
2802 } else {
2803 CDB[1] = 0x02;
2804 }
2805
2806 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2807 CDB[1] |= 0x01;
2808 }
2809 CDB[6] = (io->size >> 16) & 0xFF;
2810 CDB[7] = (io->size >> 8) & 0xFF;
2811 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302812 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 break;
2814
2815 case WRITE_BUFFER:
2816 cmdLen = 10;
2817 dir = MPI_SCSIIO_CONTROL_WRITE;
2818 CDB[0] = cmd;
2819 if (io->flags & MPT_ICFLAG_ECHO) {
2820 CDB[1] = 0x0A;
2821 } else {
2822 CDB[1] = 0x02;
2823 }
2824 CDB[6] = (io->size >> 16) & 0xFF;
2825 CDB[7] = (io->size >> 8) & 0xFF;
2826 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302827 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 break;
2829
2830 case RESERVE:
2831 cmdLen = 6;
2832 dir = MPI_SCSIIO_CONTROL_READ;
2833 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302834 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 break;
2836
2837 case RELEASE:
2838 cmdLen = 6;
2839 dir = MPI_SCSIIO_CONTROL_READ;
2840 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302841 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 break;
2843
2844 case SYNCHRONIZE_CACHE:
2845 cmdLen = 10;
2846 dir = MPI_SCSIIO_CONTROL_READ;
2847 CDB[0] = cmd;
2848// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302849 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 break;
2851
2852 default:
2853 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302854 ret = -EFAULT;
2855 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 }
2857
2858 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302859 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 */
Eric Mooree80b0022007-09-14 18:49:03 -06002861 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302862 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2863 ioc->name, __func__));
2864 ret = MPT_SCANDV_BUSY;
2865 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 }
2867
2868 pScsiReq = (SCSIIORequest_t *) mf;
2869
2870 /* Get the request index */
2871 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2872 ADD_INDEX_LOG(my_idx); /* for debug */
2873
2874 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2875 pScsiReq->TargetID = io->physDiskNum;
2876 pScsiReq->Bus = 0;
2877 pScsiReq->ChainOffset = 0;
2878 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2879 } else {
2880 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002881 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 pScsiReq->ChainOffset = 0;
2883 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2884 }
2885
2886 pScsiReq->CDBLength = cmdLen;
2887 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2888
2889 pScsiReq->Reserved = 0;
2890
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302891 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 /* MsgContext set in mpt_get_msg_fram call */
2893
Eric Moore793955f2007-01-29 09:42:20 -07002894 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
2896 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2897 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2898 else
2899 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2900
2901 if (cmd == REQUEST_SENSE) {
2902 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302903 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2904 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 }
2906
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302907 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 pScsiReq->CDB[ii] = CDB[ii];
2909
2910 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06002911 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
2913
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302914 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2915 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
2916 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302918 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302919 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302920 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
2921 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302922 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302923 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302925 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06002926 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302927 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
2928 timeout*HZ);
2929 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2930 ret = MPT_SCANDV_DID_RESET;
2931 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2932 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
2933 cmd));
2934 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2935 mpt_free_msg_frame(ioc, mf);
2936 goto out;
2937 }
2938 if (!timeleft) {
2939 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
2940 ioc->name, __func__);
2941 mpt_HardResetHandler(ioc, CAN_SLEEP);
2942 mpt_free_msg_frame(ioc, mf);
2943 }
2944 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 }
2946
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302947 ret = ioc->internal_cmds.completion_code;
2948 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
2949 ioc->name, __func__, ret));
2950
2951 out:
2952 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
2953 mutex_unlock(&ioc->internal_cmds.mutex);
2954 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955}
2956
2957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2958/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002959 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
2960 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002961 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002962 *
2963 * Uses the ISR, but with special processing.
2964 * MUST be single-threaded.
2965 *
2966 */
2967static void
2968mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
2969{
2970 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
Eric Moorecc78d302007-06-15 17:27:21 -06002972 /* Ignore hidden raid components, this is handled when the command
2973 * is sent to the volume
2974 */
2975 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
2976 return;
2977
2978 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
2979 !vdevice->configured_lun)
2980 return;
2981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 /* Following parameters will not change
2983 * in this routine.
2984 */
2985 iocmd.cmd = SYNCHRONIZE_CACHE;
2986 iocmd.flags = 0;
2987 iocmd.physDiskNum = -1;
2988 iocmd.data = NULL;
2989 iocmd.data_dma = -1;
2990 iocmd.size = 0;
2991 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07002992 iocmd.channel = vdevice->vtarget->channel;
2993 iocmd.id = vdevice->vtarget->id;
2994 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
Eric Moorecc78d302007-06-15 17:27:21 -06002996 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997}
2998
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302999static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003000mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3001 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303002{
Tony Jonesee959b02008-02-22 00:13:36 +01003003 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003004 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303005 MPT_ADAPTER *ioc = hd->ioc;
3006
3007 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3008 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3009 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3010 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3011 ioc->facts.FWVersion.Word & 0x000000FF);
3012}
Tony Jonesee959b02008-02-22 00:13:36 +01003013static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303014
3015static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003016mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3017 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303018{
Tony Jonesee959b02008-02-22 00:13:36 +01003019 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003020 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303021 MPT_ADAPTER *ioc = hd->ioc;
3022
3023 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3024 (ioc->biosVersion & 0xFF000000) >> 24,
3025 (ioc->biosVersion & 0x00FF0000) >> 16,
3026 (ioc->biosVersion & 0x0000FF00) >> 8,
3027 ioc->biosVersion & 0x000000FF);
3028}
Tony Jonesee959b02008-02-22 00:13:36 +01003029static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303030
3031static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003032mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3033 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303034{
Tony Jonesee959b02008-02-22 00:13:36 +01003035 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003036 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303037 MPT_ADAPTER *ioc = hd->ioc;
3038
3039 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3040}
Tony Jonesee959b02008-02-22 00:13:36 +01003041static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303042
3043static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003044mptscsih_version_product_show(struct device *dev,
3045 struct device_attribute *attr,
3046char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303047{
Tony Jonesee959b02008-02-22 00:13:36 +01003048 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003049 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303050 MPT_ADAPTER *ioc = hd->ioc;
3051
3052 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3053}
Tony Jonesee959b02008-02-22 00:13:36 +01003054static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303055 mptscsih_version_product_show, NULL);
3056
3057static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003058mptscsih_version_nvdata_persistent_show(struct device *dev,
3059 struct device_attribute *attr,
3060 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303061{
Tony Jonesee959b02008-02-22 00:13:36 +01003062 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003063 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303064 MPT_ADAPTER *ioc = hd->ioc;
3065
3066 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3067 ioc->nvdata_version_persistent);
3068}
Tony Jonesee959b02008-02-22 00:13:36 +01003069static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303070 mptscsih_version_nvdata_persistent_show, NULL);
3071
3072static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003073mptscsih_version_nvdata_default_show(struct device *dev,
3074 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303075{
Tony Jonesee959b02008-02-22 00:13:36 +01003076 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003077 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303078 MPT_ADAPTER *ioc = hd->ioc;
3079
3080 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3081}
Tony Jonesee959b02008-02-22 00:13:36 +01003082static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303083 mptscsih_version_nvdata_default_show, NULL);
3084
3085static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003086mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3087 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303088{
Tony Jonesee959b02008-02-22 00:13:36 +01003089 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003090 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303091 MPT_ADAPTER *ioc = hd->ioc;
3092
3093 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3094}
Tony Jonesee959b02008-02-22 00:13:36 +01003095static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303096
3097static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003098mptscsih_board_assembly_show(struct device *dev,
3099 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303100{
Tony Jonesee959b02008-02-22 00:13:36 +01003101 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003102 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303103 MPT_ADAPTER *ioc = hd->ioc;
3104
3105 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3106}
Tony Jonesee959b02008-02-22 00:13:36 +01003107static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303108 mptscsih_board_assembly_show, NULL);
3109
3110static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003111mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3112 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303113{
Tony Jonesee959b02008-02-22 00:13:36 +01003114 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003115 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303116 MPT_ADAPTER *ioc = hd->ioc;
3117
3118 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3119}
Tony Jonesee959b02008-02-22 00:13:36 +01003120static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303121 mptscsih_board_tracer_show, NULL);
3122
3123static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003124mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3125 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303126{
Tony Jonesee959b02008-02-22 00:13:36 +01003127 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003128 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303129 MPT_ADAPTER *ioc = hd->ioc;
3130
3131 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3132}
Tony Jonesee959b02008-02-22 00:13:36 +01003133static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303134 mptscsih_io_delay_show, NULL);
3135
3136static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003137mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3138 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303139{
Tony Jonesee959b02008-02-22 00:13:36 +01003140 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003141 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303142 MPT_ADAPTER *ioc = hd->ioc;
3143
3144 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3145}
Tony Jonesee959b02008-02-22 00:13:36 +01003146static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303147 mptscsih_device_delay_show, NULL);
3148
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303149static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003150mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3151 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303152{
Tony Jonesee959b02008-02-22 00:13:36 +01003153 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003154 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303155 MPT_ADAPTER *ioc = hd->ioc;
3156
3157 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3158}
3159static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003160mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3161 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303162{
Tony Jonesee959b02008-02-22 00:13:36 +01003163 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003164 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303165 MPT_ADAPTER *ioc = hd->ioc;
3166 int val = 0;
3167
3168 if (sscanf(buf, "%x", &val) != 1)
3169 return -EINVAL;
3170
3171 ioc->debug_level = val;
3172 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3173 ioc->name, ioc->debug_level);
3174 return strlen(buf);
3175}
Tony Jonesee959b02008-02-22 00:13:36 +01003176static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3177 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303178
Tony Jonesee959b02008-02-22 00:13:36 +01003179struct device_attribute *mptscsih_host_attrs[] = {
3180 &dev_attr_version_fw,
3181 &dev_attr_version_bios,
3182 &dev_attr_version_mpi,
3183 &dev_attr_version_product,
3184 &dev_attr_version_nvdata_persistent,
3185 &dev_attr_version_nvdata_default,
3186 &dev_attr_board_name,
3187 &dev_attr_board_assembly,
3188 &dev_attr_board_tracer,
3189 &dev_attr_io_delay,
3190 &dev_attr_device_delay,
3191 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303192 NULL,
3193};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303194
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303195EXPORT_SYMBOL(mptscsih_host_attrs);
3196
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003197EXPORT_SYMBOL(mptscsih_remove);
3198EXPORT_SYMBOL(mptscsih_shutdown);
3199#ifdef CONFIG_PM
3200EXPORT_SYMBOL(mptscsih_suspend);
3201EXPORT_SYMBOL(mptscsih_resume);
3202#endif
3203EXPORT_SYMBOL(mptscsih_proc_info);
3204EXPORT_SYMBOL(mptscsih_info);
3205EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003206EXPORT_SYMBOL(mptscsih_slave_destroy);
3207EXPORT_SYMBOL(mptscsih_slave_configure);
3208EXPORT_SYMBOL(mptscsih_abort);
3209EXPORT_SYMBOL(mptscsih_dev_reset);
3210EXPORT_SYMBOL(mptscsih_bus_reset);
3211EXPORT_SYMBOL(mptscsih_host_reset);
3212EXPORT_SYMBOL(mptscsih_bios_param);
3213EXPORT_SYMBOL(mptscsih_io_done);
3214EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3215EXPORT_SYMBOL(mptscsih_scandv_complete);
3216EXPORT_SYMBOL(mptscsih_event_process);
3217EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003218EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003219EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/