blob: a6a2bbda2f18c7abd8f99a675ec9b4e1deb7ea7b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/workqueue.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060063#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "mptbase.h"
66#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060067#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*
81 * Other private/forward protos...
82 */
Eric Mooree8206382007-09-29 10:16:53 -060083static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
84static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
85static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
86static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040087int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040089int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
92 SCSIIORequest_t *pReq, int req_idx);
93static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040094static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +053096int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
97 int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040099int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
100int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530102void
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530103mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530104static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
105 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400106int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700108static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530110static int
111mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
112 SCSITaskMgmtReply_t *pScsiTmReply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400113void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700114void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400116int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
117int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#endif
119
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900120#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
124/*
125 * mptscsih_getFreeChainBuffer - Function to get a free chain
126 * from the MPT_SCSI_HOST FreeChainQ.
127 * @ioc: Pointer to MPT_ADAPTER structure
128 * @req_idx: Index of the SCSI IO request frame. (output)
129 *
130 * return SUCCESS or FAILED
131 */
132static inline int
133mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
134{
135 MPT_FRAME_HDR *chainBuf;
136 unsigned long flags;
137 int rc;
138 int chain_idx;
139
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530140 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600141 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 spin_lock_irqsave(&ioc->FreeQlock, flags);
143 if (!list_empty(&ioc->FreeChainQ)) {
144 int offset;
145
146 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
147 u.frame.linkage.list);
148 list_del(&chainBuf->u.frame.linkage.list);
149 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
150 chain_idx = offset / ioc->req_sz;
151 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600152 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
153 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
154 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 } else {
156 rc = FAILED;
157 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600158 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
159 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
162
163 *retIndex = chain_idx;
164 return rc;
165} /* mptscsih_getFreeChainBuffer() */
166
167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
168/*
169 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
170 * SCSIIORequest_t Message Frame.
171 * @ioc: Pointer to MPT_ADAPTER structure
172 * @SCpnt: Pointer to scsi_cmnd structure
173 * @pReq: Pointer to SCSIIORequest_t structure
174 *
175 * Returns ...
176 */
177static int
178mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
179 SCSIIORequest_t *pReq, int req_idx)
180{
181 char *psge;
182 char *chainSge;
183 struct scatterlist *sg;
184 int frm_sz;
185 int sges_left, sg_done;
186 int chain_idx = MPT_HOST_NO_CHAIN;
187 int sgeOffset;
188 int numSgeSlots, numSgeThisFrame;
189 u32 sgflags, sgdir, thisxfer = 0;
190 int chain_dma_off = 0;
191 int newIndex;
192 int ii;
193 dma_addr_t v2;
194 u32 RequestNB;
195
196 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
197 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
198 sgdir = MPT_TRANSFER_HOST_TO_IOC;
199 } else {
200 sgdir = MPT_TRANSFER_IOC_TO_HOST;
201 }
202
203 psge = (char *) &pReq->SGL;
204 frm_sz = ioc->req_sz;
205
206 /* Map the data portion, if any.
207 * sges_left = 0 if no data transfer.
208 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900209 sges_left = scsi_dma_map(SCpnt);
210 if (sges_left < 0)
211 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 /* Handle the SG case.
214 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900215 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 sg_done = 0;
217 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
218 chainSge = NULL;
219
220 /* Prior to entering this loop - the following must be set
221 * current MF: sgeOffset (bytes)
222 * chainSge (Null if original MF is not a chain buffer)
223 * sg_done (num SGE done for this MF)
224 */
225
226nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530227 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
229
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530230 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 /* Get first (num - 1) SG elements
233 * Skip any SG entries with a length of 0
234 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
235 */
236 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
237 thisxfer = sg_dma_len(sg);
238 if (thisxfer == 0) {
Jens Axboeed17b032007-07-16 15:30:33 +0200239 sg = sg_next(sg); /* Get next SG element from the OS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 sg_done++;
241 continue;
242 }
243
244 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530245 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Jens Axboeed17b032007-07-16 15:30:33 +0200247 sg = sg_next(sg); /* Get next SG element from the OS */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530248 psge += ioc->SGE_size;
249 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 sg_done++;
251 }
252
253 if (numSgeThisFrame == sges_left) {
254 /* Add last element, end of buffer and end of list flags.
255 */
256 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
257 MPT_SGE_FLAGS_END_OF_BUFFER |
258 MPT_SGE_FLAGS_END_OF_LIST;
259
260 /* Add last SGE and set termination flags.
261 * Note: Last SGE may have a length of 0 - which should be ok.
262 */
263 thisxfer = sg_dma_len(sg);
264
265 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530266 ioc->add_sge(psge, sgflags | thisxfer, v2);
267 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 sg_done++;
269
270 if (chainSge) {
271 /* The current buffer is a chain buffer,
272 * but there is not another one.
273 * Update the chain element
274 * Offset and Length fields.
275 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530276 ioc->add_chain((char *)chainSge, 0, sgeOffset,
277 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 } else {
279 /* The current buffer is the original MF
280 * and there is no Chain buffer.
281 */
282 pReq->ChainOffset = 0;
283 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530284 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
286 ioc->RequestNB[req_idx] = RequestNB;
287 }
288 } else {
289 /* At least one chain buffer is needed.
290 * Complete the first MF
291 * - last SGE element, set the LastElement bit
292 * - set ChainOffset (words) for orig MF
293 * (OR finish previous MF chain buffer)
294 * - update MFStructPtr ChainIndex
295 * - Populate chain element
296 * Also
297 * Loop until done.
298 */
299
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530300 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 ioc->name, sg_done));
302
303 /* Set LAST_ELEMENT flag for last non-chain element
304 * in the buffer. Since psge points at the NEXT
305 * SGE element, go back one SGE element, update the flags
306 * and reset the pointer. (Note: sgflags & thisxfer are already
307 * set properly).
308 */
309 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530310 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 sgflags = le32_to_cpu(*ptmp);
312 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
313 *ptmp = cpu_to_le32(sgflags);
314 }
315
316 if (chainSge) {
317 /* The current buffer is a chain buffer.
318 * chainSge points to the previous Chain Element.
319 * Update its chain element Offset and Length (must
320 * include chain element size) fields.
321 * Old chain element is now complete.
322 */
323 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530324 sgeOffset += ioc->SGE_size;
325 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
326 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 } else {
328 /* The original MF buffer requires a chain buffer -
329 * set the offset.
330 * Last element in this MF is a chain element.
331 */
332 pReq->ChainOffset = (u8) (sgeOffset >> 2);
333 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530334 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 ioc->RequestNB[req_idx] = RequestNB;
336 }
337
338 sges_left -= sg_done;
339
340
341 /* NOTE: psge points to the beginning of the chain element
342 * in current buffer. Get a chain buffer.
343 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200344 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530345 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200346 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
347 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 /* Update the tracking arrays.
352 * If chainSge == NULL, update ReqToChain, else ChainToChain
353 */
354 if (chainSge) {
355 ioc->ChainToChain[chain_idx] = newIndex;
356 } else {
357 ioc->ReqToChain[req_idx] = newIndex;
358 }
359 chain_idx = newIndex;
360 chain_dma_off = ioc->req_sz * chain_idx;
361
362 /* Populate the chainSGE for the current buffer.
363 * - Set chain buffer pointer to psge and fill
364 * out the Address and Flags fields.
365 */
366 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600367 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
368 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370 /* Start the SGE for the next buffer
371 */
372 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
373 sgeOffset = 0;
374 sg_done = 0;
375
Eric Moore29dd3602007-09-14 18:46:51 -0600376 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
377 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 /* Start the SGE for the next buffer
380 */
381
382 goto nextSGEset;
383 }
384
385 return SUCCESS;
386} /* mptscsih_AddSGE() */
387
Eric Moore786899b2006-07-11 17:22:22 -0600388static void
389mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
390 U32 SlotStatus)
391{
392 MPT_FRAME_HDR *mf;
393 SEPRequest_t *SEPMsg;
394
Eric Moorecc78d302007-06-15 17:27:21 -0600395 if (ioc->bus_type != SAS)
396 return;
397
398 /* Not supported for hidden raid components
399 */
400 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600401 return;
402
403 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530404 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700405 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600406 return;
407 }
408
409 SEPMsg = (SEPRequest_t *)mf;
410 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700411 SEPMsg->Bus = vtarget->channel;
412 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600413 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
414 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530415 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700416 "Sending SEP cmd=%x channel=%d id=%d\n",
417 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600418 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
419}
420
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530421#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700422/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530423 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700424 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700425 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530426 * @pScsiReply: Pointer to MPT reply frame
427 *
428 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700429 *
430 * Refer to lsi/mpi.h.
431 **/
432static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530433mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700434{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530435 char *desc = NULL;
436 char *desc1 = NULL;
437 u16 ioc_status;
438 u8 skey, asc, ascq;
439
440 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700441
442 switch (ioc_status) {
443
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530444 case MPI_IOCSTATUS_SUCCESS:
445 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700446 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530447 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
448 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700449 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530450 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
451 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700452 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530453 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
454 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700455 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530456 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
457 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700458 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530459 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
460 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700461 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530462 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
463 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700464 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530465 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
466 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700467 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530468 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
469 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700470 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530471 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
472 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700473 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530474 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
475 desc = "task management failed";
476 break;
477 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
478 desc = "IOC terminated";
479 break;
480 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
481 desc = "ext terminated";
482 break;
483 default:
484 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700485 break;
486 }
487
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530488 switch (pScsiReply->SCSIStatus)
489 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700490
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530491 case MPI_SCSI_STATUS_SUCCESS:
492 desc1 = "success";
493 break;
494 case MPI_SCSI_STATUS_CHECK_CONDITION:
495 desc1 = "check condition";
496 break;
497 case MPI_SCSI_STATUS_CONDITION_MET:
498 desc1 = "condition met";
499 break;
500 case MPI_SCSI_STATUS_BUSY:
501 desc1 = "busy";
502 break;
503 case MPI_SCSI_STATUS_INTERMEDIATE:
504 desc1 = "intermediate";
505 break;
506 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
507 desc1 = "intermediate condmet";
508 break;
509 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
510 desc1 = "reservation conflict";
511 break;
512 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
513 desc1 = "command terminated";
514 break;
515 case MPI_SCSI_STATUS_TASK_SET_FULL:
516 desc1 = "task set full";
517 break;
518 case MPI_SCSI_STATUS_ACA_ACTIVE:
519 desc1 = "aca active";
520 break;
521 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
522 desc1 = "fcpext device logged out";
523 break;
524 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
525 desc1 = "fcpext no link";
526 break;
527 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
528 desc1 = "fcpext unassigned";
529 break;
530 default:
531 desc1 = "";
532 break;
533 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700534
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530535 scsi_print_command(sc);
Eric Moore29dd3602007-09-14 18:46:51 -0600536 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
537 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
538 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
539 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
540 scsi_get_resid(sc));
541 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
542 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530543 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Eric Moore29dd3602007-09-14 18:46:51 -0600544 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530545 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600546 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530547 pScsiReply->SCSIState);
548
549 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
550 skey = sc->sense_buffer[2] & 0x0F;
551 asc = sc->sense_buffer[12];
552 ascq = sc->sense_buffer[13];
553
Eric Moore29dd3602007-09-14 18:46:51 -0600554 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
555 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530556 }
557
558 /*
559 * Look for + dump FCP ResponseInfo[]!
560 */
561 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
562 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600563 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
564 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700565}
566#endif
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
569/*
570 * mptscsih_io_done - Main SCSI IO callback routine registered to
571 * Fusion MPT (base) driver
572 * @ioc: Pointer to MPT_ADAPTER structure
573 * @mf: Pointer to original MPT request frame
574 * @r: Pointer to MPT reply frame (NULL if TurboReply)
575 *
576 * This routine is called from mpt.c::mpt_interrupt() at the completion
577 * of any SCSI IO request.
578 * This routine is registered with the Fusion MPT (base) driver at driver
579 * load/init time via the mpt_register() API call.
580 *
581 * Returns 1 indicating alloc'd request frame ptr should be freed.
582 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400583int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
585{
586 struct scsi_cmnd *sc;
587 MPT_SCSI_HOST *hd;
588 SCSIIORequest_t *pScsiReq;
589 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700590 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600591 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600592 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Eric Mooree7eae9f2007-09-29 10:15:59 -0600594 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700596 req_idx_MR = (mr != NULL) ?
597 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
598 if ((req_idx != req_idx_MR) ||
599 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
600 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
601 ioc->name);
602 printk (MYIOC_s_ERR_FMT
603 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
604 ioc->name, req_idx, req_idx_MR, mf, mr,
Eric Mooree8206382007-09-29 10:16:53 -0600605 mptscsih_get_scsi_lookup(ioc, req_idx_MR));
Moore, Eric2254c862006-01-17 17:06:29 -0700606 return 0;
607 }
608
Eric Mooree8206382007-09-29 10:16:53 -0600609 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (sc == NULL) {
611 MPIHeader_t *hdr = (MPIHeader_t *)mf;
612
613 /* Remark: writeSDP1 will use the ScsiDoneCtx
614 * If a SCSI I/O cmd, device disabled by OS and
615 * completion done. Cannot touch sc struct. Just free mem.
616 */
617 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
618 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
619 ioc->name);
620
621 mptscsih_freeChainBuffers(ioc, req_idx);
622 return 1;
623 }
624
Eric Moore3dc0b032006-07-11 17:32:33 -0600625 if ((unsigned char *)mf != sc->host_scribble) {
626 mptscsih_freeChainBuffers(ioc, req_idx);
627 return 1;
628 }
629
630 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 sc->result = DID_OK << 16; /* Set default reply as OK */
632 pScsiReq = (SCSIIORequest_t *) mf;
633 pScsiReply = (SCSIIOReply_t *) mr;
634
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200635 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530636 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200637 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
638 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
639 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530640 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200641 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
642 ioc->name, mf, mr, sc, req_idx));
643 }
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (pScsiReply == NULL) {
646 /* special context reply handling */
647 ;
648 } else {
649 u32 xfer_cnt;
650 u16 status;
651 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700652 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
655 scsi_state = pScsiReply->SCSIState;
656 scsi_status = pScsiReply->SCSIStatus;
657 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900658 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700659 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600661 /*
662 * if we get a data underrun indication, yet no data was
663 * transferred and the SCSI status indicates that the
664 * command was never started, change the data underrun
665 * to success
666 */
667 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
668 (scsi_status == MPI_SCSI_STATUS_BUSY ||
669 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
670 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
671 status = MPI_IOCSTATUS_SUCCESS;
672 }
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400675 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 /*
678 * Look for + dump FCP ResponseInfo[]!
679 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600680 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
681 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600682 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
683 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700684 sc->device->host->host_no, sc->device->channel,
685 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 le32_to_cpu(pScsiReply->ResponseInfo));
687 }
688
689 switch(status) {
690 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
691 /* CHECKME!
692 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
693 * But not: DID_BUS_BUSY lest one risk
694 * killing interrupt handler:-(
695 */
696 sc->result = SAM_STAT_BUSY;
697 break;
698
699 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
700 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
701 sc->result = DID_BAD_TARGET << 16;
702 break;
703
704 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
705 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600706 if (ioc->bus_type != FC)
707 sc->result = DID_NO_CONNECT << 16;
708 /* else fibre, just stall until rescan event */
709 else
710 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
713 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600714
Eric Moorea69de502007-09-14 18:48:19 -0600715 vdevice = sc->device->hostdata;
716 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600717 break;
Eric Moorea69de502007-09-14 18:48:19 -0600718 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600719 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
720 mptscsih_issue_sep_command(ioc, vtarget,
721 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
722 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 break;
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600727 if ( ioc->bus_type == SAS ) {
728 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
729 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700730 if ((log_info & SAS_LOGINFO_MASK)
731 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600732 sc->result = (DID_BUS_BUSY << 16);
733 break;
734 }
735 }
Eric Moore86dd4242007-01-04 20:44:01 -0700736 } else if (ioc->bus_type == FC) {
737 /*
738 * The FC IOC may kill a request for variety of
739 * reasons, some of which may be recovered by a
740 * retry, some which are unlikely to be
741 * recovered. Return DID_ERROR instead of
742 * DID_RESET to permit retry of the command,
743 * just not an infinite number of them
744 */
745 sc->result = DID_ERROR << 16;
746 break;
Eric Moorebf451522006-07-11 17:25:35 -0600747 }
748
749 /*
750 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
751 */
752
753 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
755 /* Linux handles an unsolicited DID_RESET better
756 * than an unsolicited DID_ABORT.
757 */
758 sc->result = DID_RESET << 16;
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 break;
761
762 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900763 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600764 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
765 sc->result=DID_SOFT_ERROR << 16;
766 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600768 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700769 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600770 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
774 /*
775 * Do upfront check for valid SenseData and give it
776 * precedence!
777 */
778 sc->result = (DID_OK << 16) | scsi_status;
779 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
780 /* Have already saved the status and sense data
781 */
782 ;
783 } else {
784 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600785 if (scsi_status == SAM_STAT_BUSY)
786 sc->result = SAM_STAT_BUSY;
787 else
788 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
791 /* What to do?
792 */
793 sc->result = DID_SOFT_ERROR << 16;
794 }
795 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
796 /* Not real sure here either... */
797 sc->result = DID_RESET << 16;
798 }
799 }
800
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530801
Eric Moore29dd3602007-09-14 18:46:51 -0600802 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
803 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
804 ioc->name, sc->underflow));
805 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
806 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 /* Report Queue Full
809 */
810 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
811 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 break;
814
Moore, Eric7e551472006-01-16 18:53:21 -0700815 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900816 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
818 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600819 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (scsi_state == 0) {
821 ;
822 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
823 /*
824 * If running against circa 200003dd 909 MPT f/w,
825 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
826 * (QUEUE_FULL) returned from device! --> get 0x0000?128
827 * and with SenseBytes set to 0.
828 */
829 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
830 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
831
832 }
833 else if (scsi_state &
834 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
835 ) {
836 /*
837 * What to do?
838 */
839 sc->result = DID_SOFT_ERROR << 16;
840 }
841 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
842 /* Not real sure here either... */
843 sc->result = DID_RESET << 16;
844 }
845 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
846 /* Device Inq. data indicates that it supports
847 * QTags, but rejects QTag messages.
848 * This command completed OK.
849 *
850 * Not real sure here either so do nothing... */
851 }
852
853 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
854 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
855
856 /* Add handling of:
857 * Reservation Conflict, Busy,
858 * Command Terminated, CHECK
859 */
860 break;
861
862 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
863 sc->result = DID_SOFT_ERROR << 16;
864 break;
865
866 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
867 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
868 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
869 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
870 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
871 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
872 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
874 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
875 default:
876 /*
877 * What to do?
878 */
879 sc->result = DID_SOFT_ERROR << 16;
880 break;
881
882 } /* switch(status) */
883
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530884#ifdef CONFIG_FUSION_LOGGING
885 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
886 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700887#endif
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 } /* end of address reply case */
890
891 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900892 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 sc->scsi_done(sc); /* Issue the command callback */
895
896 /* Free Chain buffers */
897 mptscsih_freeChainBuffers(ioc, req_idx);
898 return 1;
899}
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901/*
902 * mptscsih_flush_running_cmds - For each command found, search
903 * Scsi_Host instance taskQ and reply to OS.
904 * Called only if recovering from a FW reload.
905 * @hd: Pointer to a SCSI HOST structure
906 *
907 * Returns: None.
908 *
909 * Must be called while new I/Os are being queued.
910 */
911static void
912mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
913{
914 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600915 struct scsi_cmnd *sc;
916 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 int ii;
Eric Mooree8206382007-09-29 10:16:53 -0600918 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Eric Mooree8206382007-09-29 10:16:53 -0600920 for (ii= 0; ii < ioc->req_depth; ii++) {
921 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
922 if (!sc)
923 continue;
924 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
925 if (!mf)
926 continue;
927 channel = mf->Bus;
928 id = mf->TargetID;
929 mptscsih_freeChainBuffers(ioc, ii);
930 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
931 if ((unsigned char *)mf != sc->host_scribble)
932 continue;
933 scsi_dma_unmap(sc);
934 sc->result = DID_RESET << 16;
935 sc->host_scribble = NULL;
Eric Moorec51d0be2007-09-29 10:17:21 -0600936 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
Eric Mooree8206382007-09-29 10:16:53 -0600937 "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
938 " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
939 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
943/*
944 * mptscsih_search_running_cmds - Delete any commands associated
945 * with the specified target and lun. Function called only
946 * when a lun is disable by mid-layer.
947 * Do NOT access the referenced scsi_cmnd structure or
948 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600949 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700950 * @hd: Pointer to a SCSI HOST structure
951 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 *
953 * Returns: None.
954 *
955 * Called from slave_destroy.
956 */
957static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700958mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
960 SCSIIORequest_t *mf = NULL;
961 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600962 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700963 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -0600964 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600965 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Eric Mooree8206382007-09-29 10:16:53 -0600967 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
968 for (ii = 0; ii < ioc->req_depth; ii++) {
969 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Eric Mooree80b0022007-09-14 18:49:03 -0600971 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600972 if (mf == NULL)
973 continue;
Eric Moorecc78d302007-06-15 17:27:21 -0600974 /* If the device is a hidden raid component, then its
975 * expected that the mf->function will be RAID_SCSI_IO
976 */
977 if (vdevice->vtarget->tflags &
978 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
979 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
980 continue;
981
Eric Moore793955f2007-01-29 09:42:20 -0700982 int_to_scsilun(vdevice->lun, &lun);
983 if ((mf->Bus != vdevice->vtarget->channel) ||
984 (mf->TargetID != vdevice->vtarget->id) ||
985 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 continue;
987
Eric Moore3dc0b032006-07-11 17:32:33 -0600988 if ((unsigned char *)mf != sc->host_scribble)
989 continue;
Eric Mooree8206382007-09-29 10:16:53 -0600990 ioc->ScsiLookup[ii] = NULL;
991 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
992 mptscsih_freeChainBuffers(ioc, ii);
993 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900994 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600995 sc->host_scribble = NULL;
996 sc->result = DID_NO_CONNECT << 16;
Eric Moorec51d0be2007-09-29 10:17:21 -0600997 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
Eric Mooree80b0022007-09-14 18:49:03 -0600998 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530999 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001000 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001001 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 }
1003 }
Eric Mooree8206382007-09-29 10:16:53 -06001004 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return;
1006}
1007
1008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1011/*
1012 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1013 * from a SCSI target device.
1014 * @sc: Pointer to scsi_cmnd structure
1015 * @pScsiReply: Pointer to SCSIIOReply_t
1016 * @pScsiReq: Pointer to original SCSI request
1017 *
1018 * This routine periodically reports QUEUE_FULL status returned from a
1019 * SCSI target device. It reports this to the console via kernel
1020 * printk() API call, not more than once every 10 seconds.
1021 */
1022static void
1023mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1024{
1025 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001027 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001029 if (sc->device == NULL)
1030 return;
1031 if (sc->device->host == NULL)
1032 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001033 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001034 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001035 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001036 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001037 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1038 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001039 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041}
1042
1043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1044/*
1045 * mptscsih_remove - Removed scsi devices
1046 * @pdev: Pointer to pci_dev structure
1047 *
1048 *
1049 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001050void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051mptscsih_remove(struct pci_dev *pdev)
1052{
1053 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1054 struct Scsi_Host *host = ioc->sh;
1055 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001056 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001058 if(!host) {
1059 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063 scsi_remove_host(host);
1064
Eric Mooree7eae9f2007-09-29 10:15:59 -06001065 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001066 return;
1067
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001068 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001070 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Eric Mooree8206382007-09-29 10:16:53 -06001072 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001073 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001074 kfree(ioc->ScsiLookup);
1075 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077
Eric Mooree80b0022007-09-14 18:49:03 -06001078 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001079 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001080 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001081
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001082 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001083
1084 /* NULL the Scsi_Host pointer
1085 */
Eric Mooree80b0022007-09-14 18:49:03 -06001086 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001087
1088 scsi_host_put(host);
1089
1090 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
1094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1095/*
1096 * mptscsih_shutdown - reboot notifier
1097 *
1098 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001099void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001100mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102}
1103
1104#ifdef CONFIG_PM
1105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1106/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001107 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 *
1109 *
1110 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001111int
Pavel Machek8d189f72005-04-16 15:25:28 -07001112mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301114 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1115
1116 scsi_block_requests(ioc->sh);
1117 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001118 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001119 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
1122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1123/*
1124 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1125 *
1126 *
1127 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129mptscsih_resume(struct pci_dev *pdev)
1130{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301131 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1132 int rc;
1133
1134 rc = mpt_resume(pdev);
1135 scsi_unblock_requests(ioc->sh);
1136 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
1139#endif
1140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1142/**
1143 * mptscsih_info - Return information about MPT adapter
1144 * @SChost: Pointer to Scsi_Host structure
1145 *
1146 * (linux scsi_host_template.info routine)
1147 *
1148 * Returns pointer to buffer where information was written.
1149 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001150const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151mptscsih_info(struct Scsi_Host *SChost)
1152{
1153 MPT_SCSI_HOST *h;
1154 int size = 0;
1155
Eric Mooree7eae9f2007-09-29 10:15:59 -06001156 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159 if (h->info_kbuf == NULL)
1160 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1161 return h->info_kbuf;
1162 h->info_kbuf[0] = '\0';
1163
1164 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1165 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001168 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169}
1170
1171struct info_str {
1172 char *buffer;
1173 int length;
1174 int offset;
1175 int pos;
1176};
1177
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001178static void
1179mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
1181 if (info->pos + len > info->length)
1182 len = info->length - info->pos;
1183
1184 if (info->pos + len < info->offset) {
1185 info->pos += len;
1186 return;
1187 }
1188
1189 if (info->pos < info->offset) {
1190 data += (info->offset - info->pos);
1191 len -= (info->offset - info->pos);
1192 }
1193
1194 if (len > 0) {
1195 memcpy(info->buffer + info->pos, data, len);
1196 info->pos += len;
1197 }
1198}
1199
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001200static int
1201mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 va_list args;
1204 char buf[81];
1205 int len;
1206
1207 va_start(args, fmt);
1208 len = vsprintf(buf, fmt, args);
1209 va_end(args);
1210
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return len;
1213}
1214
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001215static int
1216mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
1218 struct info_str info;
1219
1220 info.buffer = pbuf;
1221 info.length = len;
1222 info.offset = offset;
1223 info.pos = 0;
1224
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001225 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1226 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1227 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1228 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1231}
1232
1233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1234/**
1235 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001236 * @host: scsi host struct
1237 * @buffer: if write, user data; if read, buffer for user
1238 * @start: returns the buffer address
1239 * @offset: if write, 0; if read, the current offset into the buffer from
1240 * the previous read.
1241 * @length: if write, return length;
1242 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 *
1244 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001246int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1248 int length, int func)
1249{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001250 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 MPT_ADAPTER *ioc = hd->ioc;
1252 int size = 0;
1253
1254 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001255 /*
1256 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 */
1258 } else {
1259 if (start)
1260 *start = buffer;
1261
1262 size = mptscsih_host_info(ioc, buffer, offset, length);
1263 }
1264
1265 return size;
1266}
1267
1268/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1269#define ADD_INDEX_LOG(req_ent) do { } while(0)
1270
1271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1272/**
1273 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1274 * @SCpnt: Pointer to scsi_cmnd structure
1275 * @done: Pointer SCSI mid-layer IO completion function
1276 *
1277 * (linux scsi_host_template.queuecommand routine)
1278 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1279 * from a linux scsi_cmnd request and send it to the IOC.
1280 *
1281 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1282 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001283int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1285{
1286 MPT_SCSI_HOST *hd;
1287 MPT_FRAME_HDR *mf;
1288 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001289 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 int lun;
1291 u32 datalen;
1292 u32 scsictl;
1293 u32 scsidir;
1294 u32 cmd_len;
1295 int my_idx;
1296 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301297 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Eric Mooree7eae9f2007-09-29 10:15:59 -06001299 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301300 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 lun = SCpnt->device->lun;
1302 SCpnt->scsi_done = done;
1303
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301304 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1305 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301307 if (ioc->taskmgmt_quiesce_io) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301308 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1309 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 return SCSI_MLQUEUE_HOST_BUSY;
1311 }
1312
1313 /*
1314 * Put together a MPT SCSI request...
1315 */
Eric Mooree80b0022007-09-14 18:49:03 -06001316 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301317 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1318 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 return SCSI_MLQUEUE_HOST_BUSY;
1320 }
1321
1322 pScsiReq = (SCSIIORequest_t *) mf;
1323
1324 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1325
1326 ADD_INDEX_LOG(my_idx);
1327
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001328 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 * Seems we may receive a buffer (datalen>0) even when there
1330 * will be no data transfer! GRRRRR...
1331 */
1332 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001333 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1335 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001336 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1338 } else {
1339 datalen = 0;
1340 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1341 }
1342
1343 /* Default to untagged. Once a target structure has been allocated,
1344 * use the Inquiry data to determine if device supports tagged.
1345 */
Eric Moorea69de502007-09-14 18:48:19 -06001346 if (vdevice
1347 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 && (SCpnt->device->tagged_supported)) {
1349 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1350 } else {
1351 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1352 }
1353
1354 /* Use the above information to set up the message frame
1355 */
Eric Moorea69de502007-09-14 18:48:19 -06001356 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1357 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001359 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001360 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1361 else
1362 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pScsiReq->CDBLength = SCpnt->cmd_len;
1364 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1365 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301366 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001367 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 pScsiReq->Control = cpu_to_le32(scsictl);
1369
1370 /*
1371 * Write SCSI CDB into the message
1372 */
1373 cmd_len = SCpnt->cmd_len;
1374 for (ii=0; ii < cmd_len; ii++)
1375 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1376
1377 for (ii=cmd_len; ii < 16; ii++)
1378 pScsiReq->CDB[ii] = 0;
1379
1380 /* DataLength */
1381 pScsiReq->DataLength = cpu_to_le32(datalen);
1382
1383 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001384 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1386
1387 /* Now add the SG list
1388 * Always have a SGE even if null length.
1389 */
1390 if (datalen == 0) {
1391 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301392 ioc->add_sge((char *)&pScsiReq->SGL,
1393 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 (dma_addr_t) -1);
1395 } else {
1396 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001397 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 goto fail;
1399 }
1400
Eric Moore3dc0b032006-07-11 17:32:33 -06001401 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001402 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Eric Mooree80b0022007-09-14 18:49:03 -06001404 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301405 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1406 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001407 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 return 0;
1409
1410 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001411 mptscsih_freeChainBuffers(ioc, my_idx);
1412 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 return SCSI_MLQUEUE_HOST_BUSY;
1414}
1415
1416/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1417/*
1418 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1419 * with a SCSI IO request
1420 * @hd: Pointer to the MPT_SCSI_HOST instance
1421 * @req_idx: Index of the SCSI IO request frame.
1422 *
1423 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1424 * No return.
1425 */
1426static void
1427mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1428{
1429 MPT_FRAME_HDR *chain;
1430 unsigned long flags;
1431 int chain_idx;
1432 int next;
1433
1434 /* Get the first chain index and reset
1435 * tracker state.
1436 */
1437 chain_idx = ioc->ReqToChain[req_idx];
1438 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1439
1440 while (chain_idx != MPT_HOST_NO_CHAIN) {
1441
1442 /* Save the next chain buffer index */
1443 next = ioc->ChainToChain[chain_idx];
1444
1445 /* Free this chain buffer and reset
1446 * tracker
1447 */
1448 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1449
1450 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1451 + (chain_idx * ioc->req_sz));
1452
1453 spin_lock_irqsave(&ioc->FreeQlock, flags);
1454 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1455 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1456
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301457 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 ioc->name, chain_idx));
1459
1460 /* handle next */
1461 chain_idx = next;
1462 }
1463 return;
1464}
1465
1466/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1467/*
1468 * Reset Handling
1469 */
1470
1471/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001472/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1474 * @hd: Pointer to MPT_SCSI_HOST structure
1475 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001476 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001477 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 * @lun: Logical Unit for reset (if appropriate)
1479 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001480 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 *
1482 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1483 * or a non-interrupt thread. In the former, must not call schedule().
1484 *
1485 * Not all fields are meaningfull for all task types.
1486 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001487 * Returns 0 for SUCCESS, or FAILED.
1488 *
1489 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301490int
1491mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1492 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 MPT_FRAME_HDR *mf;
1495 SCSITaskMgmt_t *pScsiTm;
1496 int ii;
1497 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001498 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301499 unsigned long timeleft;
1500 u8 issue_hard_reset;
1501 u32 ioc_raw_state;
1502 unsigned long time_count;
1503
1504 issue_hard_reset = 0;
1505 ioc_raw_state = mpt_GetIocState(ioc, 0);
1506
1507 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1508 printk(MYIOC_s_WARN_FMT
1509 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1510 ioc->name, type, ioc_raw_state);
1511 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1512 ioc->name, __func__);
1513 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1514 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1515 "FAILED!!\n", ioc->name);
1516 return 0;
1517 }
1518
1519 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1520 printk(MYIOC_s_WARN_FMT
1521 "TaskMgmt type=%x: ioc_state: "
1522 "DOORBELL_ACTIVE (0x%x)!\n",
1523 ioc->name, type, ioc_raw_state);
1524 return FAILED;
1525 }
1526
1527 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1528 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1529 mf = NULL;
1530 retval = FAILED;
1531 goto out;
1532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534 /* Return Fail to calling function if no message frames available.
1535 */
Eric Mooree80b0022007-09-14 18:49:03 -06001536 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301537 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1538 "TaskMgmt no msg frames!!\n", ioc->name));
1539 retval = FAILED;
1540 mpt_clear_taskmgmt_in_progress_flag(ioc);
1541 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301543 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001544 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
1546 /* Format the Request
1547 */
1548 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001549 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 pScsiTm->Bus = channel;
1551 pScsiTm->ChainOffset = 0;
1552 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1553
1554 pScsiTm->Reserved = 0;
1555 pScsiTm->TaskType = type;
1556 pScsiTm->Reserved1 = 0;
1557 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1558 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1559
Eric Moore793955f2007-01-29 09:42:20 -07001560 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 for (ii=0; ii < 7; ii++)
1563 pScsiTm->Reserved2[ii] = 0;
1564
1565 pScsiTm->TaskMsgContext = ctx2abort;
1566
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301567 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1568 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1569 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301571 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301573 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1574 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001575 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1576 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1577 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301578 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001579 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301580 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1581 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301582 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1583 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1584 ioc->name, mf, retval));
1585 mpt_free_msg_frame(ioc, mf);
1586 mpt_clear_taskmgmt_in_progress_flag(ioc);
1587 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 }
1590
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301591 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1592 timeout*HZ);
1593 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1594 retval = FAILED;
1595 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1596 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1597 mpt_clear_taskmgmt_in_progress_flag(ioc);
1598 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1599 goto out;
1600 issue_hard_reset = 1;
1601 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 }
1603
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301604 retval = mptscsih_taskmgmt_reply(ioc, type,
1605 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001606
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301607 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1608 "TaskMgmt completed (%d seconds)\n",
1609 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1610
1611 out:
1612
1613 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1614 if (issue_hard_reset) {
1615 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
1616 ioc->name, __func__);
1617 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1618 mpt_free_msg_frame(ioc, mf);
1619 }
1620
1621 retval = (retval == 0) ? 0 : FAILED;
1622 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return retval;
1624}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301625EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001627static int
1628mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1629{
1630 switch (ioc->bus_type) {
1631 case FC:
1632 return 40;
1633 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001634 case SPI:
1635 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001636 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001637 }
1638}
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1641/**
1642 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1643 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1644 *
1645 * (linux scsi_host_template.eh_abort_handler routine)
1646 *
1647 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001648 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001649int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650mptscsih_abort(struct scsi_cmnd * SCpnt)
1651{
1652 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 MPT_FRAME_HDR *mf;
1654 u32 ctx2abort;
1655 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001656 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001657 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001658 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001659 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 /* If we can't locate our host adapter structure, return FAILED status.
1662 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001663 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 SCpnt->result = DID_RESET << 16;
1665 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001666 printk(KERN_ERR MYNAM ": task abort: "
1667 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 return FAILED;
1669 }
1670
Eric Moore958d4a32007-06-15 17:24:14 -06001671 ioc = hd->ioc;
1672 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1673 ioc->name, SCpnt);
1674 scsi_print_command(SCpnt);
1675
1676 vdevice = SCpnt->device->hostdata;
1677 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001678 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1679 "task abort: device has been deleted (sc=%p)\n",
1680 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001681 SCpnt->result = DID_NO_CONNECT << 16;
1682 SCpnt->scsi_done(SCpnt);
1683 retval = 0;
1684 goto out;
1685 }
1686
Eric Moorecc78d302007-06-15 17:27:21 -06001687 /* Task aborts are not supported for hidden raid components.
1688 */
1689 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001690 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1691 "task abort: hidden raid component (sc=%p)\n",
1692 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001693 SCpnt->result = DID_RESET << 16;
1694 retval = FAILED;
1695 goto out;
1696 }
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 /* Find this command
1699 */
Eric Mooree8206382007-09-29 10:16:53 -06001700 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001701 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 * Do OS callback.
1703 */
1704 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001705 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001706 "Command not in the active list! (sc=%p)\n", ioc->name,
1707 SCpnt));
1708 retval = 0;
1709 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
1711
Moore, Eric65207fe2006-04-21 16:14:35 -06001712 if (hd->timeouts < -1)
1713 hd->timeouts++;
1714
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301715 if (mpt_fwfault_debug)
1716 mpt_halt_firmware(ioc);
1717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1719 * (the IO to be ABORT'd)
1720 *
1721 * NOTE: Since we do not byteswap MsgContext, we do not
1722 * swap it here either. It is an opaque cookie to
1723 * the controller, so it does not matter. -DaveM
1724 */
Eric Mooree80b0022007-09-14 18:49:03 -06001725 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1727
1728 hd->abortSCpnt = SCpnt;
1729
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301730 retval = mptscsih_IssueTaskMgmt(hd,
1731 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1732 vdevice->vtarget->channel,
1733 vdevice->vtarget->id, vdevice->lun,
1734 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Eric Mooree8206382007-09-29 10:16:53 -06001736 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001737 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001738 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001739
Eric Moore958d4a32007-06-15 17:24:14 -06001740 out:
1741 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1742 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001744 if (retval == 0)
1745 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001746 else
1747 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748}
1749
1750/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1751/**
1752 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1753 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1754 *
1755 * (linux scsi_host_template.eh_dev_reset_handler routine)
1756 *
1757 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001758 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001759int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1761{
1762 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001763 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001764 VirtDevice *vdevice;
1765 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 /* If we can't locate our host adapter structure, return FAILED status.
1768 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001769 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001770 printk(KERN_ERR MYNAM ": target reset: "
1771 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return FAILED;
1773 }
1774
Eric Moore958d4a32007-06-15 17:24:14 -06001775 ioc = hd->ioc;
1776 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1777 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001778 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Eric Moore958d4a32007-06-15 17:24:14 -06001780 vdevice = SCpnt->device->hostdata;
1781 if (!vdevice || !vdevice->vtarget) {
1782 retval = 0;
1783 goto out;
1784 }
1785
Eric Moorecc78d302007-06-15 17:27:21 -06001786 /* Target reset to hidden raid component is not supported
1787 */
1788 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1789 retval = FAILED;
1790 goto out;
1791 }
1792
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301793 retval = mptscsih_IssueTaskMgmt(hd,
1794 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1795 vdevice->vtarget->channel,
1796 vdevice->vtarget->id, 0, 0,
1797 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001798
1799 out:
1800 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1801 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001802
1803 if (retval == 0)
1804 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001805 else
1806 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807}
1808
Eric Moorecd2c6192007-01-29 09:47:47 -07001809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1811/**
1812 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1813 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1814 *
1815 * (linux scsi_host_template.eh_bus_reset_handler routine)
1816 *
1817 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001818 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001819int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1821{
1822 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001823 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001824 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001825 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
1827 /* If we can't locate our host adapter structure, return FAILED status.
1828 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001829 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001830 printk(KERN_ERR MYNAM ": bus reset: "
1831 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 return FAILED;
1833 }
1834
Eric Moore958d4a32007-06-15 17:24:14 -06001835 ioc = hd->ioc;
1836 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1837 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001838 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
1840 if (hd->timeouts < -1)
1841 hd->timeouts++;
1842
Eric Moorea69de502007-09-14 18:48:19 -06001843 vdevice = SCpnt->device->hostdata;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301844 retval = mptscsih_IssueTaskMgmt(hd,
1845 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1846 vdevice->vtarget->channel, 0, 0, 0,
1847 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Eric Moore958d4a32007-06-15 17:24:14 -06001849 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1850 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001851
1852 if (retval == 0)
1853 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001854 else
1855 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856}
1857
1858/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1859/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001860 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1862 *
1863 * (linux scsi_host_template.eh_host_reset_handler routine)
1864 *
1865 * Returns SUCCESS or FAILED.
1866 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001867int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1869{
1870 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001871 int retval;
1872 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001875 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001876 printk(KERN_ERR MYNAM ": host reset: "
1877 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 return FAILED;
1879 }
1880
James Bottomleya6da74c2008-12-15 14:13:27 -06001881 /* make sure we have no outstanding commands at this stage */
1882 mptscsih_flush_running_cmds(hd);
1883
Eric Moore958d4a32007-06-15 17:24:14 -06001884 ioc = hd->ioc;
1885 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1886 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 /* If our attempts to reset the host failed, then return a failed
1889 * status. The host will be taken off line by the SCSI mid-layer.
1890 */
Eric Mooree80b0022007-09-14 18:49:03 -06001891 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06001892 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 } else {
1894 /* Make sure TM pending is cleared and TM state is set to
1895 * NONE.
1896 */
Eric Moore958d4a32007-06-15 17:24:14 -06001897 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 hd->tmPending = 0;
1899 hd->tmState = TM_STATE_NONE;
1900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
Eric Moore958d4a32007-06-15 17:24:14 -06001902 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1903 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Eric Moore958d4a32007-06-15 17:24:14 -06001905 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906}
1907
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301909mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
1910 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301912 u16 iocstatus;
1913 u32 termination_count;
1914 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301916 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
1917 retval = FAILED;
1918 goto out;
1919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301921 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301923 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
1924 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301926 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1927 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
1928 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
1929 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
1930 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
1931 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
1932 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301934 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
1935 pScsiTmReply->ResponseCode)
1936 mptscsih_taskmgmt_response_code(ioc,
1937 pScsiTmReply->ResponseCode);
1938
1939 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
1940 retval = 0;
1941 goto out;
1942 }
1943
1944 retval = FAILED;
1945 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
1946 if (termination_count == 1)
1947 retval = 0;
1948 goto out;
1949 }
1950
1951 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1952 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1953 retval = 0;
1954
1955 out:
1956 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
1959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301960void
Moore, Eric9f63bb72006-01-16 18:53:26 -07001961mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1962{
1963 char *desc;
1964
1965 switch (response_code) {
1966 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1967 desc = "The task completed.";
1968 break;
1969 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1970 desc = "The IOC received an invalid frame status.";
1971 break;
1972 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1973 desc = "The task type is not supported.";
1974 break;
1975 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1976 desc = "The requested task failed.";
1977 break;
1978 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1979 desc = "The task completed successfully.";
1980 break;
1981 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1982 desc = "The LUN request is invalid.";
1983 break;
1984 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1985 desc = "The task is in the IOC queue and has not been sent to target.";
1986 break;
1987 default:
1988 desc = "unknown";
1989 break;
1990 }
1991 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
1992 ioc->name, response_code, desc);
1993}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301994EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07001995
1996/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997/**
1998 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
1999 * @ioc: Pointer to MPT_ADAPTER structure
2000 * @mf: Pointer to SCSI task mgmt request frame
2001 * @mr: Pointer to SCSI task mgmt reply frame
2002 *
2003 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2004 * of any SCSI task management request.
2005 * This routine is registered with the MPT (base) driver at driver
2006 * load/init time via the mpt_register() API call.
2007 *
2008 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002009 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002010int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302011mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2012 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302014 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2015 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302017 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302019 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002020 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002021
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302022 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2023 memcpy(ioc->taskmgmt_cmds.reply, mr,
2024 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002025 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302026 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2027 mpt_clear_taskmgmt_in_progress_flag(ioc);
2028 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2029 complete(&ioc->taskmgmt_cmds.done);
2030 return 1;
2031 }
2032 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033}
2034
2035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2036/*
2037 * This is anyones guess quite frankly.
2038 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002039int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2041 sector_t capacity, int geom[])
2042{
2043 int heads;
2044 int sectors;
2045 sector_t cylinders;
2046 ulong dummy;
2047
2048 heads = 64;
2049 sectors = 32;
2050
2051 dummy = heads * sectors;
2052 cylinders = capacity;
2053 sector_div(cylinders,dummy);
2054
2055 /*
2056 * Handle extended translation size for logical drives
2057 * > 1Gb
2058 */
2059 if ((ulong)capacity >= 0x200000) {
2060 heads = 255;
2061 sectors = 63;
2062 dummy = heads * sectors;
2063 cylinders = capacity;
2064 sector_div(cylinders,dummy);
2065 }
2066
2067 /* return result */
2068 geom[0] = heads;
2069 geom[1] = sectors;
2070 geom[2] = cylinders;
2071
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 return 0;
2073}
2074
Moore, Ericf44e5462006-03-14 09:14:21 -07002075/* Search IOC page 3 to determine if this is hidden physical disk
2076 *
2077 */
2078int
Eric Moore793955f2007-01-29 09:42:20 -07002079mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002080{
Eric Mooreb506ade2007-01-29 09:45:37 -07002081 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002082 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002083 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002084
Eric Moore793955f2007-01-29 09:42:20 -07002085 if (!ioc->raid_data.pIocPg3)
2086 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002087 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002088 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2089 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2090 rc = 1;
2091 goto out;
2092 }
2093 }
2094
Eric Mooreb506ade2007-01-29 09:45:37 -07002095 /*
2096 * Check inactive list for matching phys disks
2097 */
2098 if (list_empty(&ioc->raid_data.inactive_list))
2099 goto out;
2100
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002101 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002102 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2103 list) {
2104 if ((component_info->d.PhysDiskID == id) &&
2105 (component_info->d.PhysDiskBus == channel))
2106 rc = 1;
2107 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002108 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002109
Eric Moore793955f2007-01-29 09:42:20 -07002110 out:
2111 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002112}
2113EXPORT_SYMBOL(mptscsih_is_phys_disk);
2114
Eric Moore793955f2007-01-29 09:42:20 -07002115u8
2116mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002117{
Eric Mooreb506ade2007-01-29 09:45:37 -07002118 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002119 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002120 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002121
Eric Moore793955f2007-01-29 09:42:20 -07002122 if (!ioc->raid_data.pIocPg3)
2123 goto out;
2124 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2125 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2126 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2127 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2128 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002129 }
2130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Eric Mooreb506ade2007-01-29 09:45:37 -07002132 /*
2133 * Check inactive list for matching phys disks
2134 */
2135 if (list_empty(&ioc->raid_data.inactive_list))
2136 goto out;
2137
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002138 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002139 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2140 list) {
2141 if ((component_info->d.PhysDiskID == id) &&
2142 (component_info->d.PhysDiskBus == channel))
2143 rc = component_info->d.PhysDiskNum;
2144 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002145 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002146
Eric Moore793955f2007-01-29 09:42:20 -07002147 out:
2148 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002149}
Eric Moore793955f2007-01-29 09:42:20 -07002150EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002151
2152/*
2153 * OS entry point to allow for host driver to free allocated memory
2154 * Called if no device present or device being unloaded
2155 */
2156void
2157mptscsih_slave_destroy(struct scsi_device *sdev)
2158{
2159 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002160 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002161 VirtTarget *vtarget;
2162 VirtDevice *vdevice;
2163 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002165 starget = scsi_target(sdev);
2166 vtarget = starget->hostdata;
2167 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002169 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002170 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002171 mptscsih_synchronize_cache(hd, vdevice);
2172 kfree(vdevice);
2173 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174}
2175
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002176/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2177/*
2178 * mptscsih_change_queue_depth - This function will set a devices queue depth
2179 * @sdev: per scsi_device pointer
2180 * @qdepth: requested queue depth
2181 *
2182 * Adding support for new 'change_queue_depth' api.
2183*/
2184int
2185mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002187 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002188 VirtTarget *vtarget;
2189 struct scsi_target *starget;
2190 int max_depth;
2191 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002192 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002194 starget = scsi_target(sdev);
2195 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002196
Eric Mooree80b0022007-09-14 18:49:03 -06002197 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002198 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002200 else if (sdev->type == TYPE_DISK &&
2201 vtarget->minSyncFactor <= MPT_ULTRA160)
2202 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2203 else
2204 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 } else
2206 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2207
2208 if (qdepth > max_depth)
2209 qdepth = max_depth;
2210 if (qdepth == 1)
2211 tagged = 0;
2212 else
2213 tagged = MSG_SIMPLE_TAG;
2214
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002215 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2216 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217}
2218
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219/*
2220 * OS entry point to adjust the queue_depths on a per-device basis.
2221 * Called once per device the bus scan. Use it to force the queue_depth
2222 * member to 1 if a device does not support Q tags.
2223 * Return non-zero if fails.
2224 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002225int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002226mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002228 struct Scsi_Host *sh = sdev->host;
2229 VirtTarget *vtarget;
2230 VirtDevice *vdevice;
2231 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002232 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002233 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002235 starget = scsi_target(sdev);
2236 vtarget = starget->hostdata;
2237 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
Eric Mooree80b0022007-09-14 18:49:03 -06002239 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002240 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002241 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2242 if (ioc->bus_type == SPI)
2243 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002244 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002245 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002246 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
Eric Moore793955f2007-01-29 09:42:20 -07002248 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002249 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Eric Mooree80b0022007-09-14 18:49:03 -06002251 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002253 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
Eric Mooree80b0022007-09-14 18:49:03 -06002255 if (ioc->bus_type == SPI)
2256 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002257 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002258 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002259 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
Eric Mooree80b0022007-09-14 18:49:03 -06002261 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002263 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002264 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
2266 return 0;
2267}
2268
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2270/*
2271 * Private routines...
2272 */
2273
2274/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2275/* Utility function to copy sense data from the scsi_cmnd buffer
2276 * to the FC and SCSI target structures.
2277 *
2278 */
2279static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002280mptscsih_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 -07002281{
Eric Moorea69de502007-09-14 18:48:19 -06002282 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 SCSIIORequest_t *pReq;
2284 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002285 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
2287 /* Get target structure
2288 */
2289 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002290 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 if (sense_count) {
2293 u8 *sense_data;
2294 int req_index;
2295
2296 /* Copy the sense received into the scsi command block. */
2297 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002298 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2300
2301 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2302 */
Eric Mooree80b0022007-09-14 18:49:03 -06002303 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002304 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002307 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2309 ioc->events[idx].eventContext = ioc->eventContext;
2310
Dave Jones3d9780b2007-05-21 20:59:47 -04002311 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2312 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2313 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Dave Jones3d9780b2007-05-21 20:59:47 -04002315 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002318 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002319 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002320 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002321 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2322 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002323 MPT_TARGET_FLAGS_LED_ON;
2324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 }
2326 }
2327 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002328 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2329 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 }
2331}
2332
Eric Mooree8206382007-09-29 10:16:53 -06002333/**
2334 * mptscsih_get_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002335 * @ioc: Pointer to MPT_ADAPTER structure
2336 * @i: index into the array
2337 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002338 * retrieves scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002339 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002340 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002341 **/
2342static struct scsi_cmnd *
2343mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344{
Eric Mooree8206382007-09-29 10:16:53 -06002345 unsigned long flags;
2346 struct scsi_cmnd *scmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Eric Mooree8206382007-09-29 10:16:53 -06002348 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2349 scmd = ioc->ScsiLookup[i];
2350 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Eric Mooree8206382007-09-29 10:16:53 -06002352 return scmd;
2353}
2354
2355/**
2356 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002357 * @ioc: Pointer to MPT_ADAPTER structure
2358 * @i: index into the array
2359 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002360 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002361 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002362 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002363 **/
2364static struct scsi_cmnd *
2365mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2366{
2367 unsigned long flags;
2368 struct scsi_cmnd *scmd;
2369
2370 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2371 scmd = ioc->ScsiLookup[i];
2372 ioc->ScsiLookup[i] = NULL;
2373 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2374
2375 return scmd;
2376}
2377
2378/**
2379 * mptscsih_set_scsi_lookup
2380 *
2381 * writes a scmd entry into the ScsiLookup[] array list
2382 *
2383 * @ioc: Pointer to MPT_ADAPTER structure
2384 * @i: index into the array
2385 * @scmd: scsi_cmnd pointer
2386 *
2387 **/
2388static void
2389mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2390{
2391 unsigned long flags;
2392
2393 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2394 ioc->ScsiLookup[i] = scmd;
2395 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2396}
2397
2398/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002399 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002400 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002401 * @sc: scsi_cmnd pointer
2402 */
Eric Mooree8206382007-09-29 10:16:53 -06002403static int
2404SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2405{
2406 unsigned long flags;
2407 int i, index=-1;
2408
2409 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2410 for (i = 0; i < ioc->req_depth; i++) {
2411 if (ioc->ScsiLookup[i] == sc) {
2412 index = i;
2413 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 }
2415 }
2416
Eric Mooree8206382007-09-29 10:16:53 -06002417 out:
2418 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2419 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420}
2421
2422/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002423int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2425{
2426 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Eric Mooree7eae9f2007-09-29 10:15:59 -06002428 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302431 hd = shost_priv(ioc->sh);
2432 switch (reset_phase) {
2433 case MPT_IOC_SETUP_RESET:
2434 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2435 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302436 break;
2437 case MPT_IOC_PRE_RESET:
2438 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2439 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302440 mptscsih_flush_running_cmds(hd);
2441 break;
2442 case MPT_IOC_POST_RESET:
2443 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2444 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2445 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2446 ioc->internal_cmds.status |=
2447 MPT_MGMT_STATUS_DID_IOCRESET;
2448 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302450 break;
2451 default:
2452 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 return 1; /* currently means nothing really */
2455}
2456
2457/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002458int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2460{
2461 MPT_SCSI_HOST *hd;
2462 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2463
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302464 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2465 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2466 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002468 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06002469 ((hd = shost_priv(ioc->sh)) == NULL))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002470 return 1;
2471
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 switch (event) {
2473 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2474 /* FIXME! */
2475 break;
2476 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2477 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002478 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002479 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 break;
2481 case MPI_EVENT_LOGOUT: /* 09 */
2482 /* FIXME! */
2483 break;
2484
Michael Reed05e8ec12006-01-13 14:31:54 -06002485 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002486 break;
2487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 /*
2489 * CHECKME! Don't think we need to do
2490 * anything for these, but...
2491 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2493 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2494 /*
2495 * CHECKME! Falling thru...
2496 */
2497 break;
2498
2499 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002500 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 case MPI_EVENT_NONE: /* 00 */
2503 case MPI_EVENT_LOG_DATA: /* 01 */
2504 case MPI_EVENT_STATE_CHANGE: /* 02 */
2505 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2506 default:
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302507 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2508 ": Ignoring event (=%02Xh)\n",
2509 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 break;
2511 }
2512
2513 return 1; /* currently means nothing really */
2514}
2515
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2517/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 * Bus Scan and Domain Validation functionality ...
2519 */
2520
2521/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2522/*
2523 * mptscsih_scandv_complete - Scan and DV callback routine registered
2524 * to Fustion MPT (base) driver.
2525 *
2526 * @ioc: Pointer to MPT_ADAPTER structure
2527 * @mf: Pointer to original MPT request frame
2528 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2529 *
2530 * This routine is called from mpt.c::mpt_interrupt() at the completion
2531 * of any SCSI IO request.
2532 * This routine is registered with the Fusion MPT (base) driver at driver
2533 * load/init time via the mpt_register() API call.
2534 *
2535 * Returns 1 indicating alloc'd request frame ptr should be freed.
2536 *
2537 * Remark: Sets a completion code and (possibly) saves sense data
2538 * in the IOC member localReply structure.
2539 * Used ONLY for DV and other internal commands.
2540 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002541int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302542mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2543 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302546 SCSIIOReply_t *pReply;
2547 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302549 u8 *sense_data;
2550 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302552 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2553 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2554 if (!reply)
2555 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002556
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302557 pReply = (SCSIIOReply_t *) reply;
2558 pReq = (SCSIIORequest_t *) req;
2559 ioc->internal_cmds.completion_code =
2560 mptscsih_get_completion_code(ioc, req, reply);
2561 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2562 memcpy(ioc->internal_cmds.reply, reply,
2563 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2564 cmd = reply->u.hdr.Function;
2565 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2566 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2567 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2568 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2569 sense_data = ((u8 *)ioc->sense_buf_pool +
2570 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2571 sz = min_t(int, pReq->SenseBufferLength,
2572 MPT_SENSE_BUFFER_ALLOC);
2573 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302575 out:
2576 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2577 return 0;
2578 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2579 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 return 1;
2581}
2582
2583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2584/* mptscsih_timer_expired - Call back for timer process.
2585 * Used only for dv functionality.
2586 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2587 *
2588 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002589void
2590mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591{
2592 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002593 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
Eric Mooree80b0022007-09-14 18:49:03 -06002595 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
2597 if (hd->cmdPtr) {
2598 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2599
2600 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2601 /* Desire to issue a task management request here.
2602 * TM requests MUST be single threaded.
2603 * If old eh code and no TM current, issue request.
2604 * If new eh code, do nothing. Wait for OS cmd timeout
2605 * for bus reset.
2606 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 } else {
2608 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002609 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2610 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 }
2612 }
2613 } else {
2614 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002615 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 }
2617
2618 /* No more processing.
2619 * TM call will generate an interrupt for SCSI TM Management.
2620 * The FW will reply to all outstanding commands, callback will finish cleanup.
2621 * Hard reset clean-up will free all resources.
2622 */
Eric Mooree80b0022007-09-14 18:49:03 -06002623 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 return;
2626}
2627
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302628/**
2629 * mptscsih_get_completion_code -
2630 * @ioc: Pointer to MPT_ADAPTER structure
2631 * @reply:
2632 * @cmd:
2633 *
2634 **/
2635static int
2636mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2637 MPT_FRAME_HDR *reply)
2638{
2639 SCSIIOReply_t *pReply;
2640 MpiRaidActionReply_t *pr;
2641 u8 scsi_status;
2642 u16 status;
2643 int completion_code;
2644
2645 pReply = (SCSIIOReply_t *)reply;
2646 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2647 scsi_status = pReply->SCSIStatus;
2648
2649 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2650 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2651 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2652 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2653
2654 switch (status) {
2655
2656 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2657 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2658 break;
2659
2660 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2661 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2662 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2663 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2664 completion_code = MPT_SCANDV_DID_RESET;
2665 break;
2666
2667 case MPI_IOCSTATUS_BUSY:
2668 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2669 completion_code = MPT_SCANDV_BUSY;
2670 break;
2671
2672 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2673 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2674 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2675 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2676 completion_code = MPT_SCANDV_GOOD;
2677 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2678 pr = (MpiRaidActionReply_t *)reply;
2679 if (le16_to_cpu(pr->ActionStatus) ==
2680 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2681 completion_code = MPT_SCANDV_GOOD;
2682 else
2683 completion_code = MPT_SCANDV_SOME_ERROR;
2684 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2685 completion_code = MPT_SCANDV_SENSE;
2686 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2687 if (req->u.scsireq.CDB[0] == INQUIRY)
2688 completion_code = MPT_SCANDV_ISSUE_SENSE;
2689 else
2690 completion_code = MPT_SCANDV_DID_RESET;
2691 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2692 completion_code = MPT_SCANDV_DID_RESET;
2693 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2694 completion_code = MPT_SCANDV_DID_RESET;
2695 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2696 completion_code = MPT_SCANDV_BUSY;
2697 else
2698 completion_code = MPT_SCANDV_GOOD;
2699 break;
2700
2701 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2702 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2703 completion_code = MPT_SCANDV_DID_RESET;
2704 else
2705 completion_code = MPT_SCANDV_SOME_ERROR;
2706 break;
2707 default:
2708 completion_code = MPT_SCANDV_SOME_ERROR;
2709 break;
2710
2711 } /* switch(status) */
2712
2713 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2714 " completionCode set to %08xh\n", ioc->name, completion_code));
2715 return completion_code;
2716}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
2718/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2719/**
2720 * mptscsih_do_cmd - Do internal command.
2721 * @hd: MPT_SCSI_HOST pointer
2722 * @io: INTERNAL_CMD pointer.
2723 *
2724 * Issue the specified internally generated command and do command
2725 * specific cleanup. For bus scan / DV only.
2726 * NOTES: If command is Inquiry and status is good,
2727 * initialize a target structure, save the data
2728 *
2729 * Remark: Single threaded access only.
2730 *
2731 * Return:
2732 * < 0 if an illegal command or no resources
2733 *
2734 * 0 if good
2735 *
2736 * > 0 if command complete but some type of completion error.
2737 */
2738static int
2739mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2740{
2741 MPT_FRAME_HDR *mf;
2742 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302744 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 char cmdLen;
2746 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 +05302747 u8 cmd = io->cmd;
2748 MPT_ADAPTER *ioc = hd->ioc;
2749 int ret = 0;
2750 unsigned long timeleft;
2751 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302753 /* don't send internal command during diag reset */
2754 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2755 if (ioc->ioc_reset_in_progress) {
2756 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2757 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2758 "%s: busy with host reset\n", ioc->name, __func__));
2759 return MPT_SCANDV_BUSY;
2760 }
2761 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2762
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302763 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764
2765 /* Set command specific information
2766 */
2767 switch (cmd) {
2768 case INQUIRY:
2769 cmdLen = 6;
2770 dir = MPI_SCSIIO_CONTROL_READ;
2771 CDB[0] = cmd;
2772 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302773 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 break;
2775
2776 case TEST_UNIT_READY:
2777 cmdLen = 6;
2778 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302779 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 break;
2781
2782 case START_STOP:
2783 cmdLen = 6;
2784 dir = MPI_SCSIIO_CONTROL_READ;
2785 CDB[0] = cmd;
2786 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302787 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 break;
2789
2790 case REQUEST_SENSE:
2791 cmdLen = 6;
2792 CDB[0] = cmd;
2793 CDB[4] = io->size;
2794 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302795 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 break;
2797
2798 case READ_BUFFER:
2799 cmdLen = 10;
2800 dir = MPI_SCSIIO_CONTROL_READ;
2801 CDB[0] = cmd;
2802 if (io->flags & MPT_ICFLAG_ECHO) {
2803 CDB[1] = 0x0A;
2804 } else {
2805 CDB[1] = 0x02;
2806 }
2807
2808 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2809 CDB[1] |= 0x01;
2810 }
2811 CDB[6] = (io->size >> 16) & 0xFF;
2812 CDB[7] = (io->size >> 8) & 0xFF;
2813 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302814 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 break;
2816
2817 case WRITE_BUFFER:
2818 cmdLen = 10;
2819 dir = MPI_SCSIIO_CONTROL_WRITE;
2820 CDB[0] = cmd;
2821 if (io->flags & MPT_ICFLAG_ECHO) {
2822 CDB[1] = 0x0A;
2823 } else {
2824 CDB[1] = 0x02;
2825 }
2826 CDB[6] = (io->size >> 16) & 0xFF;
2827 CDB[7] = (io->size >> 8) & 0xFF;
2828 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302829 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 break;
2831
2832 case RESERVE:
2833 cmdLen = 6;
2834 dir = MPI_SCSIIO_CONTROL_READ;
2835 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302836 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 break;
2838
2839 case RELEASE:
2840 cmdLen = 6;
2841 dir = MPI_SCSIIO_CONTROL_READ;
2842 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302843 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 break;
2845
2846 case SYNCHRONIZE_CACHE:
2847 cmdLen = 10;
2848 dir = MPI_SCSIIO_CONTROL_READ;
2849 CDB[0] = cmd;
2850// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302851 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 break;
2853
2854 default:
2855 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302856 ret = -EFAULT;
2857 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 }
2859
2860 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302861 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 */
Eric Mooree80b0022007-09-14 18:49:03 -06002863 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302864 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2865 ioc->name, __func__));
2866 ret = MPT_SCANDV_BUSY;
2867 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 }
2869
2870 pScsiReq = (SCSIIORequest_t *) mf;
2871
2872 /* Get the request index */
2873 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2874 ADD_INDEX_LOG(my_idx); /* for debug */
2875
2876 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2877 pScsiReq->TargetID = io->physDiskNum;
2878 pScsiReq->Bus = 0;
2879 pScsiReq->ChainOffset = 0;
2880 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2881 } else {
2882 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002883 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 pScsiReq->ChainOffset = 0;
2885 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2886 }
2887
2888 pScsiReq->CDBLength = cmdLen;
2889 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2890
2891 pScsiReq->Reserved = 0;
2892
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302893 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 /* MsgContext set in mpt_get_msg_fram call */
2895
Eric Moore793955f2007-01-29 09:42:20 -07002896 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897
2898 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2899 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2900 else
2901 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2902
2903 if (cmd == REQUEST_SENSE) {
2904 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302905 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2906 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 }
2908
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302909 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 pScsiReq->CDB[ii] = CDB[ii];
2911
2912 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06002913 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
2915
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302916 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2917 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
2918 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302920 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302921 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302922 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
2923 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302924 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302925 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302927 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06002928 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302929 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
2930 timeout*HZ);
2931 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2932 ret = MPT_SCANDV_DID_RESET;
2933 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2934 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
2935 cmd));
2936 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2937 mpt_free_msg_frame(ioc, mf);
2938 goto out;
2939 }
2940 if (!timeleft) {
2941 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
2942 ioc->name, __func__);
2943 mpt_HardResetHandler(ioc, CAN_SLEEP);
2944 mpt_free_msg_frame(ioc, mf);
2945 }
2946 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 }
2948
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302949 ret = ioc->internal_cmds.completion_code;
2950 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
2951 ioc->name, __func__, ret));
2952
2953 out:
2954 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
2955 mutex_unlock(&ioc->internal_cmds.mutex);
2956 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957}
2958
2959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2960/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002961 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
2962 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002963 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002964 *
2965 * Uses the ISR, but with special processing.
2966 * MUST be single-threaded.
2967 *
2968 */
2969static void
2970mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
2971{
2972 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Eric Moorecc78d302007-06-15 17:27:21 -06002974 /* Ignore hidden raid components, this is handled when the command
2975 * is sent to the volume
2976 */
2977 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
2978 return;
2979
2980 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
2981 !vdevice->configured_lun)
2982 return;
2983
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 /* Following parameters will not change
2985 * in this routine.
2986 */
2987 iocmd.cmd = SYNCHRONIZE_CACHE;
2988 iocmd.flags = 0;
2989 iocmd.physDiskNum = -1;
2990 iocmd.data = NULL;
2991 iocmd.data_dma = -1;
2992 iocmd.size = 0;
2993 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07002994 iocmd.channel = vdevice->vtarget->channel;
2995 iocmd.id = vdevice->vtarget->id;
2996 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
Eric Moorecc78d302007-06-15 17:27:21 -06002998 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999}
3000
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303001static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003002mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3003 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303004{
Tony Jonesee959b02008-02-22 00:13:36 +01003005 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003006 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303007 MPT_ADAPTER *ioc = hd->ioc;
3008
3009 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3010 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3011 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3012 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3013 ioc->facts.FWVersion.Word & 0x000000FF);
3014}
Tony Jonesee959b02008-02-22 00:13:36 +01003015static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303016
3017static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003018mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3019 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303020{
Tony Jonesee959b02008-02-22 00:13:36 +01003021 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003022 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303023 MPT_ADAPTER *ioc = hd->ioc;
3024
3025 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3026 (ioc->biosVersion & 0xFF000000) >> 24,
3027 (ioc->biosVersion & 0x00FF0000) >> 16,
3028 (ioc->biosVersion & 0x0000FF00) >> 8,
3029 ioc->biosVersion & 0x000000FF);
3030}
Tony Jonesee959b02008-02-22 00:13:36 +01003031static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303032
3033static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003034mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3035 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303036{
Tony Jonesee959b02008-02-22 00:13:36 +01003037 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003038 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303039 MPT_ADAPTER *ioc = hd->ioc;
3040
3041 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3042}
Tony Jonesee959b02008-02-22 00:13:36 +01003043static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303044
3045static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003046mptscsih_version_product_show(struct device *dev,
3047 struct device_attribute *attr,
3048char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303049{
Tony Jonesee959b02008-02-22 00:13:36 +01003050 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003051 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303052 MPT_ADAPTER *ioc = hd->ioc;
3053
3054 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3055}
Tony Jonesee959b02008-02-22 00:13:36 +01003056static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303057 mptscsih_version_product_show, NULL);
3058
3059static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003060mptscsih_version_nvdata_persistent_show(struct device *dev,
3061 struct device_attribute *attr,
3062 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303063{
Tony Jonesee959b02008-02-22 00:13:36 +01003064 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003065 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303066 MPT_ADAPTER *ioc = hd->ioc;
3067
3068 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3069 ioc->nvdata_version_persistent);
3070}
Tony Jonesee959b02008-02-22 00:13:36 +01003071static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303072 mptscsih_version_nvdata_persistent_show, NULL);
3073
3074static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003075mptscsih_version_nvdata_default_show(struct device *dev,
3076 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303077{
Tony Jonesee959b02008-02-22 00:13:36 +01003078 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003079 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303080 MPT_ADAPTER *ioc = hd->ioc;
3081
3082 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3083}
Tony Jonesee959b02008-02-22 00:13:36 +01003084static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303085 mptscsih_version_nvdata_default_show, NULL);
3086
3087static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003088mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3089 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303090{
Tony Jonesee959b02008-02-22 00:13:36 +01003091 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003092 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303093 MPT_ADAPTER *ioc = hd->ioc;
3094
3095 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3096}
Tony Jonesee959b02008-02-22 00:13:36 +01003097static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303098
3099static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003100mptscsih_board_assembly_show(struct device *dev,
3101 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303102{
Tony Jonesee959b02008-02-22 00:13:36 +01003103 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003104 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303105 MPT_ADAPTER *ioc = hd->ioc;
3106
3107 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3108}
Tony Jonesee959b02008-02-22 00:13:36 +01003109static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303110 mptscsih_board_assembly_show, NULL);
3111
3112static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003113mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3114 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303115{
Tony Jonesee959b02008-02-22 00:13:36 +01003116 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003117 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303118 MPT_ADAPTER *ioc = hd->ioc;
3119
3120 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3121}
Tony Jonesee959b02008-02-22 00:13:36 +01003122static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303123 mptscsih_board_tracer_show, NULL);
3124
3125static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003126mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3127 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303128{
Tony Jonesee959b02008-02-22 00:13:36 +01003129 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003130 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303131 MPT_ADAPTER *ioc = hd->ioc;
3132
3133 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3134}
Tony Jonesee959b02008-02-22 00:13:36 +01003135static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303136 mptscsih_io_delay_show, NULL);
3137
3138static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003139mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3140 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303141{
Tony Jonesee959b02008-02-22 00:13:36 +01003142 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003143 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303144 MPT_ADAPTER *ioc = hd->ioc;
3145
3146 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3147}
Tony Jonesee959b02008-02-22 00:13:36 +01003148static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303149 mptscsih_device_delay_show, NULL);
3150
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303151static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003152mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3153 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303154{
Tony Jonesee959b02008-02-22 00:13:36 +01003155 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003156 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303157 MPT_ADAPTER *ioc = hd->ioc;
3158
3159 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3160}
3161static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003162mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3163 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303164{
Tony Jonesee959b02008-02-22 00:13:36 +01003165 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003166 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303167 MPT_ADAPTER *ioc = hd->ioc;
3168 int val = 0;
3169
3170 if (sscanf(buf, "%x", &val) != 1)
3171 return -EINVAL;
3172
3173 ioc->debug_level = val;
3174 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3175 ioc->name, ioc->debug_level);
3176 return strlen(buf);
3177}
Tony Jonesee959b02008-02-22 00:13:36 +01003178static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3179 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303180
Tony Jonesee959b02008-02-22 00:13:36 +01003181struct device_attribute *mptscsih_host_attrs[] = {
3182 &dev_attr_version_fw,
3183 &dev_attr_version_bios,
3184 &dev_attr_version_mpi,
3185 &dev_attr_version_product,
3186 &dev_attr_version_nvdata_persistent,
3187 &dev_attr_version_nvdata_default,
3188 &dev_attr_board_name,
3189 &dev_attr_board_assembly,
3190 &dev_attr_board_tracer,
3191 &dev_attr_io_delay,
3192 &dev_attr_device_delay,
3193 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303194 NULL,
3195};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303196
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303197EXPORT_SYMBOL(mptscsih_host_attrs);
3198
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003199EXPORT_SYMBOL(mptscsih_remove);
3200EXPORT_SYMBOL(mptscsih_shutdown);
3201#ifdef CONFIG_PM
3202EXPORT_SYMBOL(mptscsih_suspend);
3203EXPORT_SYMBOL(mptscsih_resume);
3204#endif
3205EXPORT_SYMBOL(mptscsih_proc_info);
3206EXPORT_SYMBOL(mptscsih_info);
3207EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003208EXPORT_SYMBOL(mptscsih_slave_destroy);
3209EXPORT_SYMBOL(mptscsih_slave_configure);
3210EXPORT_SYMBOL(mptscsih_abort);
3211EXPORT_SYMBOL(mptscsih_dev_reset);
3212EXPORT_SYMBOL(mptscsih_bus_reset);
3213EXPORT_SYMBOL(mptscsih_host_reset);
3214EXPORT_SYMBOL(mptscsih_bios_param);
3215EXPORT_SYMBOL(mptscsih_io_done);
3216EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3217EXPORT_SYMBOL(mptscsih_scandv_complete);
3218EXPORT_SYMBOL(mptscsih_event_process);
3219EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003220EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003221EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/