blob: 2463731ed3559dca5de78e6ba7827049aa5ad46c [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, Desai1ba9ab22009-05-29 16:44:48 +0530102static void
103mptscsih_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
1307 if (hd->resetPending) {
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
Eric Moore958d4a32007-06-15 17:24:14 -06001712 if (hd->resetPending) {
1713 retval = FAILED;
1714 goto out;
1715 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001716
1717 if (hd->timeouts < -1)
1718 hd->timeouts++;
1719
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301720 if (mpt_fwfault_debug)
1721 mpt_halt_firmware(ioc);
1722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1724 * (the IO to be ABORT'd)
1725 *
1726 * NOTE: Since we do not byteswap MsgContext, we do not
1727 * swap it here either. It is an opaque cookie to
1728 * the controller, so it does not matter. -DaveM
1729 */
Eric Mooree80b0022007-09-14 18:49:03 -06001730 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1732
1733 hd->abortSCpnt = SCpnt;
1734
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301735 retval = mptscsih_IssueTaskMgmt(hd,
1736 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1737 vdevice->vtarget->channel,
1738 vdevice->vtarget->id, vdevice->lun,
1739 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Eric Mooree8206382007-09-29 10:16:53 -06001741 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001742 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001743 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001744
Eric Moore958d4a32007-06-15 17:24:14 -06001745 out:
1746 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1747 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001749 if (retval == 0)
1750 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001751 else
1752 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753}
1754
1755/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1756/**
1757 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1758 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1759 *
1760 * (linux scsi_host_template.eh_dev_reset_handler routine)
1761 *
1762 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001763 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001764int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1766{
1767 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001768 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001769 VirtDevice *vdevice;
1770 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772 /* If we can't locate our host adapter structure, return FAILED status.
1773 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001774 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001775 printk(KERN_ERR MYNAM ": target reset: "
1776 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 return FAILED;
1778 }
1779
Eric Moore958d4a32007-06-15 17:24:14 -06001780 ioc = hd->ioc;
1781 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1782 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001783 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Eric Moore958d4a32007-06-15 17:24:14 -06001785 if (hd->resetPending) {
1786 retval = FAILED;
1787 goto out;
1788 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001789
Eric Moore958d4a32007-06-15 17:24:14 -06001790 vdevice = SCpnt->device->hostdata;
1791 if (!vdevice || !vdevice->vtarget) {
1792 retval = 0;
1793 goto out;
1794 }
1795
Eric Moorecc78d302007-06-15 17:27:21 -06001796 /* Target reset to hidden raid component is not supported
1797 */
1798 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1799 retval = FAILED;
1800 goto out;
1801 }
1802
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301803 retval = mptscsih_IssueTaskMgmt(hd,
1804 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1805 vdevice->vtarget->channel,
1806 vdevice->vtarget->id, 0, 0,
1807 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001808
1809 out:
1810 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1811 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001812
1813 if (retval == 0)
1814 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001815 else
1816 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817}
1818
Eric Moorecd2c6192007-01-29 09:47:47 -07001819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1821/**
1822 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1823 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1824 *
1825 * (linux scsi_host_template.eh_bus_reset_handler routine)
1826 *
1827 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001828 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001829int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1831{
1832 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001833 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001834 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001835 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 /* If we can't locate our host adapter structure, return FAILED status.
1838 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001839 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001840 printk(KERN_ERR MYNAM ": bus reset: "
1841 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 return FAILED;
1843 }
1844
Eric Moore958d4a32007-06-15 17:24:14 -06001845 ioc = hd->ioc;
1846 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1847 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001848 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850 if (hd->timeouts < -1)
1851 hd->timeouts++;
1852
Eric Moorea69de502007-09-14 18:48:19 -06001853 vdevice = SCpnt->device->hostdata;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301854 retval = mptscsih_IssueTaskMgmt(hd,
1855 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1856 vdevice->vtarget->channel, 0, 0, 0,
1857 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
Eric Moore958d4a32007-06-15 17:24:14 -06001859 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1860 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001861
1862 if (retval == 0)
1863 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001864 else
1865 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1869/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001870 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1872 *
1873 * (linux scsi_host_template.eh_host_reset_handler routine)
1874 *
1875 * Returns SUCCESS or FAILED.
1876 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001877int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1879{
1880 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001881 int retval;
1882 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
1884 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001885 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001886 printk(KERN_ERR MYNAM ": host reset: "
1887 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 return FAILED;
1889 }
1890
James Bottomleya6da74c2008-12-15 14:13:27 -06001891 /* make sure we have no outstanding commands at this stage */
1892 mptscsih_flush_running_cmds(hd);
1893
Eric Moore958d4a32007-06-15 17:24:14 -06001894 ioc = hd->ioc;
1895 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1896 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898 /* If our attempts to reset the host failed, then return a failed
1899 * status. The host will be taken off line by the SCSI mid-layer.
1900 */
Eric Mooree80b0022007-09-14 18:49:03 -06001901 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06001902 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 } else {
1904 /* Make sure TM pending is cleared and TM state is set to
1905 * NONE.
1906 */
Eric Moore958d4a32007-06-15 17:24:14 -06001907 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 hd->tmPending = 0;
1909 hd->tmState = TM_STATE_NONE;
1910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
Eric Moore958d4a32007-06-15 17:24:14 -06001912 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1913 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Eric Moore958d4a32007-06-15 17:24:14 -06001915 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916}
1917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301919mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
1920 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301922 u16 iocstatus;
1923 u32 termination_count;
1924 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301926 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
1927 retval = FAILED;
1928 goto out;
1929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301931 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301933 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
1934 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301936 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1937 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
1938 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
1939 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
1940 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
1941 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
1942 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301944 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
1945 pScsiTmReply->ResponseCode)
1946 mptscsih_taskmgmt_response_code(ioc,
1947 pScsiTmReply->ResponseCode);
1948
1949 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
1950 retval = 0;
1951 goto out;
1952 }
1953
1954 retval = FAILED;
1955 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
1956 if (termination_count == 1)
1957 retval = 0;
1958 goto out;
1959 }
1960
1961 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1962 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1963 retval = 0;
1964
1965 out:
1966 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967}
1968
1969/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07001970static void
1971mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1972{
1973 char *desc;
1974
1975 switch (response_code) {
1976 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1977 desc = "The task completed.";
1978 break;
1979 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1980 desc = "The IOC received an invalid frame status.";
1981 break;
1982 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1983 desc = "The task type is not supported.";
1984 break;
1985 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1986 desc = "The requested task failed.";
1987 break;
1988 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1989 desc = "The task completed successfully.";
1990 break;
1991 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1992 desc = "The LUN request is invalid.";
1993 break;
1994 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1995 desc = "The task is in the IOC queue and has not been sent to target.";
1996 break;
1997 default:
1998 desc = "unknown";
1999 break;
2000 }
2001 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2002 ioc->name, response_code, desc);
2003}
2004
2005/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006/**
2007 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2008 * @ioc: Pointer to MPT_ADAPTER structure
2009 * @mf: Pointer to SCSI task mgmt request frame
2010 * @mr: Pointer to SCSI task mgmt reply frame
2011 *
2012 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2013 * of any SCSI task management request.
2014 * This routine is registered with the MPT (base) driver at driver
2015 * load/init time via the mpt_register() API call.
2016 *
2017 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002018 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002019int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302020mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2021 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302023 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2024 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302026 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302028 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002029 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002030
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302031 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2032 memcpy(ioc->taskmgmt_cmds.reply, mr,
2033 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002034 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302035 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2036 mpt_clear_taskmgmt_in_progress_flag(ioc);
2037 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2038 complete(&ioc->taskmgmt_cmds.done);
2039 return 1;
2040 }
2041 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042}
2043
2044/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2045/*
2046 * This is anyones guess quite frankly.
2047 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002048int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2050 sector_t capacity, int geom[])
2051{
2052 int heads;
2053 int sectors;
2054 sector_t cylinders;
2055 ulong dummy;
2056
2057 heads = 64;
2058 sectors = 32;
2059
2060 dummy = heads * sectors;
2061 cylinders = capacity;
2062 sector_div(cylinders,dummy);
2063
2064 /*
2065 * Handle extended translation size for logical drives
2066 * > 1Gb
2067 */
2068 if ((ulong)capacity >= 0x200000) {
2069 heads = 255;
2070 sectors = 63;
2071 dummy = heads * sectors;
2072 cylinders = capacity;
2073 sector_div(cylinders,dummy);
2074 }
2075
2076 /* return result */
2077 geom[0] = heads;
2078 geom[1] = sectors;
2079 geom[2] = cylinders;
2080
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 return 0;
2082}
2083
Moore, Ericf44e5462006-03-14 09:14:21 -07002084/* Search IOC page 3 to determine if this is hidden physical disk
2085 *
2086 */
2087int
Eric Moore793955f2007-01-29 09:42:20 -07002088mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002089{
Eric Mooreb506ade2007-01-29 09:45:37 -07002090 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002091 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002092 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002093
Eric Moore793955f2007-01-29 09:42:20 -07002094 if (!ioc->raid_data.pIocPg3)
2095 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002096 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002097 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2098 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2099 rc = 1;
2100 goto out;
2101 }
2102 }
2103
Eric Mooreb506ade2007-01-29 09:45:37 -07002104 /*
2105 * Check inactive list for matching phys disks
2106 */
2107 if (list_empty(&ioc->raid_data.inactive_list))
2108 goto out;
2109
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002110 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002111 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2112 list) {
2113 if ((component_info->d.PhysDiskID == id) &&
2114 (component_info->d.PhysDiskBus == channel))
2115 rc = 1;
2116 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002117 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002118
Eric Moore793955f2007-01-29 09:42:20 -07002119 out:
2120 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002121}
2122EXPORT_SYMBOL(mptscsih_is_phys_disk);
2123
Eric Moore793955f2007-01-29 09:42:20 -07002124u8
2125mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002126{
Eric Mooreb506ade2007-01-29 09:45:37 -07002127 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002128 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002129 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002130
Eric Moore793955f2007-01-29 09:42:20 -07002131 if (!ioc->raid_data.pIocPg3)
2132 goto out;
2133 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2134 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2135 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2136 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2137 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002138 }
2139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Eric Mooreb506ade2007-01-29 09:45:37 -07002141 /*
2142 * Check inactive list for matching phys disks
2143 */
2144 if (list_empty(&ioc->raid_data.inactive_list))
2145 goto out;
2146
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002147 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002148 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2149 list) {
2150 if ((component_info->d.PhysDiskID == id) &&
2151 (component_info->d.PhysDiskBus == channel))
2152 rc = component_info->d.PhysDiskNum;
2153 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002154 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002155
Eric Moore793955f2007-01-29 09:42:20 -07002156 out:
2157 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002158}
Eric Moore793955f2007-01-29 09:42:20 -07002159EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002160
2161/*
2162 * OS entry point to allow for host driver to free allocated memory
2163 * Called if no device present or device being unloaded
2164 */
2165void
2166mptscsih_slave_destroy(struct scsi_device *sdev)
2167{
2168 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002169 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002170 VirtTarget *vtarget;
2171 VirtDevice *vdevice;
2172 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002174 starget = scsi_target(sdev);
2175 vtarget = starget->hostdata;
2176 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002178 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002179 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002180 mptscsih_synchronize_cache(hd, vdevice);
2181 kfree(vdevice);
2182 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183}
2184
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002185/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2186/*
2187 * mptscsih_change_queue_depth - This function will set a devices queue depth
2188 * @sdev: per scsi_device pointer
2189 * @qdepth: requested queue depth
2190 *
2191 * Adding support for new 'change_queue_depth' api.
2192*/
2193int
2194mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002196 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002197 VirtTarget *vtarget;
2198 struct scsi_target *starget;
2199 int max_depth;
2200 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002201 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002203 starget = scsi_target(sdev);
2204 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002205
Eric Mooree80b0022007-09-14 18:49:03 -06002206 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002207 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002209 else if (sdev->type == TYPE_DISK &&
2210 vtarget->minSyncFactor <= MPT_ULTRA160)
2211 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2212 else
2213 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 } else
2215 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2216
2217 if (qdepth > max_depth)
2218 qdepth = max_depth;
2219 if (qdepth == 1)
2220 tagged = 0;
2221 else
2222 tagged = MSG_SIMPLE_TAG;
2223
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002224 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2225 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226}
2227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228/*
2229 * OS entry point to adjust the queue_depths on a per-device basis.
2230 * Called once per device the bus scan. Use it to force the queue_depth
2231 * member to 1 if a device does not support Q tags.
2232 * Return non-zero if fails.
2233 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002234int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002235mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002237 struct Scsi_Host *sh = sdev->host;
2238 VirtTarget *vtarget;
2239 VirtDevice *vdevice;
2240 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002241 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002242 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002244 starget = scsi_target(sdev);
2245 vtarget = starget->hostdata;
2246 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
Eric Mooree80b0022007-09-14 18:49:03 -06002248 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002249 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002250 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2251 if (ioc->bus_type == SPI)
2252 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002253 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002254 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002255 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Eric Moore793955f2007-01-29 09:42:20 -07002257 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002258 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
Eric Mooree80b0022007-09-14 18:49:03 -06002260 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002262 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
Eric Mooree80b0022007-09-14 18:49:03 -06002264 if (ioc->bus_type == SPI)
2265 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002266 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002267 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002268 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
Eric Mooree80b0022007-09-14 18:49:03 -06002270 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002272 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002273 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
2275 return 0;
2276}
2277
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2279/*
2280 * Private routines...
2281 */
2282
2283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2284/* Utility function to copy sense data from the scsi_cmnd buffer
2285 * to the FC and SCSI target structures.
2286 *
2287 */
2288static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002289mptscsih_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 -07002290{
Eric Moorea69de502007-09-14 18:48:19 -06002291 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 SCSIIORequest_t *pReq;
2293 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002294 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296 /* Get target structure
2297 */
2298 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002299 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
2301 if (sense_count) {
2302 u8 *sense_data;
2303 int req_index;
2304
2305 /* Copy the sense received into the scsi command block. */
2306 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002307 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2309
2310 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2311 */
Eric Mooree80b0022007-09-14 18:49:03 -06002312 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002313 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002316 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2318 ioc->events[idx].eventContext = ioc->eventContext;
2319
Dave Jones3d9780b2007-05-21 20:59:47 -04002320 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2321 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2322 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Dave Jones3d9780b2007-05-21 20:59:47 -04002324 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
2326 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002327 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002328 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002329 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002330 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2331 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002332 MPT_TARGET_FLAGS_LED_ON;
2333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 }
2335 }
2336 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002337 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2338 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 }
2340}
2341
Eric Mooree8206382007-09-29 10:16:53 -06002342/**
2343 * mptscsih_get_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002344 * @ioc: Pointer to MPT_ADAPTER structure
2345 * @i: index into the array
2346 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002347 * retrieves scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002348 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002349 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002350 **/
2351static struct scsi_cmnd *
2352mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353{
Eric Mooree8206382007-09-29 10:16:53 -06002354 unsigned long flags;
2355 struct scsi_cmnd *scmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Eric Mooree8206382007-09-29 10:16:53 -06002357 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2358 scmd = ioc->ScsiLookup[i];
2359 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Eric Mooree8206382007-09-29 10:16:53 -06002361 return scmd;
2362}
2363
2364/**
2365 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002366 * @ioc: Pointer to MPT_ADAPTER structure
2367 * @i: index into the array
2368 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002369 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002370 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002371 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002372 **/
2373static struct scsi_cmnd *
2374mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2375{
2376 unsigned long flags;
2377 struct scsi_cmnd *scmd;
2378
2379 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2380 scmd = ioc->ScsiLookup[i];
2381 ioc->ScsiLookup[i] = NULL;
2382 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2383
2384 return scmd;
2385}
2386
2387/**
2388 * mptscsih_set_scsi_lookup
2389 *
2390 * writes a scmd entry into the ScsiLookup[] array list
2391 *
2392 * @ioc: Pointer to MPT_ADAPTER structure
2393 * @i: index into the array
2394 * @scmd: scsi_cmnd pointer
2395 *
2396 **/
2397static void
2398mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2399{
2400 unsigned long flags;
2401
2402 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2403 ioc->ScsiLookup[i] = scmd;
2404 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2405}
2406
2407/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002408 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002409 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002410 * @sc: scsi_cmnd pointer
2411 */
Eric Mooree8206382007-09-29 10:16:53 -06002412static int
2413SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2414{
2415 unsigned long flags;
2416 int i, index=-1;
2417
2418 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2419 for (i = 0; i < ioc->req_depth; i++) {
2420 if (ioc->ScsiLookup[i] == sc) {
2421 index = i;
2422 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 }
2424 }
2425
Eric Mooree8206382007-09-29 10:16:53 -06002426 out:
2427 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2428 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429}
2430
2431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002432int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2434{
2435 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Eric Mooree7eae9f2007-09-29 10:15:59 -06002437 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302440 hd = shost_priv(ioc->sh);
2441 switch (reset_phase) {
2442 case MPT_IOC_SETUP_RESET:
2443 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2444 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 hd->resetPending = 1;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302446 break;
2447 case MPT_IOC_PRE_RESET:
2448 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2449 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 hd->resetPending = 0;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302451 mptscsih_flush_running_cmds(hd);
2452 break;
2453 case MPT_IOC_POST_RESET:
2454 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2455 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2456 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2457 ioc->internal_cmds.status |=
2458 MPT_MGMT_STATUS_DID_IOCRESET;
2459 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302461 break;
2462 default:
2463 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 return 1; /* currently means nothing really */
2466}
2467
2468/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002469int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2471{
2472 MPT_SCSI_HOST *hd;
2473 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2474
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302475 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2476 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2477 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002479 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06002480 ((hd = shost_priv(ioc->sh)) == NULL))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002481 return 1;
2482
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 switch (event) {
2484 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2485 /* FIXME! */
2486 break;
2487 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2488 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002489 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002490 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 break;
2492 case MPI_EVENT_LOGOUT: /* 09 */
2493 /* FIXME! */
2494 break;
2495
Michael Reed05e8ec12006-01-13 14:31:54 -06002496 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002497 break;
2498
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 /*
2500 * CHECKME! Don't think we need to do
2501 * anything for these, but...
2502 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2504 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2505 /*
2506 * CHECKME! Falling thru...
2507 */
2508 break;
2509
2510 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002511 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 case MPI_EVENT_NONE: /* 00 */
2514 case MPI_EVENT_LOG_DATA: /* 01 */
2515 case MPI_EVENT_STATE_CHANGE: /* 02 */
2516 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2517 default:
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302518 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2519 ": Ignoring event (=%02Xh)\n",
2520 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 break;
2522 }
2523
2524 return 1; /* currently means nothing really */
2525}
2526
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2528/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 * Bus Scan and Domain Validation functionality ...
2530 */
2531
2532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2533/*
2534 * mptscsih_scandv_complete - Scan and DV callback routine registered
2535 * to Fustion MPT (base) driver.
2536 *
2537 * @ioc: Pointer to MPT_ADAPTER structure
2538 * @mf: Pointer to original MPT request frame
2539 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2540 *
2541 * This routine is called from mpt.c::mpt_interrupt() at the completion
2542 * of any SCSI IO request.
2543 * This routine is registered with the Fusion MPT (base) driver at driver
2544 * load/init time via the mpt_register() API call.
2545 *
2546 * Returns 1 indicating alloc'd request frame ptr should be freed.
2547 *
2548 * Remark: Sets a completion code and (possibly) saves sense data
2549 * in the IOC member localReply structure.
2550 * Used ONLY for DV and other internal commands.
2551 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002552int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302553mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2554 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302557 SCSIIOReply_t *pReply;
2558 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302560 u8 *sense_data;
2561 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302563 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2564 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2565 if (!reply)
2566 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002567
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302568 pReply = (SCSIIOReply_t *) reply;
2569 pReq = (SCSIIORequest_t *) req;
2570 ioc->internal_cmds.completion_code =
2571 mptscsih_get_completion_code(ioc, req, reply);
2572 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2573 memcpy(ioc->internal_cmds.reply, reply,
2574 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2575 cmd = reply->u.hdr.Function;
2576 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2577 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2578 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2579 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2580 sense_data = ((u8 *)ioc->sense_buf_pool +
2581 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2582 sz = min_t(int, pReq->SenseBufferLength,
2583 MPT_SENSE_BUFFER_ALLOC);
2584 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302586 out:
2587 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2588 return 0;
2589 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2590 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 return 1;
2592}
2593
2594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2595/* mptscsih_timer_expired - Call back for timer process.
2596 * Used only for dv functionality.
2597 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2598 *
2599 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002600void
2601mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602{
2603 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002604 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Eric Mooree80b0022007-09-14 18:49:03 -06002606 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 if (hd->cmdPtr) {
2609 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2610
2611 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2612 /* Desire to issue a task management request here.
2613 * TM requests MUST be single threaded.
2614 * If old eh code and no TM current, issue request.
2615 * If new eh code, do nothing. Wait for OS cmd timeout
2616 * for bus reset.
2617 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 } else {
2619 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002620 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2621 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 }
2623 }
2624 } else {
2625 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002626 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 }
2628
2629 /* No more processing.
2630 * TM call will generate an interrupt for SCSI TM Management.
2631 * The FW will reply to all outstanding commands, callback will finish cleanup.
2632 * Hard reset clean-up will free all resources.
2633 */
Eric Mooree80b0022007-09-14 18:49:03 -06002634 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 return;
2637}
2638
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302639/**
2640 * mptscsih_get_completion_code -
2641 * @ioc: Pointer to MPT_ADAPTER structure
2642 * @reply:
2643 * @cmd:
2644 *
2645 **/
2646static int
2647mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2648 MPT_FRAME_HDR *reply)
2649{
2650 SCSIIOReply_t *pReply;
2651 MpiRaidActionReply_t *pr;
2652 u8 scsi_status;
2653 u16 status;
2654 int completion_code;
2655
2656 pReply = (SCSIIOReply_t *)reply;
2657 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2658 scsi_status = pReply->SCSIStatus;
2659
2660 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2661 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2662 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2663 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2664
2665 switch (status) {
2666
2667 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2668 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2669 break;
2670
2671 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2672 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2673 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2674 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2675 completion_code = MPT_SCANDV_DID_RESET;
2676 break;
2677
2678 case MPI_IOCSTATUS_BUSY:
2679 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2680 completion_code = MPT_SCANDV_BUSY;
2681 break;
2682
2683 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2684 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2685 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2686 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2687 completion_code = MPT_SCANDV_GOOD;
2688 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2689 pr = (MpiRaidActionReply_t *)reply;
2690 if (le16_to_cpu(pr->ActionStatus) ==
2691 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2692 completion_code = MPT_SCANDV_GOOD;
2693 else
2694 completion_code = MPT_SCANDV_SOME_ERROR;
2695 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2696 completion_code = MPT_SCANDV_SENSE;
2697 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2698 if (req->u.scsireq.CDB[0] == INQUIRY)
2699 completion_code = MPT_SCANDV_ISSUE_SENSE;
2700 else
2701 completion_code = MPT_SCANDV_DID_RESET;
2702 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2703 completion_code = MPT_SCANDV_DID_RESET;
2704 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2705 completion_code = MPT_SCANDV_DID_RESET;
2706 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2707 completion_code = MPT_SCANDV_BUSY;
2708 else
2709 completion_code = MPT_SCANDV_GOOD;
2710 break;
2711
2712 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2713 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2714 completion_code = MPT_SCANDV_DID_RESET;
2715 else
2716 completion_code = MPT_SCANDV_SOME_ERROR;
2717 break;
2718 default:
2719 completion_code = MPT_SCANDV_SOME_ERROR;
2720 break;
2721
2722 } /* switch(status) */
2723
2724 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2725 " completionCode set to %08xh\n", ioc->name, completion_code));
2726 return completion_code;
2727}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
2729/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2730/**
2731 * mptscsih_do_cmd - Do internal command.
2732 * @hd: MPT_SCSI_HOST pointer
2733 * @io: INTERNAL_CMD pointer.
2734 *
2735 * Issue the specified internally generated command and do command
2736 * specific cleanup. For bus scan / DV only.
2737 * NOTES: If command is Inquiry and status is good,
2738 * initialize a target structure, save the data
2739 *
2740 * Remark: Single threaded access only.
2741 *
2742 * Return:
2743 * < 0 if an illegal command or no resources
2744 *
2745 * 0 if good
2746 *
2747 * > 0 if command complete but some type of completion error.
2748 */
2749static int
2750mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2751{
2752 MPT_FRAME_HDR *mf;
2753 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302755 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 char cmdLen;
2757 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 +05302758 u8 cmd = io->cmd;
2759 MPT_ADAPTER *ioc = hd->ioc;
2760 int ret = 0;
2761 unsigned long timeleft;
2762 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302764 /* don't send internal command during diag reset */
2765 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2766 if (ioc->ioc_reset_in_progress) {
2767 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2768 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2769 "%s: busy with host reset\n", ioc->name, __func__));
2770 return MPT_SCANDV_BUSY;
2771 }
2772 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2773
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302774 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
2776 /* Set command specific information
2777 */
2778 switch (cmd) {
2779 case INQUIRY:
2780 cmdLen = 6;
2781 dir = MPI_SCSIIO_CONTROL_READ;
2782 CDB[0] = cmd;
2783 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302784 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 break;
2786
2787 case TEST_UNIT_READY:
2788 cmdLen = 6;
2789 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302790 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 break;
2792
2793 case START_STOP:
2794 cmdLen = 6;
2795 dir = MPI_SCSIIO_CONTROL_READ;
2796 CDB[0] = cmd;
2797 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302798 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 break;
2800
2801 case REQUEST_SENSE:
2802 cmdLen = 6;
2803 CDB[0] = cmd;
2804 CDB[4] = io->size;
2805 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302806 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 break;
2808
2809 case READ_BUFFER:
2810 cmdLen = 10;
2811 dir = MPI_SCSIIO_CONTROL_READ;
2812 CDB[0] = cmd;
2813 if (io->flags & MPT_ICFLAG_ECHO) {
2814 CDB[1] = 0x0A;
2815 } else {
2816 CDB[1] = 0x02;
2817 }
2818
2819 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2820 CDB[1] |= 0x01;
2821 }
2822 CDB[6] = (io->size >> 16) & 0xFF;
2823 CDB[7] = (io->size >> 8) & 0xFF;
2824 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302825 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 break;
2827
2828 case WRITE_BUFFER:
2829 cmdLen = 10;
2830 dir = MPI_SCSIIO_CONTROL_WRITE;
2831 CDB[0] = cmd;
2832 if (io->flags & MPT_ICFLAG_ECHO) {
2833 CDB[1] = 0x0A;
2834 } else {
2835 CDB[1] = 0x02;
2836 }
2837 CDB[6] = (io->size >> 16) & 0xFF;
2838 CDB[7] = (io->size >> 8) & 0xFF;
2839 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302840 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 break;
2842
2843 case RESERVE:
2844 cmdLen = 6;
2845 dir = MPI_SCSIIO_CONTROL_READ;
2846 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302847 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 break;
2849
2850 case RELEASE:
2851 cmdLen = 6;
2852 dir = MPI_SCSIIO_CONTROL_READ;
2853 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302854 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 break;
2856
2857 case SYNCHRONIZE_CACHE:
2858 cmdLen = 10;
2859 dir = MPI_SCSIIO_CONTROL_READ;
2860 CDB[0] = cmd;
2861// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302862 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 break;
2864
2865 default:
2866 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302867 ret = -EFAULT;
2868 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 }
2870
2871 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302872 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 */
Eric Mooree80b0022007-09-14 18:49:03 -06002874 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302875 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2876 ioc->name, __func__));
2877 ret = MPT_SCANDV_BUSY;
2878 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 }
2880
2881 pScsiReq = (SCSIIORequest_t *) mf;
2882
2883 /* Get the request index */
2884 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2885 ADD_INDEX_LOG(my_idx); /* for debug */
2886
2887 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2888 pScsiReq->TargetID = io->physDiskNum;
2889 pScsiReq->Bus = 0;
2890 pScsiReq->ChainOffset = 0;
2891 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2892 } else {
2893 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002894 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 pScsiReq->ChainOffset = 0;
2896 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2897 }
2898
2899 pScsiReq->CDBLength = cmdLen;
2900 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2901
2902 pScsiReq->Reserved = 0;
2903
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302904 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 /* MsgContext set in mpt_get_msg_fram call */
2906
Eric Moore793955f2007-01-29 09:42:20 -07002907 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2910 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2911 else
2912 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2913
2914 if (cmd == REQUEST_SENSE) {
2915 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302916 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2917 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 }
2919
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302920 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 pScsiReq->CDB[ii] = CDB[ii];
2922
2923 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06002924 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
2926
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302927 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2928 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
2929 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302931 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302932 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302933 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
2934 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302935 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302936 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302938 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06002939 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302940 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
2941 timeout*HZ);
2942 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2943 ret = MPT_SCANDV_DID_RESET;
2944 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2945 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
2946 cmd));
2947 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2948 mpt_free_msg_frame(ioc, mf);
2949 goto out;
2950 }
2951 if (!timeleft) {
2952 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
2953 ioc->name, __func__);
2954 mpt_HardResetHandler(ioc, CAN_SLEEP);
2955 mpt_free_msg_frame(ioc, mf);
2956 }
2957 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 }
2959
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302960 ret = ioc->internal_cmds.completion_code;
2961 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
2962 ioc->name, __func__, ret));
2963
2964 out:
2965 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
2966 mutex_unlock(&ioc->internal_cmds.mutex);
2967 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968}
2969
2970/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2971/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002972 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
2973 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002974 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002975 *
2976 * Uses the ISR, but with special processing.
2977 * MUST be single-threaded.
2978 *
2979 */
2980static void
2981mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
2982{
2983 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
Eric Moorecc78d302007-06-15 17:27:21 -06002985 /* Ignore hidden raid components, this is handled when the command
2986 * is sent to the volume
2987 */
2988 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
2989 return;
2990
2991 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
2992 !vdevice->configured_lun)
2993 return;
2994
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 /* Following parameters will not change
2996 * in this routine.
2997 */
2998 iocmd.cmd = SYNCHRONIZE_CACHE;
2999 iocmd.flags = 0;
3000 iocmd.physDiskNum = -1;
3001 iocmd.data = NULL;
3002 iocmd.data_dma = -1;
3003 iocmd.size = 0;
3004 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003005 iocmd.channel = vdevice->vtarget->channel;
3006 iocmd.id = vdevice->vtarget->id;
3007 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
Eric Moorecc78d302007-06-15 17:27:21 -06003009 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010}
3011
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303012static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003013mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3014 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303015{
Tony Jonesee959b02008-02-22 00:13:36 +01003016 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003017 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303018 MPT_ADAPTER *ioc = hd->ioc;
3019
3020 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3021 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3022 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3023 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3024 ioc->facts.FWVersion.Word & 0x000000FF);
3025}
Tony Jonesee959b02008-02-22 00:13:36 +01003026static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303027
3028static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003029mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3030 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303031{
Tony Jonesee959b02008-02-22 00:13:36 +01003032 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003033 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303034 MPT_ADAPTER *ioc = hd->ioc;
3035
3036 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3037 (ioc->biosVersion & 0xFF000000) >> 24,
3038 (ioc->biosVersion & 0x00FF0000) >> 16,
3039 (ioc->biosVersion & 0x0000FF00) >> 8,
3040 ioc->biosVersion & 0x000000FF);
3041}
Tony Jonesee959b02008-02-22 00:13:36 +01003042static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303043
3044static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003045mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3046 char *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, "%03x\n", ioc->facts.MsgVersion);
3053}
Tony Jonesee959b02008-02-22 00:13:36 +01003054static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303055
3056static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003057mptscsih_version_product_show(struct device *dev,
3058 struct device_attribute *attr,
3059char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303060{
Tony Jonesee959b02008-02-22 00:13:36 +01003061 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003062 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303063 MPT_ADAPTER *ioc = hd->ioc;
3064
3065 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3066}
Tony Jonesee959b02008-02-22 00:13:36 +01003067static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303068 mptscsih_version_product_show, NULL);
3069
3070static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003071mptscsih_version_nvdata_persistent_show(struct device *dev,
3072 struct device_attribute *attr,
3073 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303074{
Tony Jonesee959b02008-02-22 00:13:36 +01003075 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003076 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303077 MPT_ADAPTER *ioc = hd->ioc;
3078
3079 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3080 ioc->nvdata_version_persistent);
3081}
Tony Jonesee959b02008-02-22 00:13:36 +01003082static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303083 mptscsih_version_nvdata_persistent_show, NULL);
3084
3085static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003086mptscsih_version_nvdata_default_show(struct device *dev,
3087 struct device_attribute *attr, 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, "%02xh\n",ioc->nvdata_version_default);
3094}
Tony Jonesee959b02008-02-22 00:13:36 +01003095static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303096 mptscsih_version_nvdata_default_show, NULL);
3097
3098static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003099mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3100 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303101{
Tony Jonesee959b02008-02-22 00:13:36 +01003102 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003103 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303104 MPT_ADAPTER *ioc = hd->ioc;
3105
3106 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3107}
Tony Jonesee959b02008-02-22 00:13:36 +01003108static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303109
3110static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003111mptscsih_board_assembly_show(struct device *dev,
3112 struct device_attribute *attr, 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_assembly);
3119}
Tony Jonesee959b02008-02-22 00:13:36 +01003120static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303121 mptscsih_board_assembly_show, NULL);
3122
3123static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003124mptscsih_board_tracer_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, "%s\n", ioc->board_tracer);
3132}
Tony Jonesee959b02008-02-22 00:13:36 +01003133static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303134 mptscsih_board_tracer_show, NULL);
3135
3136static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003137mptscsih_io_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->io_missing_delay);
3145}
Tony Jonesee959b02008-02-22 00:13:36 +01003146static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303147 mptscsih_io_delay_show, NULL);
3148
3149static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003150mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3151 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +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, Sathyaedb90682007-07-17 14:39:14 +05303155 MPT_ADAPTER *ioc = hd->ioc;
3156
3157 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3158}
Tony Jonesee959b02008-02-22 00:13:36 +01003159static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303160 mptscsih_device_delay_show, NULL);
3161
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303162static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003163mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3164 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303165{
Tony Jonesee959b02008-02-22 00:13:36 +01003166 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003167 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303168 MPT_ADAPTER *ioc = hd->ioc;
3169
3170 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3171}
3172static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003173mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3174 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303175{
Tony Jonesee959b02008-02-22 00:13:36 +01003176 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003177 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303178 MPT_ADAPTER *ioc = hd->ioc;
3179 int val = 0;
3180
3181 if (sscanf(buf, "%x", &val) != 1)
3182 return -EINVAL;
3183
3184 ioc->debug_level = val;
3185 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3186 ioc->name, ioc->debug_level);
3187 return strlen(buf);
3188}
Tony Jonesee959b02008-02-22 00:13:36 +01003189static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3190 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303191
Tony Jonesee959b02008-02-22 00:13:36 +01003192struct device_attribute *mptscsih_host_attrs[] = {
3193 &dev_attr_version_fw,
3194 &dev_attr_version_bios,
3195 &dev_attr_version_mpi,
3196 &dev_attr_version_product,
3197 &dev_attr_version_nvdata_persistent,
3198 &dev_attr_version_nvdata_default,
3199 &dev_attr_board_name,
3200 &dev_attr_board_assembly,
3201 &dev_attr_board_tracer,
3202 &dev_attr_io_delay,
3203 &dev_attr_device_delay,
3204 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303205 NULL,
3206};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303207
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303208EXPORT_SYMBOL(mptscsih_host_attrs);
3209
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003210EXPORT_SYMBOL(mptscsih_remove);
3211EXPORT_SYMBOL(mptscsih_shutdown);
3212#ifdef CONFIG_PM
3213EXPORT_SYMBOL(mptscsih_suspend);
3214EXPORT_SYMBOL(mptscsih_resume);
3215#endif
3216EXPORT_SYMBOL(mptscsih_proc_info);
3217EXPORT_SYMBOL(mptscsih_info);
3218EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003219EXPORT_SYMBOL(mptscsih_slave_destroy);
3220EXPORT_SYMBOL(mptscsih_slave_configure);
3221EXPORT_SYMBOL(mptscsih_abort);
3222EXPORT_SYMBOL(mptscsih_dev_reset);
3223EXPORT_SYMBOL(mptscsih_bus_reset);
3224EXPORT_SYMBOL(mptscsih_host_reset);
3225EXPORT_SYMBOL(mptscsih_bios_param);
3226EXPORT_SYMBOL(mptscsih_io_done);
3227EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3228EXPORT_SYMBOL(mptscsih_scandv_complete);
3229EXPORT_SYMBOL(mptscsih_event_process);
3230EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003231EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003232EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/