blob: 6424dcbd59084aa5b76dd77a246cd5d5a13eb2d1 [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_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
84static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
85static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040086int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040088int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
91 SCSIIORequest_t *pReq, int req_idx);
92static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040093static 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 -070094
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +053095int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
96 int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040098int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
99int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530101void
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530102mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530103static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
104 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400105int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700107static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530109static int
110mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
111 SCSITaskMgmtReply_t *pScsiTmReply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400112void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700113void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400115int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
116int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117#endif
118
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900119#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * mptscsih_getFreeChainBuffer - Function to get a free chain
125 * from the MPT_SCSI_HOST FreeChainQ.
126 * @ioc: Pointer to MPT_ADAPTER structure
127 * @req_idx: Index of the SCSI IO request frame. (output)
128 *
129 * return SUCCESS or FAILED
130 */
131static inline int
132mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
133{
134 MPT_FRAME_HDR *chainBuf;
135 unsigned long flags;
136 int rc;
137 int chain_idx;
138
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530139 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600140 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 spin_lock_irqsave(&ioc->FreeQlock, flags);
142 if (!list_empty(&ioc->FreeChainQ)) {
143 int offset;
144
145 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
146 u.frame.linkage.list);
147 list_del(&chainBuf->u.frame.linkage.list);
148 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
149 chain_idx = offset / ioc->req_sz;
150 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600151 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
152 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
153 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 } else {
155 rc = FAILED;
156 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600157 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
158 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
160 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
161
162 *retIndex = chain_idx;
163 return rc;
164} /* mptscsih_getFreeChainBuffer() */
165
166/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
167/*
168 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
169 * SCSIIORequest_t Message Frame.
170 * @ioc: Pointer to MPT_ADAPTER structure
171 * @SCpnt: Pointer to scsi_cmnd structure
172 * @pReq: Pointer to SCSIIORequest_t structure
173 *
174 * Returns ...
175 */
176static int
177mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
178 SCSIIORequest_t *pReq, int req_idx)
179{
180 char *psge;
181 char *chainSge;
182 struct scatterlist *sg;
183 int frm_sz;
184 int sges_left, sg_done;
185 int chain_idx = MPT_HOST_NO_CHAIN;
186 int sgeOffset;
187 int numSgeSlots, numSgeThisFrame;
188 u32 sgflags, sgdir, thisxfer = 0;
189 int chain_dma_off = 0;
190 int newIndex;
191 int ii;
192 dma_addr_t v2;
193 u32 RequestNB;
194
195 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
196 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
197 sgdir = MPT_TRANSFER_HOST_TO_IOC;
198 } else {
199 sgdir = MPT_TRANSFER_IOC_TO_HOST;
200 }
201
202 psge = (char *) &pReq->SGL;
203 frm_sz = ioc->req_sz;
204
205 /* Map the data portion, if any.
206 * sges_left = 0 if no data transfer.
207 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900208 sges_left = scsi_dma_map(SCpnt);
209 if (sges_left < 0)
210 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
212 /* Handle the SG case.
213 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900214 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 sg_done = 0;
216 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
217 chainSge = NULL;
218
219 /* Prior to entering this loop - the following must be set
220 * current MF: sgeOffset (bytes)
221 * chainSge (Null if original MF is not a chain buffer)
222 * sg_done (num SGE done for this MF)
223 */
224
225nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530226 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
228
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530229 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 /* Get first (num - 1) SG elements
232 * Skip any SG entries with a length of 0
233 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
234 */
235 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
236 thisxfer = sg_dma_len(sg);
237 if (thisxfer == 0) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530238 /* Get next SG element from the OS */
239 sg = sg_next(sg);
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
Kashyap, Desai2f187862009-05-29 16:52:37 +0530247 /* Get next SG element from the OS */
248 sg = sg_next(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530249 psge += ioc->SGE_size;
250 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 sg_done++;
252 }
253
254 if (numSgeThisFrame == sges_left) {
255 /* Add last element, end of buffer and end of list flags.
256 */
257 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
258 MPT_SGE_FLAGS_END_OF_BUFFER |
259 MPT_SGE_FLAGS_END_OF_LIST;
260
261 /* Add last SGE and set termination flags.
262 * Note: Last SGE may have a length of 0 - which should be ok.
263 */
264 thisxfer = sg_dma_len(sg);
265
266 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530267 ioc->add_sge(psge, sgflags | thisxfer, v2);
268 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sg_done++;
270
271 if (chainSge) {
272 /* The current buffer is a chain buffer,
273 * but there is not another one.
274 * Update the chain element
275 * Offset and Length fields.
276 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530277 ioc->add_chain((char *)chainSge, 0, sgeOffset,
278 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 } else {
280 /* The current buffer is the original MF
281 * and there is no Chain buffer.
282 */
283 pReq->ChainOffset = 0;
284 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530285 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
287 ioc->RequestNB[req_idx] = RequestNB;
288 }
289 } else {
290 /* At least one chain buffer is needed.
291 * Complete the first MF
292 * - last SGE element, set the LastElement bit
293 * - set ChainOffset (words) for orig MF
294 * (OR finish previous MF chain buffer)
295 * - update MFStructPtr ChainIndex
296 * - Populate chain element
297 * Also
298 * Loop until done.
299 */
300
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530301 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 ioc->name, sg_done));
303
304 /* Set LAST_ELEMENT flag for last non-chain element
305 * in the buffer. Since psge points at the NEXT
306 * SGE element, go back one SGE element, update the flags
307 * and reset the pointer. (Note: sgflags & thisxfer are already
308 * set properly).
309 */
310 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530311 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 sgflags = le32_to_cpu(*ptmp);
313 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
314 *ptmp = cpu_to_le32(sgflags);
315 }
316
317 if (chainSge) {
318 /* The current buffer is a chain buffer.
319 * chainSge points to the previous Chain Element.
320 * Update its chain element Offset and Length (must
321 * include chain element size) fields.
322 * Old chain element is now complete.
323 */
324 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530325 sgeOffset += ioc->SGE_size;
326 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
327 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 } else {
329 /* The original MF buffer requires a chain buffer -
330 * set the offset.
331 * Last element in this MF is a chain element.
332 */
333 pReq->ChainOffset = (u8) (sgeOffset >> 2);
334 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530335 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 -0700336 ioc->RequestNB[req_idx] = RequestNB;
337 }
338
339 sges_left -= sg_done;
340
341
342 /* NOTE: psge points to the beginning of the chain element
343 * in current buffer. Get a chain buffer.
344 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200345 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530346 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200347 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
348 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 /* Update the tracking arrays.
353 * If chainSge == NULL, update ReqToChain, else ChainToChain
354 */
355 if (chainSge) {
356 ioc->ChainToChain[chain_idx] = newIndex;
357 } else {
358 ioc->ReqToChain[req_idx] = newIndex;
359 }
360 chain_idx = newIndex;
361 chain_dma_off = ioc->req_sz * chain_idx;
362
363 /* Populate the chainSGE for the current buffer.
364 * - Set chain buffer pointer to psge and fill
365 * out the Address and Flags fields.
366 */
367 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600368 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
369 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 /* Start the SGE for the next buffer
372 */
373 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
374 sgeOffset = 0;
375 sg_done = 0;
376
Eric Moore29dd3602007-09-14 18:46:51 -0600377 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
378 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* Start the SGE for the next buffer
381 */
382
383 goto nextSGEset;
384 }
385
386 return SUCCESS;
387} /* mptscsih_AddSGE() */
388
Eric Moore786899b2006-07-11 17:22:22 -0600389static void
390mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
391 U32 SlotStatus)
392{
393 MPT_FRAME_HDR *mf;
394 SEPRequest_t *SEPMsg;
395
Eric Moorecc78d302007-06-15 17:27:21 -0600396 if (ioc->bus_type != SAS)
397 return;
398
399 /* Not supported for hidden raid components
400 */
401 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600402 return;
403
404 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530405 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700406 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600407 return;
408 }
409
410 SEPMsg = (SEPRequest_t *)mf;
411 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700412 SEPMsg->Bus = vtarget->channel;
413 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600414 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
415 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530416 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700417 "Sending SEP cmd=%x channel=%d id=%d\n",
418 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600419 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
420}
421
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530422#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700423/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530424 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700425 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700426 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530427 * @pScsiReply: Pointer to MPT reply frame
428 *
429 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700430 *
431 * Refer to lsi/mpi.h.
432 **/
433static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530434mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700435{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530436 char *desc = NULL;
437 char *desc1 = NULL;
438 u16 ioc_status;
439 u8 skey, asc, ascq;
440
441 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700442
443 switch (ioc_status) {
444
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530445 case MPI_IOCSTATUS_SUCCESS:
446 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700447 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530448 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
449 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700450 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530451 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
452 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700453 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530454 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
455 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700456 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530457 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
458 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700459 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530460 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
461 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700462 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530463 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
464 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700465 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530466 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
467 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700468 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530469 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
470 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700471 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530472 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
473 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700474 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530475 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
476 desc = "task management failed";
477 break;
478 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
479 desc = "IOC terminated";
480 break;
481 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
482 desc = "ext terminated";
483 break;
484 default:
485 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700486 break;
487 }
488
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530489 switch (pScsiReply->SCSIStatus)
490 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700491
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530492 case MPI_SCSI_STATUS_SUCCESS:
493 desc1 = "success";
494 break;
495 case MPI_SCSI_STATUS_CHECK_CONDITION:
496 desc1 = "check condition";
497 break;
498 case MPI_SCSI_STATUS_CONDITION_MET:
499 desc1 = "condition met";
500 break;
501 case MPI_SCSI_STATUS_BUSY:
502 desc1 = "busy";
503 break;
504 case MPI_SCSI_STATUS_INTERMEDIATE:
505 desc1 = "intermediate";
506 break;
507 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
508 desc1 = "intermediate condmet";
509 break;
510 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
511 desc1 = "reservation conflict";
512 break;
513 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
514 desc1 = "command terminated";
515 break;
516 case MPI_SCSI_STATUS_TASK_SET_FULL:
517 desc1 = "task set full";
518 break;
519 case MPI_SCSI_STATUS_ACA_ACTIVE:
520 desc1 = "aca active";
521 break;
522 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
523 desc1 = "fcpext device logged out";
524 break;
525 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
526 desc1 = "fcpext no link";
527 break;
528 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
529 desc1 = "fcpext unassigned";
530 break;
531 default:
532 desc1 = "";
533 break;
534 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700535
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530536 scsi_print_command(sc);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530537 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
538 ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
Eric Moore29dd3602007-09-14 18:46:51 -0600539 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
540 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
541 scsi_get_resid(sc));
542 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
543 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530544 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530545
Eric Moore29dd3602007-09-14 18:46:51 -0600546 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530547 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600548 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530549 pScsiReply->SCSIState);
550
551 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
552 skey = sc->sense_buffer[2] & 0x0F;
553 asc = sc->sense_buffer[12];
554 ascq = sc->sense_buffer[13];
555
Eric Moore29dd3602007-09-14 18:46:51 -0600556 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
557 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530558 }
559
560 /*
561 * Look for + dump FCP ResponseInfo[]!
562 */
563 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
564 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600565 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
566 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700567}
568#endif
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
571/*
572 * mptscsih_io_done - Main SCSI IO callback routine registered to
573 * Fusion MPT (base) driver
574 * @ioc: Pointer to MPT_ADAPTER structure
575 * @mf: Pointer to original MPT request frame
576 * @r: Pointer to MPT reply frame (NULL if TurboReply)
577 *
578 * This routine is called from mpt.c::mpt_interrupt() at the completion
579 * of any SCSI IO request.
580 * This routine is registered with the Fusion MPT (base) driver at driver
581 * load/init time via the mpt_register() API call.
582 *
583 * Returns 1 indicating alloc'd request frame ptr should be freed.
584 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400585int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
587{
588 struct scsi_cmnd *sc;
589 MPT_SCSI_HOST *hd;
590 SCSIIORequest_t *pScsiReq;
591 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700592 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600593 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600594 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Eric Mooree7eae9f2007-09-29 10:15:59 -0600596 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700598 req_idx_MR = (mr != NULL) ?
599 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
Kashyap, Desai2f187862009-05-29 16:52:37 +0530600
601 /* Special case, where already freed message frame is received from
602 * Firmware. It happens with Resetting IOC.
603 * Return immediately. Do not care
604 */
Moore, Eric2254c862006-01-17 17:06:29 -0700605 if ((req_idx != req_idx_MR) ||
Kashyap, Desai2f187862009-05-29 16:52:37 +0530606 (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
Moore, Eric2254c862006-01-17 17:06:29 -0700607 return 0;
Moore, Eric2254c862006-01-17 17:06:29 -0700608
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 /* Linux handles an unsolicited DID_RESET better
755 * than an unsolicited DID_ABORT.
756 */
757 sc->result = DID_RESET << 16;
758
Kashyap, Desai2f187862009-05-29 16:52:37 +0530759 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
760 if (ioc->bus_type == FC)
761 sc->result = DID_ERROR << 16;
762 else
763 sc->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 break;
765
766 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900767 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600768 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
769 sc->result=DID_SOFT_ERROR << 16;
770 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600772 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700773 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600774 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
778 /*
779 * Do upfront check for valid SenseData and give it
780 * precedence!
781 */
782 sc->result = (DID_OK << 16) | scsi_status;
783 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
784 /* Have already saved the status and sense data
785 */
786 ;
787 } else {
788 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600789 if (scsi_status == SAM_STAT_BUSY)
790 sc->result = SAM_STAT_BUSY;
791 else
792 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
795 /* What to do?
796 */
797 sc->result = DID_SOFT_ERROR << 16;
798 }
799 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
800 /* Not real sure here either... */
801 sc->result = DID_RESET << 16;
802 }
803 }
804
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530805
Eric Moore29dd3602007-09-14 18:46:51 -0600806 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
807 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
808 ioc->name, sc->underflow));
809 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
810 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 /* Report Queue Full
813 */
814 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
815 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 break;
818
Moore, Eric7e551472006-01-16 18:53:21 -0700819 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900820 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
822 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600823 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (scsi_state == 0) {
825 ;
826 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
827 /*
828 * If running against circa 200003dd 909 MPT f/w,
829 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
830 * (QUEUE_FULL) returned from device! --> get 0x0000?128
831 * and with SenseBytes set to 0.
832 */
833 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
834 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
835
836 }
837 else if (scsi_state &
838 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
839 ) {
840 /*
841 * What to do?
842 */
843 sc->result = DID_SOFT_ERROR << 16;
844 }
845 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
846 /* Not real sure here either... */
847 sc->result = DID_RESET << 16;
848 }
849 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
850 /* Device Inq. data indicates that it supports
851 * QTags, but rejects QTag messages.
852 * This command completed OK.
853 *
854 * Not real sure here either so do nothing... */
855 }
856
857 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
858 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
859
860 /* Add handling of:
861 * Reservation Conflict, Busy,
862 * Command Terminated, CHECK
863 */
864 break;
865
866 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
867 sc->result = DID_SOFT_ERROR << 16;
868 break;
869
870 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
871 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
872 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
873 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
874 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
875 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
876 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
878 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
879 default:
880 /*
881 * What to do?
882 */
883 sc->result = DID_SOFT_ERROR << 16;
884 break;
885
886 } /* switch(status) */
887
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530888#ifdef CONFIG_FUSION_LOGGING
889 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
890 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700891#endif
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 } /* end of address reply case */
894
895 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900896 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 sc->scsi_done(sc); /* Issue the command callback */
899
900 /* Free Chain buffers */
901 mptscsih_freeChainBuffers(ioc, req_idx);
902 return 1;
903}
904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905/*
906 * mptscsih_flush_running_cmds - For each command found, search
907 * Scsi_Host instance taskQ and reply to OS.
908 * Called only if recovering from a FW reload.
909 * @hd: Pointer to a SCSI HOST structure
910 *
911 * Returns: None.
912 *
913 * Must be called while new I/Os are being queued.
914 */
915static void
916mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
917{
918 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600919 struct scsi_cmnd *sc;
920 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 int ii;
Eric Mooree8206382007-09-29 10:16:53 -0600922 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Eric Mooree8206382007-09-29 10:16:53 -0600924 for (ii= 0; ii < ioc->req_depth; ii++) {
925 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
926 if (!sc)
927 continue;
928 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
929 if (!mf)
930 continue;
931 channel = mf->Bus;
932 id = mf->TargetID;
933 mptscsih_freeChainBuffers(ioc, ii);
934 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
935 if ((unsigned char *)mf != sc->host_scribble)
936 continue;
937 scsi_dma_unmap(sc);
938 sc->result = DID_RESET << 16;
939 sc->host_scribble = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +0530940 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
941 "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
942 "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
Eric Mooree8206382007-09-29 10:16:53 -0600943 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
947/*
948 * mptscsih_search_running_cmds - Delete any commands associated
949 * with the specified target and lun. Function called only
950 * when a lun is disable by mid-layer.
951 * Do NOT access the referenced scsi_cmnd structure or
952 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600953 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700954 * @hd: Pointer to a SCSI HOST structure
955 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 *
957 * Returns: None.
958 *
959 * Called from slave_destroy.
960 */
961static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700962mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
964 SCSIIORequest_t *mf = NULL;
965 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600966 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700967 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -0600968 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600969 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Eric Mooree8206382007-09-29 10:16:53 -0600971 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
972 for (ii = 0; ii < ioc->req_depth; ii++) {
973 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Eric Mooree80b0022007-09-14 18:49:03 -0600975 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600976 if (mf == NULL)
977 continue;
Eric Moorecc78d302007-06-15 17:27:21 -0600978 /* If the device is a hidden raid component, then its
979 * expected that the mf->function will be RAID_SCSI_IO
980 */
981 if (vdevice->vtarget->tflags &
982 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
983 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
984 continue;
985
Eric Moore793955f2007-01-29 09:42:20 -0700986 int_to_scsilun(vdevice->lun, &lun);
987 if ((mf->Bus != vdevice->vtarget->channel) ||
988 (mf->TargetID != vdevice->vtarget->id) ||
989 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 continue;
991
Eric Moore3dc0b032006-07-11 17:32:33 -0600992 if ((unsigned char *)mf != sc->host_scribble)
993 continue;
Eric Mooree8206382007-09-29 10:16:53 -0600994 ioc->ScsiLookup[ii] = NULL;
995 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
996 mptscsih_freeChainBuffers(ioc, ii);
997 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900998 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600999 sc->host_scribble = NULL;
1000 sc->result = DID_NO_CONNECT << 16;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301001 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
1002 MYIOC_s_FMT "completing cmds: fw_channel %d, "
1003 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
1004 vdevice->vtarget->channel, vdevice->vtarget->id,
1005 sc, mf, ii));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001006 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001007 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
1009 }
Eric Mooree8206382007-09-29 10:16:53 -06001010 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return;
1012}
1013
1014/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1017/*
1018 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1019 * from a SCSI target device.
1020 * @sc: Pointer to scsi_cmnd structure
1021 * @pScsiReply: Pointer to SCSIIOReply_t
1022 * @pScsiReq: Pointer to original SCSI request
1023 *
1024 * This routine periodically reports QUEUE_FULL status returned from a
1025 * SCSI target device. It reports this to the console via kernel
1026 * printk() API call, not more than once every 10 seconds.
1027 */
1028static void
1029mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1030{
1031 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001033 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001035 if (sc->device == NULL)
1036 return;
1037 if (sc->device->host == NULL)
1038 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001039 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001040 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001041 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001042 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001043 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1044 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001045 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047}
1048
1049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1050/*
1051 * mptscsih_remove - Removed scsi devices
1052 * @pdev: Pointer to pci_dev structure
1053 *
1054 *
1055 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001056void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057mptscsih_remove(struct pci_dev *pdev)
1058{
1059 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1060 struct Scsi_Host *host = ioc->sh;
1061 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001062 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001064 if(!host) {
1065 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069 scsi_remove_host(host);
1070
Eric Mooree7eae9f2007-09-29 10:15:59 -06001071 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001072 return;
1073
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001074 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001076 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Eric Mooree8206382007-09-29 10:16:53 -06001078 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001079 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001080 kfree(ioc->ScsiLookup);
1081 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083
Eric Mooree80b0022007-09-14 18:49:03 -06001084 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001085 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001086 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001087
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001088 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001089
1090 /* NULL the Scsi_Host pointer
1091 */
Eric Mooree80b0022007-09-14 18:49:03 -06001092 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001093
1094 scsi_host_put(host);
1095
1096 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1101/*
1102 * mptscsih_shutdown - reboot notifier
1103 *
1104 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001105void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001106mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
1110#ifdef CONFIG_PM
1111/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1112/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001113 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 *
1115 *
1116 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001117int
Pavel Machek8d189f72005-04-16 15:25:28 -07001118mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301120 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1121
1122 scsi_block_requests(ioc->sh);
1123 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001124 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001125 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126}
1127
1128/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1129/*
1130 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1131 *
1132 *
1133 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001134int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135mptscsih_resume(struct pci_dev *pdev)
1136{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301137 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1138 int rc;
1139
1140 rc = mpt_resume(pdev);
1141 scsi_unblock_requests(ioc->sh);
1142 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143}
1144
1145#endif
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1148/**
1149 * mptscsih_info - Return information about MPT adapter
1150 * @SChost: Pointer to Scsi_Host structure
1151 *
1152 * (linux scsi_host_template.info routine)
1153 *
1154 * Returns pointer to buffer where information was written.
1155 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001156const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157mptscsih_info(struct Scsi_Host *SChost)
1158{
1159 MPT_SCSI_HOST *h;
1160 int size = 0;
1161
Eric Mooree7eae9f2007-09-29 10:15:59 -06001162 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001165 if (h->info_kbuf == NULL)
1166 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1167 return h->info_kbuf;
1168 h->info_kbuf[0] = '\0';
1169
1170 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1171 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001174 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175}
1176
1177struct info_str {
1178 char *buffer;
1179 int length;
1180 int offset;
1181 int pos;
1182};
1183
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001184static void
1185mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186{
1187 if (info->pos + len > info->length)
1188 len = info->length - info->pos;
1189
1190 if (info->pos + len < info->offset) {
1191 info->pos += len;
1192 return;
1193 }
1194
1195 if (info->pos < info->offset) {
1196 data += (info->offset - info->pos);
1197 len -= (info->offset - info->pos);
1198 }
1199
1200 if (len > 0) {
1201 memcpy(info->buffer + info->pos, data, len);
1202 info->pos += len;
1203 }
1204}
1205
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001206static int
1207mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208{
1209 va_list args;
1210 char buf[81];
1211 int len;
1212
1213 va_start(args, fmt);
1214 len = vsprintf(buf, fmt, args);
1215 va_end(args);
1216
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001217 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 return len;
1219}
1220
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001221static int
1222mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
1224 struct info_str info;
1225
1226 info.buffer = pbuf;
1227 info.length = len;
1228 info.offset = offset;
1229 info.pos = 0;
1230
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001231 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1232 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1233 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1234 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1237}
1238
1239/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1240/**
1241 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001242 * @host: scsi host struct
1243 * @buffer: if write, user data; if read, buffer for user
1244 * @start: returns the buffer address
1245 * @offset: if write, 0; if read, the current offset into the buffer from
1246 * the previous read.
1247 * @length: if write, return length;
1248 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 *
1250 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001252int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1254 int length, int func)
1255{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001256 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 MPT_ADAPTER *ioc = hd->ioc;
1258 int size = 0;
1259
1260 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001261 /*
1262 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 */
1264 } else {
1265 if (start)
1266 *start = buffer;
1267
1268 size = mptscsih_host_info(ioc, buffer, offset, length);
1269 }
1270
1271 return size;
1272}
1273
1274/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1275#define ADD_INDEX_LOG(req_ent) do { } while(0)
1276
1277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1278/**
1279 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1280 * @SCpnt: Pointer to scsi_cmnd structure
1281 * @done: Pointer SCSI mid-layer IO completion function
1282 *
1283 * (linux scsi_host_template.queuecommand routine)
1284 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1285 * from a linux scsi_cmnd request and send it to the IOC.
1286 *
1287 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1288 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001289int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1291{
1292 MPT_SCSI_HOST *hd;
1293 MPT_FRAME_HDR *mf;
1294 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001295 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 u32 datalen;
1297 u32 scsictl;
1298 u32 scsidir;
1299 u32 cmd_len;
1300 int my_idx;
1301 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301302 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
Eric Mooree7eae9f2007-09-29 10:15:59 -06001304 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301305 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 SCpnt->scsi_done = done;
1307
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301308 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1309 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301311 if (ioc->taskmgmt_quiesce_io) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301312 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1313 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 return SCSI_MLQUEUE_HOST_BUSY;
1315 }
1316
1317 /*
1318 * Put together a MPT SCSI request...
1319 */
Eric Mooree80b0022007-09-14 18:49:03 -06001320 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301321 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1322 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 return SCSI_MLQUEUE_HOST_BUSY;
1324 }
1325
1326 pScsiReq = (SCSIIORequest_t *) mf;
1327
1328 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1329
1330 ADD_INDEX_LOG(my_idx);
1331
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001332 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 * Seems we may receive a buffer (datalen>0) even when there
1334 * will be no data transfer! GRRRRR...
1335 */
1336 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001337 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1339 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001340 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1342 } else {
1343 datalen = 0;
1344 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1345 }
1346
1347 /* Default to untagged. Once a target structure has been allocated,
1348 * use the Inquiry data to determine if device supports tagged.
1349 */
Eric Moorea69de502007-09-14 18:48:19 -06001350 if (vdevice
1351 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 && (SCpnt->device->tagged_supported)) {
1353 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1354 } else {
1355 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1356 }
1357
1358 /* Use the above information to set up the message frame
1359 */
Eric Moorea69de502007-09-14 18:48:19 -06001360 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1361 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001363 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001364 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1365 else
1366 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 pScsiReq->CDBLength = SCpnt->cmd_len;
1368 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1369 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301370 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001371 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 pScsiReq->Control = cpu_to_le32(scsictl);
1373
1374 /*
1375 * Write SCSI CDB into the message
1376 */
1377 cmd_len = SCpnt->cmd_len;
1378 for (ii=0; ii < cmd_len; ii++)
1379 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1380
1381 for (ii=cmd_len; ii < 16; ii++)
1382 pScsiReq->CDB[ii] = 0;
1383
1384 /* DataLength */
1385 pScsiReq->DataLength = cpu_to_le32(datalen);
1386
1387 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001388 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1390
1391 /* Now add the SG list
1392 * Always have a SGE even if null length.
1393 */
1394 if (datalen == 0) {
1395 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301396 ioc->add_sge((char *)&pScsiReq->SGL,
1397 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 (dma_addr_t) -1);
1399 } else {
1400 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001401 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 goto fail;
1403 }
1404
Eric Moore3dc0b032006-07-11 17:32:33 -06001405 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001406 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Eric Mooree80b0022007-09-14 18:49:03 -06001408 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301409 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1410 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001411 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 return 0;
1413
1414 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001415 mptscsih_freeChainBuffers(ioc, my_idx);
1416 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 return SCSI_MLQUEUE_HOST_BUSY;
1418}
1419
1420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1421/*
1422 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1423 * with a SCSI IO request
1424 * @hd: Pointer to the MPT_SCSI_HOST instance
1425 * @req_idx: Index of the SCSI IO request frame.
1426 *
1427 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1428 * No return.
1429 */
1430static void
1431mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1432{
1433 MPT_FRAME_HDR *chain;
1434 unsigned long flags;
1435 int chain_idx;
1436 int next;
1437
1438 /* Get the first chain index and reset
1439 * tracker state.
1440 */
1441 chain_idx = ioc->ReqToChain[req_idx];
1442 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1443
1444 while (chain_idx != MPT_HOST_NO_CHAIN) {
1445
1446 /* Save the next chain buffer index */
1447 next = ioc->ChainToChain[chain_idx];
1448
1449 /* Free this chain buffer and reset
1450 * tracker
1451 */
1452 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1453
1454 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1455 + (chain_idx * ioc->req_sz));
1456
1457 spin_lock_irqsave(&ioc->FreeQlock, flags);
1458 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1459 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1460
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301461 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 ioc->name, chain_idx));
1463
1464 /* handle next */
1465 chain_idx = next;
1466 }
1467 return;
1468}
1469
1470/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1471/*
1472 * Reset Handling
1473 */
1474
1475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001476/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1478 * @hd: Pointer to MPT_SCSI_HOST structure
1479 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001480 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001481 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 * @lun: Logical Unit for reset (if appropriate)
1483 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001484 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 *
1486 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1487 * or a non-interrupt thread. In the former, must not call schedule().
1488 *
1489 * Not all fields are meaningfull for all task types.
1490 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001491 * Returns 0 for SUCCESS, or FAILED.
1492 *
1493 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301494int
1495mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1496 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
1498 MPT_FRAME_HDR *mf;
1499 SCSITaskMgmt_t *pScsiTm;
1500 int ii;
1501 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001502 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301503 unsigned long timeleft;
1504 u8 issue_hard_reset;
1505 u32 ioc_raw_state;
1506 unsigned long time_count;
1507
1508 issue_hard_reset = 0;
1509 ioc_raw_state = mpt_GetIocState(ioc, 0);
1510
1511 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1512 printk(MYIOC_s_WARN_FMT
1513 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1514 ioc->name, type, ioc_raw_state);
1515 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1516 ioc->name, __func__);
1517 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1518 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1519 "FAILED!!\n", ioc->name);
1520 return 0;
1521 }
1522
1523 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1524 printk(MYIOC_s_WARN_FMT
1525 "TaskMgmt type=%x: ioc_state: "
1526 "DOORBELL_ACTIVE (0x%x)!\n",
1527 ioc->name, type, ioc_raw_state);
1528 return FAILED;
1529 }
1530
1531 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1532 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1533 mf = NULL;
1534 retval = FAILED;
1535 goto out;
1536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 /* Return Fail to calling function if no message frames available.
1539 */
Eric Mooree80b0022007-09-14 18:49:03 -06001540 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301541 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1542 "TaskMgmt no msg frames!!\n", ioc->name));
1543 retval = FAILED;
1544 mpt_clear_taskmgmt_in_progress_flag(ioc);
1545 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301547 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001548 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 /* Format the Request
1551 */
1552 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001553 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 pScsiTm->Bus = channel;
1555 pScsiTm->ChainOffset = 0;
1556 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1557
1558 pScsiTm->Reserved = 0;
1559 pScsiTm->TaskType = type;
1560 pScsiTm->Reserved1 = 0;
1561 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1562 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1563
Eric Moore793955f2007-01-29 09:42:20 -07001564 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566 for (ii=0; ii < 7; ii++)
1567 pScsiTm->Reserved2[ii] = 0;
1568
1569 pScsiTm->TaskMsgContext = ctx2abort;
1570
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301571 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1572 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1573 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301575 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301577 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1578 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001579 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1580 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1581 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301582 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001583 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301584 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1585 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301586 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1587 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1588 ioc->name, mf, retval));
1589 mpt_free_msg_frame(ioc, mf);
1590 mpt_clear_taskmgmt_in_progress_flag(ioc);
1591 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 }
1594
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301595 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1596 timeout*HZ);
1597 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1598 retval = FAILED;
1599 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1600 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1601 mpt_clear_taskmgmt_in_progress_flag(ioc);
1602 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1603 goto out;
1604 issue_hard_reset = 1;
1605 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 }
1607
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301608 retval = mptscsih_taskmgmt_reply(ioc, type,
1609 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001610
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301611 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1612 "TaskMgmt completed (%d seconds)\n",
1613 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1614
1615 out:
1616
1617 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1618 if (issue_hard_reset) {
1619 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
1620 ioc->name, __func__);
1621 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1622 mpt_free_msg_frame(ioc, mf);
1623 }
1624
1625 retval = (retval == 0) ? 0 : FAILED;
1626 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 return retval;
1628}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301629EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001631static int
1632mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1633{
1634 switch (ioc->bus_type) {
1635 case FC:
1636 return 40;
1637 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001638 case SPI:
1639 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001640 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001641 }
1642}
1643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1645/**
1646 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1647 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1648 *
1649 * (linux scsi_host_template.eh_abort_handler routine)
1650 *
1651 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001652 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001653int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654mptscsih_abort(struct scsi_cmnd * SCpnt)
1655{
1656 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 MPT_FRAME_HDR *mf;
1658 u32 ctx2abort;
1659 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001660 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001661 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001662 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001663 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
1665 /* If we can't locate our host adapter structure, return FAILED status.
1666 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001667 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 SCpnt->result = DID_RESET << 16;
1669 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001670 printk(KERN_ERR MYNAM ": task abort: "
1671 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 return FAILED;
1673 }
1674
Eric Moore958d4a32007-06-15 17:24:14 -06001675 ioc = hd->ioc;
1676 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1677 ioc->name, SCpnt);
1678 scsi_print_command(SCpnt);
1679
1680 vdevice = SCpnt->device->hostdata;
1681 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001682 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1683 "task abort: device has been deleted (sc=%p)\n",
1684 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001685 SCpnt->result = DID_NO_CONNECT << 16;
1686 SCpnt->scsi_done(SCpnt);
1687 retval = 0;
1688 goto out;
1689 }
1690
Eric Moorecc78d302007-06-15 17:27:21 -06001691 /* Task aborts are not supported for hidden raid components.
1692 */
1693 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001694 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1695 "task abort: hidden raid component (sc=%p)\n",
1696 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001697 SCpnt->result = DID_RESET << 16;
1698 retval = FAILED;
1699 goto out;
1700 }
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 /* Find this command
1703 */
Eric Mooree8206382007-09-29 10:16:53 -06001704 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001705 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 * Do OS callback.
1707 */
1708 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001709 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001710 "Command not in the active list! (sc=%p)\n", ioc->name,
1711 SCpnt));
1712 retval = 0;
1713 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 }
1715
Kashyap, Desai2f187862009-05-29 16:52:37 +05301716 if (ioc->timeouts < -1)
1717 ioc->timeouts++;
Moore, Eric65207fe2006-04-21 16:14:35 -06001718
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301719 if (mpt_fwfault_debug)
1720 mpt_halt_firmware(ioc);
1721
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1723 * (the IO to be ABORT'd)
1724 *
1725 * NOTE: Since we do not byteswap MsgContext, we do not
1726 * swap it here either. It is an opaque cookie to
1727 * the controller, so it does not matter. -DaveM
1728 */
Eric Mooree80b0022007-09-14 18:49:03 -06001729 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1731
1732 hd->abortSCpnt = SCpnt;
1733
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301734 retval = mptscsih_IssueTaskMgmt(hd,
1735 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1736 vdevice->vtarget->channel,
1737 vdevice->vtarget->id, vdevice->lun,
1738 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Eric Mooree8206382007-09-29 10:16:53 -06001740 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05301741 SCpnt->serial_number == sn) {
1742 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1743 "task abort: command still in active list! (sc=%p)\n",
1744 ioc->name, SCpnt));
Eric Moore3dc0b032006-07-11 17:32:33 -06001745 retval = FAILED;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301746 } else {
1747 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1748 "task abort: command cleared from active list! (sc=%p)\n",
1749 ioc->name, SCpnt));
1750 retval = SUCCESS;
1751 }
Eric Moore3dc0b032006-07-11 17:32:33 -06001752
Eric Moore958d4a32007-06-15 17:24:14 -06001753 out:
1754 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
Kashyap, Desai2f187862009-05-29 16:52:37 +05301755 ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
Kashyap, Desai2f187862009-05-29 16:52:37 +05301757 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758}
1759
1760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1761/**
1762 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1763 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1764 *
1765 * (linux scsi_host_template.eh_dev_reset_handler routine)
1766 *
1767 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001768 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001769int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1771{
1772 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001773 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001774 VirtDevice *vdevice;
1775 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 /* If we can't locate our host adapter structure, return FAILED status.
1778 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001779 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001780 printk(KERN_ERR MYNAM ": target reset: "
1781 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 return FAILED;
1783 }
1784
Eric Moore958d4a32007-06-15 17:24:14 -06001785 ioc = hd->ioc;
1786 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1787 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001788 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
Eric Moore958d4a32007-06-15 17:24:14 -06001790 vdevice = SCpnt->device->hostdata;
1791 if (!vdevice || !vdevice->vtarget) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05301792 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001793 goto out;
1794 }
1795
Eric Moorecc78d302007-06-15 17:27:21 -06001796 /* Target reset to hidden raid component is not supported
1797 */
1798 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1799 retval = FAILED;
1800 goto out;
1801 }
1802
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301803 retval = mptscsih_IssueTaskMgmt(hd,
1804 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1805 vdevice->vtarget->channel,
1806 vdevice->vtarget->id, 0, 0,
1807 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001808
1809 out:
1810 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1811 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001812
1813 if (retval == 0)
1814 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001815 else
1816 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817}
1818
Eric Moorecd2c6192007-01-29 09:47:47 -07001819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1821/**
1822 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1823 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1824 *
1825 * (linux scsi_host_template.eh_bus_reset_handler routine)
1826 *
1827 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001828 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001829int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1831{
1832 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001833 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001834 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001835 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 /* If we can't locate our host adapter structure, return FAILED status.
1838 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001839 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001840 printk(KERN_ERR MYNAM ": bus reset: "
1841 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 return FAILED;
1843 }
1844
Eric Moore958d4a32007-06-15 17:24:14 -06001845 ioc = hd->ioc;
1846 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1847 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001848 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
Kashyap, Desai2f187862009-05-29 16:52:37 +05301850 if (ioc->timeouts < -1)
1851 ioc->timeouts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Eric Moorea69de502007-09-14 18:48:19 -06001853 vdevice = SCpnt->device->hostdata;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301854 if (!vdevice || !vdevice->vtarget)
1855 return SUCCESS;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301856 retval = mptscsih_IssueTaskMgmt(hd,
1857 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1858 vdevice->vtarget->channel, 0, 0, 0,
1859 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Eric Moore958d4a32007-06-15 17:24:14 -06001861 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1862 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001863
1864 if (retval == 0)
1865 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001866 else
1867 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868}
1869
1870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1871/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001872 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1874 *
1875 * (linux scsi_host_template.eh_host_reset_handler routine)
1876 *
1877 * Returns SUCCESS or FAILED.
1878 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001879int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1881{
1882 MPT_SCSI_HOST * hd;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301883 int status = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001884 MPT_ADAPTER *ioc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301885 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
1887 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001888 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001889 printk(KERN_ERR MYNAM ": host reset: "
1890 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 return FAILED;
1892 }
1893
James Bottomleya6da74c2008-12-15 14:13:27 -06001894 /* make sure we have no outstanding commands at this stage */
1895 mptscsih_flush_running_cmds(hd);
1896
Eric Moore958d4a32007-06-15 17:24:14 -06001897 ioc = hd->ioc;
1898 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1899 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 /* If our attempts to reset the host failed, then return a failed
1902 * status. The host will be taken off line by the SCSI mid-layer.
1903 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05301904 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1905 if (retval < 0)
1906 status = FAILED;
1907 else
1908 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
Eric Moore958d4a32007-06-15 17:24:14 -06001910 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1911 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
Kashyap, Desai2f187862009-05-29 16:52:37 +05301913 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914}
1915
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301917mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
1918 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301920 u16 iocstatus;
1921 u32 termination_count;
1922 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301924 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
1925 retval = FAILED;
1926 goto out;
1927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301929 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301931 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
1932 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301934 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1935 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
1936 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
1937 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
1938 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
1939 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
1940 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301942 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
1943 pScsiTmReply->ResponseCode)
1944 mptscsih_taskmgmt_response_code(ioc,
1945 pScsiTmReply->ResponseCode);
1946
1947 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
1948 retval = 0;
1949 goto out;
1950 }
1951
1952 retval = FAILED;
1953 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
1954 if (termination_count == 1)
1955 retval = 0;
1956 goto out;
1957 }
1958
1959 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1960 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1961 retval = 0;
1962
1963 out:
1964 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965}
1966
1967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301968void
Moore, Eric9f63bb72006-01-16 18:53:26 -07001969mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
1970{
1971 char *desc;
1972
1973 switch (response_code) {
1974 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
1975 desc = "The task completed.";
1976 break;
1977 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
1978 desc = "The IOC received an invalid frame status.";
1979 break;
1980 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1981 desc = "The task type is not supported.";
1982 break;
1983 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
1984 desc = "The requested task failed.";
1985 break;
1986 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1987 desc = "The task completed successfully.";
1988 break;
1989 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1990 desc = "The LUN request is invalid.";
1991 break;
1992 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1993 desc = "The task is in the IOC queue and has not been sent to target.";
1994 break;
1995 default:
1996 desc = "unknown";
1997 break;
1998 }
1999 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2000 ioc->name, response_code, desc);
2001}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302002EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07002003
2004/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005/**
2006 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2007 * @ioc: Pointer to MPT_ADAPTER structure
2008 * @mf: Pointer to SCSI task mgmt request frame
2009 * @mr: Pointer to SCSI task mgmt reply frame
2010 *
2011 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2012 * of any SCSI task management request.
2013 * This routine is registered with the MPT (base) driver at driver
2014 * load/init time via the mpt_register() API call.
2015 *
2016 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002017 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002018int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302019mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2020 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302022 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2023 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302025 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302027 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002028 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002029
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302030 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2031 memcpy(ioc->taskmgmt_cmds.reply, mr,
2032 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002033 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302034 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2035 mpt_clear_taskmgmt_in_progress_flag(ioc);
2036 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2037 complete(&ioc->taskmgmt_cmds.done);
2038 return 1;
2039 }
2040 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041}
2042
2043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2044/*
2045 * This is anyones guess quite frankly.
2046 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002047int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2049 sector_t capacity, int geom[])
2050{
2051 int heads;
2052 int sectors;
2053 sector_t cylinders;
2054 ulong dummy;
2055
2056 heads = 64;
2057 sectors = 32;
2058
2059 dummy = heads * sectors;
2060 cylinders = capacity;
2061 sector_div(cylinders,dummy);
2062
2063 /*
2064 * Handle extended translation size for logical drives
2065 * > 1Gb
2066 */
2067 if ((ulong)capacity >= 0x200000) {
2068 heads = 255;
2069 sectors = 63;
2070 dummy = heads * sectors;
2071 cylinders = capacity;
2072 sector_div(cylinders,dummy);
2073 }
2074
2075 /* return result */
2076 geom[0] = heads;
2077 geom[1] = sectors;
2078 geom[2] = cylinders;
2079
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 return 0;
2081}
2082
Moore, Ericf44e5462006-03-14 09:14:21 -07002083/* Search IOC page 3 to determine if this is hidden physical disk
2084 *
2085 */
2086int
Eric Moore793955f2007-01-29 09:42:20 -07002087mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002088{
Eric Mooreb506ade2007-01-29 09:45:37 -07002089 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002090 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002091 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002092
Eric Moore793955f2007-01-29 09:42:20 -07002093 if (!ioc->raid_data.pIocPg3)
2094 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002095 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002096 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2097 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2098 rc = 1;
2099 goto out;
2100 }
2101 }
2102
Eric Mooreb506ade2007-01-29 09:45:37 -07002103 /*
2104 * Check inactive list for matching phys disks
2105 */
2106 if (list_empty(&ioc->raid_data.inactive_list))
2107 goto out;
2108
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002109 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002110 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2111 list) {
2112 if ((component_info->d.PhysDiskID == id) &&
2113 (component_info->d.PhysDiskBus == channel))
2114 rc = 1;
2115 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002116 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002117
Eric Moore793955f2007-01-29 09:42:20 -07002118 out:
2119 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002120}
2121EXPORT_SYMBOL(mptscsih_is_phys_disk);
2122
Eric Moore793955f2007-01-29 09:42:20 -07002123u8
2124mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002125{
Eric Mooreb506ade2007-01-29 09:45:37 -07002126 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002127 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002128 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002129
Eric Moore793955f2007-01-29 09:42:20 -07002130 if (!ioc->raid_data.pIocPg3)
2131 goto out;
2132 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2133 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2134 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2135 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2136 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002137 }
2138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
Eric Mooreb506ade2007-01-29 09:45:37 -07002140 /*
2141 * Check inactive list for matching phys disks
2142 */
2143 if (list_empty(&ioc->raid_data.inactive_list))
2144 goto out;
2145
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002146 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002147 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2148 list) {
2149 if ((component_info->d.PhysDiskID == id) &&
2150 (component_info->d.PhysDiskBus == channel))
2151 rc = component_info->d.PhysDiskNum;
2152 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002153 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002154
Eric Moore793955f2007-01-29 09:42:20 -07002155 out:
2156 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002157}
Eric Moore793955f2007-01-29 09:42:20 -07002158EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002159
2160/*
2161 * OS entry point to allow for host driver to free allocated memory
2162 * Called if no device present or device being unloaded
2163 */
2164void
2165mptscsih_slave_destroy(struct scsi_device *sdev)
2166{
2167 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002168 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002169 VirtTarget *vtarget;
2170 VirtDevice *vdevice;
2171 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002173 starget = scsi_target(sdev);
2174 vtarget = starget->hostdata;
2175 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002177 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002178 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002179 mptscsih_synchronize_cache(hd, vdevice);
2180 kfree(vdevice);
2181 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182}
2183
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2185/*
2186 * mptscsih_change_queue_depth - This function will set a devices queue depth
2187 * @sdev: per scsi_device pointer
2188 * @qdepth: requested queue depth
2189 *
2190 * Adding support for new 'change_queue_depth' api.
2191*/
2192int
2193mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002195 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002196 VirtTarget *vtarget;
2197 struct scsi_target *starget;
2198 int max_depth;
2199 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002200 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002202 starget = scsi_target(sdev);
2203 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002204
Eric Mooree80b0022007-09-14 18:49:03 -06002205 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002206 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002208 else if (sdev->type == TYPE_DISK &&
2209 vtarget->minSyncFactor <= MPT_ULTRA160)
2210 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2211 else
2212 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 } else
2214 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2215
2216 if (qdepth > max_depth)
2217 qdepth = max_depth;
2218 if (qdepth == 1)
2219 tagged = 0;
2220 else
2221 tagged = MSG_SIMPLE_TAG;
2222
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002223 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2224 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225}
2226
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227/*
2228 * OS entry point to adjust the queue_depths on a per-device basis.
2229 * Called once per device the bus scan. Use it to force the queue_depth
2230 * member to 1 if a device does not support Q tags.
2231 * Return non-zero if fails.
2232 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002233int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002234mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002236 struct Scsi_Host *sh = sdev->host;
2237 VirtTarget *vtarget;
2238 VirtDevice *vdevice;
2239 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002240 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002241 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002243 starget = scsi_target(sdev);
2244 vtarget = starget->hostdata;
2245 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Eric Mooree80b0022007-09-14 18:49:03 -06002247 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002248 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002249 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2250 if (ioc->bus_type == SPI)
2251 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002252 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002253 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002254 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
Eric Moore793955f2007-01-29 09:42:20 -07002256 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Eric Mooree80b0022007-09-14 18:49:03 -06002258 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002260 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
Eric Mooree80b0022007-09-14 18:49:03 -06002262 if (ioc->bus_type == SPI)
2263 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002264 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002265 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002266 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Kashyap, Desai2f187862009-05-29 16:52:37 +05302268 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Eric Mooree80b0022007-09-14 18:49:03 -06002269 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002271 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002272 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
2274 return 0;
2275}
2276
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2278/*
2279 * Private routines...
2280 */
2281
2282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2283/* Utility function to copy sense data from the scsi_cmnd buffer
2284 * to the FC and SCSI target structures.
2285 *
2286 */
2287static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002288mptscsih_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 -07002289{
Eric Moorea69de502007-09-14 18:48:19 -06002290 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 SCSIIORequest_t *pReq;
2292 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002293 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
2295 /* Get target structure
2296 */
2297 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002298 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
2300 if (sense_count) {
2301 u8 *sense_data;
2302 int req_index;
2303
2304 /* Copy the sense received into the scsi command block. */
2305 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002306 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2308
2309 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2310 */
Eric Mooree80b0022007-09-14 18:49:03 -06002311 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002312 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002315 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2317 ioc->events[idx].eventContext = ioc->eventContext;
2318
Dave Jones3d9780b2007-05-21 20:59:47 -04002319 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2320 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2321 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
Dave Jones3d9780b2007-05-21 20:59:47 -04002323 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
2325 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002326 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002327 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002328 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002329 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2330 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002331 MPT_TARGET_FLAGS_LED_ON;
2332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 }
2334 }
2335 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002336 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2337 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
2339}
2340
Eric Mooree8206382007-09-29 10:16:53 -06002341
2342/**
2343 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002344 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002345 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002346 *
Kashyap, Desai2f187862009-05-29 16:52:37 +05302347 * @ioc: Pointer to MPT_ADAPTER structure
2348 * @i: index into the array
2349 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002350 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302351 *
Eric Mooree8206382007-09-29 10:16:53 -06002352 **/
2353static struct scsi_cmnd *
2354mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2355{
2356 unsigned long flags;
2357 struct scsi_cmnd *scmd;
2358
2359 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2360 scmd = ioc->ScsiLookup[i];
2361 ioc->ScsiLookup[i] = NULL;
2362 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2363
2364 return scmd;
2365}
2366
2367/**
2368 * mptscsih_set_scsi_lookup
2369 *
2370 * writes a scmd entry into the ScsiLookup[] array list
2371 *
2372 * @ioc: Pointer to MPT_ADAPTER structure
2373 * @i: index into the array
2374 * @scmd: scsi_cmnd pointer
2375 *
2376 **/
2377static void
2378mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2379{
2380 unsigned long flags;
2381
2382 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2383 ioc->ScsiLookup[i] = scmd;
2384 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2385}
2386
2387/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002388 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002389 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002390 * @sc: scsi_cmnd pointer
2391 */
Eric Mooree8206382007-09-29 10:16:53 -06002392static int
2393SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2394{
2395 unsigned long flags;
2396 int i, index=-1;
2397
2398 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2399 for (i = 0; i < ioc->req_depth; i++) {
2400 if (ioc->ScsiLookup[i] == sc) {
2401 index = i;
2402 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 }
2404 }
2405
Eric Mooree8206382007-09-29 10:16:53 -06002406 out:
2407 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2408 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409}
2410
2411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002412int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2414{
2415 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
Eric Mooree7eae9f2007-09-29 10:15:59 -06002417 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302420 hd = shost_priv(ioc->sh);
2421 switch (reset_phase) {
2422 case MPT_IOC_SETUP_RESET:
2423 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2424 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302425 break;
2426 case MPT_IOC_PRE_RESET:
2427 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2428 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302429 mptscsih_flush_running_cmds(hd);
2430 break;
2431 case MPT_IOC_POST_RESET:
2432 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2433 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2434 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2435 ioc->internal_cmds.status |=
2436 MPT_MGMT_STATUS_DID_IOCRESET;
2437 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302439 break;
2440 default:
2441 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 return 1; /* currently means nothing really */
2444}
2445
2446/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002447int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2449{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2451
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302452 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2453 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2454 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Kashyap, Desai2f187862009-05-29 16:52:37 +05302456 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2457 event == MPI_EVENT_EXT_BUS_RESET) &&
2458 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2459 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
2461 return 1; /* currently means nothing really */
2462}
2463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2465/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 * Bus Scan and Domain Validation functionality ...
2467 */
2468
2469/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2470/*
2471 * mptscsih_scandv_complete - Scan and DV callback routine registered
2472 * to Fustion MPT (base) driver.
2473 *
2474 * @ioc: Pointer to MPT_ADAPTER structure
2475 * @mf: Pointer to original MPT request frame
2476 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2477 *
2478 * This routine is called from mpt.c::mpt_interrupt() at the completion
2479 * of any SCSI IO request.
2480 * This routine is registered with the Fusion MPT (base) driver at driver
2481 * load/init time via the mpt_register() API call.
2482 *
2483 * Returns 1 indicating alloc'd request frame ptr should be freed.
2484 *
2485 * Remark: Sets a completion code and (possibly) saves sense data
2486 * in the IOC member localReply structure.
2487 * Used ONLY for DV and other internal commands.
2488 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002489int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302490mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2491 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302494 SCSIIOReply_t *pReply;
2495 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302497 u8 *sense_data;
2498 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302500 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2501 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2502 if (!reply)
2503 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002504
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302505 pReply = (SCSIIOReply_t *) reply;
2506 pReq = (SCSIIORequest_t *) req;
2507 ioc->internal_cmds.completion_code =
2508 mptscsih_get_completion_code(ioc, req, reply);
2509 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2510 memcpy(ioc->internal_cmds.reply, reply,
2511 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2512 cmd = reply->u.hdr.Function;
2513 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2514 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2515 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2516 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2517 sense_data = ((u8 *)ioc->sense_buf_pool +
2518 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2519 sz = min_t(int, pReq->SenseBufferLength,
2520 MPT_SENSE_BUFFER_ALLOC);
2521 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302523 out:
2524 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2525 return 0;
2526 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2527 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 return 1;
2529}
2530
2531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2532/* mptscsih_timer_expired - Call back for timer process.
2533 * Used only for dv functionality.
2534 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2535 *
2536 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002537void
2538mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539{
2540 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002541 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Eric Mooree80b0022007-09-14 18:49:03 -06002543 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
2545 if (hd->cmdPtr) {
2546 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2547
2548 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2549 /* Desire to issue a task management request here.
2550 * TM requests MUST be single threaded.
2551 * If old eh code and no TM current, issue request.
2552 * If new eh code, do nothing. Wait for OS cmd timeout
2553 * for bus reset.
2554 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 } else {
2556 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002557 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2558 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 }
2560 }
2561 } else {
2562 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002563 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 }
2565
2566 /* No more processing.
2567 * TM call will generate an interrupt for SCSI TM Management.
2568 * The FW will reply to all outstanding commands, callback will finish cleanup.
2569 * Hard reset clean-up will free all resources.
2570 */
Eric Mooree80b0022007-09-14 18:49:03 -06002571 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
2573 return;
2574}
2575
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302576/**
2577 * mptscsih_get_completion_code -
2578 * @ioc: Pointer to MPT_ADAPTER structure
2579 * @reply:
2580 * @cmd:
2581 *
2582 **/
2583static int
2584mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2585 MPT_FRAME_HDR *reply)
2586{
2587 SCSIIOReply_t *pReply;
2588 MpiRaidActionReply_t *pr;
2589 u8 scsi_status;
2590 u16 status;
2591 int completion_code;
2592
2593 pReply = (SCSIIOReply_t *)reply;
2594 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2595 scsi_status = pReply->SCSIStatus;
2596
2597 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2598 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2599 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2600 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2601
2602 switch (status) {
2603
2604 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2605 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2606 break;
2607
2608 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2609 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2610 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2611 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2612 completion_code = MPT_SCANDV_DID_RESET;
2613 break;
2614
2615 case MPI_IOCSTATUS_BUSY:
2616 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2617 completion_code = MPT_SCANDV_BUSY;
2618 break;
2619
2620 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2621 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2622 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2623 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2624 completion_code = MPT_SCANDV_GOOD;
2625 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2626 pr = (MpiRaidActionReply_t *)reply;
2627 if (le16_to_cpu(pr->ActionStatus) ==
2628 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2629 completion_code = MPT_SCANDV_GOOD;
2630 else
2631 completion_code = MPT_SCANDV_SOME_ERROR;
2632 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2633 completion_code = MPT_SCANDV_SENSE;
2634 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2635 if (req->u.scsireq.CDB[0] == INQUIRY)
2636 completion_code = MPT_SCANDV_ISSUE_SENSE;
2637 else
2638 completion_code = MPT_SCANDV_DID_RESET;
2639 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2640 completion_code = MPT_SCANDV_DID_RESET;
2641 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2642 completion_code = MPT_SCANDV_DID_RESET;
2643 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2644 completion_code = MPT_SCANDV_BUSY;
2645 else
2646 completion_code = MPT_SCANDV_GOOD;
2647 break;
2648
2649 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2650 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2651 completion_code = MPT_SCANDV_DID_RESET;
2652 else
2653 completion_code = MPT_SCANDV_SOME_ERROR;
2654 break;
2655 default:
2656 completion_code = MPT_SCANDV_SOME_ERROR;
2657 break;
2658
2659 } /* switch(status) */
2660
2661 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2662 " completionCode set to %08xh\n", ioc->name, completion_code));
2663 return completion_code;
2664}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
2666/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2667/**
2668 * mptscsih_do_cmd - Do internal command.
2669 * @hd: MPT_SCSI_HOST pointer
2670 * @io: INTERNAL_CMD pointer.
2671 *
2672 * Issue the specified internally generated command and do command
2673 * specific cleanup. For bus scan / DV only.
2674 * NOTES: If command is Inquiry and status is good,
2675 * initialize a target structure, save the data
2676 *
2677 * Remark: Single threaded access only.
2678 *
2679 * Return:
2680 * < 0 if an illegal command or no resources
2681 *
2682 * 0 if good
2683 *
2684 * > 0 if command complete but some type of completion error.
2685 */
2686static int
2687mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2688{
2689 MPT_FRAME_HDR *mf;
2690 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302692 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 char cmdLen;
2694 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 +05302695 u8 cmd = io->cmd;
2696 MPT_ADAPTER *ioc = hd->ioc;
2697 int ret = 0;
2698 unsigned long timeleft;
2699 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302701 /* don't send internal command during diag reset */
2702 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2703 if (ioc->ioc_reset_in_progress) {
2704 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2705 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2706 "%s: busy with host reset\n", ioc->name, __func__));
2707 return MPT_SCANDV_BUSY;
2708 }
2709 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2710
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302711 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 /* Set command specific information
2714 */
2715 switch (cmd) {
2716 case INQUIRY:
2717 cmdLen = 6;
2718 dir = MPI_SCSIIO_CONTROL_READ;
2719 CDB[0] = cmd;
2720 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302721 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 break;
2723
2724 case TEST_UNIT_READY:
2725 cmdLen = 6;
2726 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302727 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 break;
2729
2730 case START_STOP:
2731 cmdLen = 6;
2732 dir = MPI_SCSIIO_CONTROL_READ;
2733 CDB[0] = cmd;
2734 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302735 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 break;
2737
2738 case REQUEST_SENSE:
2739 cmdLen = 6;
2740 CDB[0] = cmd;
2741 CDB[4] = io->size;
2742 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302743 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 break;
2745
2746 case READ_BUFFER:
2747 cmdLen = 10;
2748 dir = MPI_SCSIIO_CONTROL_READ;
2749 CDB[0] = cmd;
2750 if (io->flags & MPT_ICFLAG_ECHO) {
2751 CDB[1] = 0x0A;
2752 } else {
2753 CDB[1] = 0x02;
2754 }
2755
2756 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2757 CDB[1] |= 0x01;
2758 }
2759 CDB[6] = (io->size >> 16) & 0xFF;
2760 CDB[7] = (io->size >> 8) & 0xFF;
2761 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302762 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 break;
2764
2765 case WRITE_BUFFER:
2766 cmdLen = 10;
2767 dir = MPI_SCSIIO_CONTROL_WRITE;
2768 CDB[0] = cmd;
2769 if (io->flags & MPT_ICFLAG_ECHO) {
2770 CDB[1] = 0x0A;
2771 } else {
2772 CDB[1] = 0x02;
2773 }
2774 CDB[6] = (io->size >> 16) & 0xFF;
2775 CDB[7] = (io->size >> 8) & 0xFF;
2776 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302777 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 break;
2779
2780 case RESERVE:
2781 cmdLen = 6;
2782 dir = MPI_SCSIIO_CONTROL_READ;
2783 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302784 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 break;
2786
2787 case RELEASE:
2788 cmdLen = 6;
2789 dir = MPI_SCSIIO_CONTROL_READ;
2790 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302791 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 break;
2793
2794 case SYNCHRONIZE_CACHE:
2795 cmdLen = 10;
2796 dir = MPI_SCSIIO_CONTROL_READ;
2797 CDB[0] = cmd;
2798// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302799 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 break;
2801
2802 default:
2803 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302804 ret = -EFAULT;
2805 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 }
2807
2808 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302809 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 */
Eric Mooree80b0022007-09-14 18:49:03 -06002811 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302812 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2813 ioc->name, __func__));
2814 ret = MPT_SCANDV_BUSY;
2815 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 }
2817
2818 pScsiReq = (SCSIIORequest_t *) mf;
2819
2820 /* Get the request index */
2821 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2822 ADD_INDEX_LOG(my_idx); /* for debug */
2823
2824 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2825 pScsiReq->TargetID = io->physDiskNum;
2826 pScsiReq->Bus = 0;
2827 pScsiReq->ChainOffset = 0;
2828 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2829 } else {
2830 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002831 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 pScsiReq->ChainOffset = 0;
2833 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2834 }
2835
2836 pScsiReq->CDBLength = cmdLen;
2837 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2838
2839 pScsiReq->Reserved = 0;
2840
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302841 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 /* MsgContext set in mpt_get_msg_fram call */
2843
Eric Moore793955f2007-01-29 09:42:20 -07002844 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2847 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2848 else
2849 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2850
2851 if (cmd == REQUEST_SENSE) {
2852 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302853 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2854 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 }
2856
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302857 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 pScsiReq->CDB[ii] = CDB[ii];
2859
2860 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06002861 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
2863
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302864 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2865 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
2866 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302868 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302869 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302870 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
2871 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302872 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302873 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302875 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06002876 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302877 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
2878 timeout*HZ);
2879 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2880 ret = MPT_SCANDV_DID_RESET;
2881 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2882 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
2883 cmd));
2884 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2885 mpt_free_msg_frame(ioc, mf);
2886 goto out;
2887 }
2888 if (!timeleft) {
2889 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
2890 ioc->name, __func__);
2891 mpt_HardResetHandler(ioc, CAN_SLEEP);
2892 mpt_free_msg_frame(ioc, mf);
2893 }
2894 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 }
2896
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302897 ret = ioc->internal_cmds.completion_code;
2898 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
2899 ioc->name, __func__, ret));
2900
2901 out:
2902 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
2903 mutex_unlock(&ioc->internal_cmds.mutex);
2904 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905}
2906
2907/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2908/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002909 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
2910 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002911 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002912 *
2913 * Uses the ISR, but with special processing.
2914 * MUST be single-threaded.
2915 *
2916 */
2917static void
2918mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
2919{
2920 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Eric Moorecc78d302007-06-15 17:27:21 -06002922 /* Ignore hidden raid components, this is handled when the command
2923 * is sent to the volume
2924 */
2925 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
2926 return;
2927
2928 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
2929 !vdevice->configured_lun)
2930 return;
2931
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 /* Following parameters will not change
2933 * in this routine.
2934 */
2935 iocmd.cmd = SYNCHRONIZE_CACHE;
2936 iocmd.flags = 0;
2937 iocmd.physDiskNum = -1;
2938 iocmd.data = NULL;
2939 iocmd.data_dma = -1;
2940 iocmd.size = 0;
2941 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07002942 iocmd.channel = vdevice->vtarget->channel;
2943 iocmd.id = vdevice->vtarget->id;
2944 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
Eric Moorecc78d302007-06-15 17:27:21 -06002946 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947}
2948
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302949static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01002950mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
2951 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302952{
Tony Jonesee959b02008-02-22 00:13:36 +01002953 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06002954 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302955 MPT_ADAPTER *ioc = hd->ioc;
2956
2957 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
2958 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
2959 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
2960 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
2961 ioc->facts.FWVersion.Word & 0x000000FF);
2962}
Tony Jonesee959b02008-02-22 00:13:36 +01002963static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302964
2965static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01002966mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
2967 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302968{
Tony Jonesee959b02008-02-22 00:13:36 +01002969 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06002970 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302971 MPT_ADAPTER *ioc = hd->ioc;
2972
2973 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
2974 (ioc->biosVersion & 0xFF000000) >> 24,
2975 (ioc->biosVersion & 0x00FF0000) >> 16,
2976 (ioc->biosVersion & 0x0000FF00) >> 8,
2977 ioc->biosVersion & 0x000000FF);
2978}
Tony Jonesee959b02008-02-22 00:13:36 +01002979static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302980
2981static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01002982mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
2983 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302984{
Tony Jonesee959b02008-02-22 00:13:36 +01002985 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06002986 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302987 MPT_ADAPTER *ioc = hd->ioc;
2988
2989 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
2990}
Tony Jonesee959b02008-02-22 00:13:36 +01002991static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302992
2993static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01002994mptscsih_version_product_show(struct device *dev,
2995 struct device_attribute *attr,
2996char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302997{
Tony Jonesee959b02008-02-22 00:13:36 +01002998 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06002999 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303000 MPT_ADAPTER *ioc = hd->ioc;
3001
3002 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3003}
Tony Jonesee959b02008-02-22 00:13:36 +01003004static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303005 mptscsih_version_product_show, NULL);
3006
3007static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003008mptscsih_version_nvdata_persistent_show(struct device *dev,
3009 struct device_attribute *attr,
3010 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303011{
Tony Jonesee959b02008-02-22 00:13:36 +01003012 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003013 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303014 MPT_ADAPTER *ioc = hd->ioc;
3015
3016 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3017 ioc->nvdata_version_persistent);
3018}
Tony Jonesee959b02008-02-22 00:13:36 +01003019static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303020 mptscsih_version_nvdata_persistent_show, NULL);
3021
3022static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003023mptscsih_version_nvdata_default_show(struct device *dev,
3024 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303025{
Tony Jonesee959b02008-02-22 00:13:36 +01003026 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003027 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303028 MPT_ADAPTER *ioc = hd->ioc;
3029
3030 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3031}
Tony Jonesee959b02008-02-22 00:13:36 +01003032static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303033 mptscsih_version_nvdata_default_show, NULL);
3034
3035static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003036mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3037 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303038{
Tony Jonesee959b02008-02-22 00:13:36 +01003039 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003040 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303041 MPT_ADAPTER *ioc = hd->ioc;
3042
3043 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3044}
Tony Jonesee959b02008-02-22 00:13:36 +01003045static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303046
3047static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003048mptscsih_board_assembly_show(struct device *dev,
3049 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303050{
Tony Jonesee959b02008-02-22 00:13:36 +01003051 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003052 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303053 MPT_ADAPTER *ioc = hd->ioc;
3054
3055 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3056}
Tony Jonesee959b02008-02-22 00:13:36 +01003057static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303058 mptscsih_board_assembly_show, NULL);
3059
3060static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003061mptscsih_board_tracer_show(struct device *dev, 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, "%s\n", ioc->board_tracer);
3069}
Tony Jonesee959b02008-02-22 00:13:36 +01003070static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303071 mptscsih_board_tracer_show, NULL);
3072
3073static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003074mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3075 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303076{
Tony Jonesee959b02008-02-22 00:13:36 +01003077 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003078 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303079 MPT_ADAPTER *ioc = hd->ioc;
3080
3081 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3082}
Tony Jonesee959b02008-02-22 00:13:36 +01003083static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303084 mptscsih_io_delay_show, NULL);
3085
3086static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003087mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3088 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303089{
Tony Jonesee959b02008-02-22 00:13:36 +01003090 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003091 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303092 MPT_ADAPTER *ioc = hd->ioc;
3093
3094 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3095}
Tony Jonesee959b02008-02-22 00:13:36 +01003096static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303097 mptscsih_device_delay_show, NULL);
3098
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303099static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003100mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3101 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +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, Sathya6757d6b2007-07-25 11:14:01 +05303105 MPT_ADAPTER *ioc = hd->ioc;
3106
3107 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3108}
3109static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003110mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3111 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303112{
Tony Jonesee959b02008-02-22 00:13:36 +01003113 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003114 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303115 MPT_ADAPTER *ioc = hd->ioc;
3116 int val = 0;
3117
3118 if (sscanf(buf, "%x", &val) != 1)
3119 return -EINVAL;
3120
3121 ioc->debug_level = val;
3122 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3123 ioc->name, ioc->debug_level);
3124 return strlen(buf);
3125}
Tony Jonesee959b02008-02-22 00:13:36 +01003126static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3127 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303128
Tony Jonesee959b02008-02-22 00:13:36 +01003129struct device_attribute *mptscsih_host_attrs[] = {
3130 &dev_attr_version_fw,
3131 &dev_attr_version_bios,
3132 &dev_attr_version_mpi,
3133 &dev_attr_version_product,
3134 &dev_attr_version_nvdata_persistent,
3135 &dev_attr_version_nvdata_default,
3136 &dev_attr_board_name,
3137 &dev_attr_board_assembly,
3138 &dev_attr_board_tracer,
3139 &dev_attr_io_delay,
3140 &dev_attr_device_delay,
3141 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303142 NULL,
3143};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303144
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303145EXPORT_SYMBOL(mptscsih_host_attrs);
3146
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003147EXPORT_SYMBOL(mptscsih_remove);
3148EXPORT_SYMBOL(mptscsih_shutdown);
3149#ifdef CONFIG_PM
3150EXPORT_SYMBOL(mptscsih_suspend);
3151EXPORT_SYMBOL(mptscsih_resume);
3152#endif
3153EXPORT_SYMBOL(mptscsih_proc_info);
3154EXPORT_SYMBOL(mptscsih_info);
3155EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003156EXPORT_SYMBOL(mptscsih_slave_destroy);
3157EXPORT_SYMBOL(mptscsih_slave_configure);
3158EXPORT_SYMBOL(mptscsih_abort);
3159EXPORT_SYMBOL(mptscsih_dev_reset);
3160EXPORT_SYMBOL(mptscsih_bus_reset);
3161EXPORT_SYMBOL(mptscsih_host_reset);
3162EXPORT_SYMBOL(mptscsih_bios_param);
3163EXPORT_SYMBOL(mptscsih_io_done);
3164EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3165EXPORT_SYMBOL(mptscsih_scandv_complete);
3166EXPORT_SYMBOL(mptscsih_event_process);
3167EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003168EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003169EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003171/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/