blob: cf1aba18a09fc349411d0637db4a3d5c44d53d13 [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;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302090 int i, j;
2091 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002092 int rc = 0;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302093 int num_paths;
Moore, Ericf44e5462006-03-14 09:14:21 -07002094
Eric Moore793955f2007-01-29 09:42:20 -07002095 if (!ioc->raid_data.pIocPg3)
2096 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002097 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002098 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2099 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2100 rc = 1;
2101 goto out;
2102 }
2103 }
2104
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302105 if (ioc->bus_type != SAS)
2106 goto out;
2107
2108 /*
2109 * Check if dual path
2110 */
2111 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2112 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2113 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2114 if (num_paths < 2)
2115 continue;
2116 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2117 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2118 if (!phys_disk)
2119 continue;
2120 if ((mpt_raid_phys_disk_pg1(ioc,
2121 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2122 phys_disk))) {
2123 kfree(phys_disk);
2124 continue;
2125 }
2126 for (j = 0; j < num_paths; j++) {
2127 if ((phys_disk->Path[j].Flags &
2128 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2129 continue;
2130 if ((phys_disk->Path[j].Flags &
2131 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2132 continue;
2133 if ((id == phys_disk->Path[j].PhysDiskID) &&
2134 (channel == phys_disk->Path[j].PhysDiskBus)) {
2135 rc = 1;
2136 kfree(phys_disk);
2137 goto out;
2138 }
2139 }
2140 kfree(phys_disk);
2141 }
2142
2143
Eric Mooreb506ade2007-01-29 09:45:37 -07002144 /*
2145 * Check inactive list for matching phys disks
2146 */
2147 if (list_empty(&ioc->raid_data.inactive_list))
2148 goto out;
2149
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002150 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002151 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2152 list) {
2153 if ((component_info->d.PhysDiskID == id) &&
2154 (component_info->d.PhysDiskBus == channel))
2155 rc = 1;
2156 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002157 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002158
Eric Moore793955f2007-01-29 09:42:20 -07002159 out:
2160 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002161}
2162EXPORT_SYMBOL(mptscsih_is_phys_disk);
2163
Eric Moore793955f2007-01-29 09:42:20 -07002164u8
2165mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002166{
Eric Mooreb506ade2007-01-29 09:45:37 -07002167 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302168 int i, j;
2169 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002170 int rc = -ENXIO;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302171 int num_paths;
James Bottomleyc92f2222006-03-01 09:02:49 -06002172
Eric Moore793955f2007-01-29 09:42:20 -07002173 if (!ioc->raid_data.pIocPg3)
2174 goto out;
2175 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2176 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2177 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2178 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2179 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002180 }
2181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302183 if (ioc->bus_type != SAS)
2184 goto out;
2185
2186 /*
2187 * Check if dual path
2188 */
2189 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2190 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2191 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2192 if (num_paths < 2)
2193 continue;
2194 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2195 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2196 if (!phys_disk)
2197 continue;
2198 if ((mpt_raid_phys_disk_pg1(ioc,
2199 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2200 phys_disk))) {
2201 kfree(phys_disk);
2202 continue;
2203 }
2204 for (j = 0; j < num_paths; j++) {
2205 if ((phys_disk->Path[j].Flags &
2206 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2207 continue;
2208 if ((phys_disk->Path[j].Flags &
2209 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2210 continue;
2211 if ((id == phys_disk->Path[j].PhysDiskID) &&
2212 (channel == phys_disk->Path[j].PhysDiskBus)) {
2213 rc = phys_disk->PhysDiskNum;
2214 kfree(phys_disk);
2215 goto out;
2216 }
2217 }
2218 kfree(phys_disk);
2219 }
2220
Eric Mooreb506ade2007-01-29 09:45:37 -07002221 /*
2222 * Check inactive list for matching phys disks
2223 */
2224 if (list_empty(&ioc->raid_data.inactive_list))
2225 goto out;
2226
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002227 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002228 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2229 list) {
2230 if ((component_info->d.PhysDiskID == id) &&
2231 (component_info->d.PhysDiskBus == channel))
2232 rc = component_info->d.PhysDiskNum;
2233 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002234 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002235
Eric Moore793955f2007-01-29 09:42:20 -07002236 out:
2237 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002238}
Eric Moore793955f2007-01-29 09:42:20 -07002239EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002240
2241/*
2242 * OS entry point to allow for host driver to free allocated memory
2243 * Called if no device present or device being unloaded
2244 */
2245void
2246mptscsih_slave_destroy(struct scsi_device *sdev)
2247{
2248 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002249 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002250 VirtTarget *vtarget;
2251 VirtDevice *vdevice;
2252 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002254 starget = scsi_target(sdev);
2255 vtarget = starget->hostdata;
2256 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002258 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002259 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002260 mptscsih_synchronize_cache(hd, vdevice);
2261 kfree(vdevice);
2262 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263}
2264
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002265/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2266/*
2267 * mptscsih_change_queue_depth - This function will set a devices queue depth
2268 * @sdev: per scsi_device pointer
2269 * @qdepth: requested queue depth
2270 *
2271 * Adding support for new 'change_queue_depth' api.
2272*/
2273int
2274mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002276 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002277 VirtTarget *vtarget;
2278 struct scsi_target *starget;
2279 int max_depth;
2280 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002281 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002283 starget = scsi_target(sdev);
2284 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002285
Eric Mooree80b0022007-09-14 18:49:03 -06002286 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002287 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002289 else if (sdev->type == TYPE_DISK &&
2290 vtarget->minSyncFactor <= MPT_ULTRA160)
2291 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2292 else
2293 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 } else
2295 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2296
2297 if (qdepth > max_depth)
2298 qdepth = max_depth;
2299 if (qdepth == 1)
2300 tagged = 0;
2301 else
2302 tagged = MSG_SIMPLE_TAG;
2303
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002304 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2305 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306}
2307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308/*
2309 * OS entry point to adjust the queue_depths on a per-device basis.
2310 * Called once per device the bus scan. Use it to force the queue_depth
2311 * member to 1 if a device does not support Q tags.
2312 * Return non-zero if fails.
2313 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002314int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002315mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002317 struct Scsi_Host *sh = sdev->host;
2318 VirtTarget *vtarget;
2319 VirtDevice *vdevice;
2320 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002321 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002322 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324 starget = scsi_target(sdev);
2325 vtarget = starget->hostdata;
2326 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
Eric Mooree80b0022007-09-14 18:49:03 -06002328 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002329 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002330 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2331 if (ioc->bus_type == SPI)
2332 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002333 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002334 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002335 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Eric Moore793955f2007-01-29 09:42:20 -07002337 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
Eric Mooree80b0022007-09-14 18:49:03 -06002339 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002341 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342
Eric Mooree80b0022007-09-14 18:49:03 -06002343 if (ioc->bus_type == SPI)
2344 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002345 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002346 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002347 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Kashyap, Desai2f187862009-05-29 16:52:37 +05302349 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Eric Mooree80b0022007-09-14 18:49:03 -06002350 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002352 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002353 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
2355 return 0;
2356}
2357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2359/*
2360 * Private routines...
2361 */
2362
2363/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2364/* Utility function to copy sense data from the scsi_cmnd buffer
2365 * to the FC and SCSI target structures.
2366 *
2367 */
2368static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002369mptscsih_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 -07002370{
Eric Moorea69de502007-09-14 18:48:19 -06002371 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 SCSIIORequest_t *pReq;
2373 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002374 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
2376 /* Get target structure
2377 */
2378 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002379 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
2381 if (sense_count) {
2382 u8 *sense_data;
2383 int req_index;
2384
2385 /* Copy the sense received into the scsi command block. */
2386 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002387 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2389
2390 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2391 */
Eric Mooree80b0022007-09-14 18:49:03 -06002392 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002393 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002396 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2398 ioc->events[idx].eventContext = ioc->eventContext;
2399
Dave Jones3d9780b2007-05-21 20:59:47 -04002400 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2401 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2402 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
Dave Jones3d9780b2007-05-21 20:59:47 -04002404 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002407 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002408 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002409 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002410 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2411 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002412 MPT_TARGET_FLAGS_LED_ON;
2413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 }
2415 }
2416 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002417 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2418 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 }
2420}
2421
Eric Mooree8206382007-09-29 10:16:53 -06002422
2423/**
2424 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002425 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002426 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002427 *
Kashyap, Desai2f187862009-05-29 16:52:37 +05302428 * @ioc: Pointer to MPT_ADAPTER structure
2429 * @i: index into the array
2430 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002431 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302432 *
Eric Mooree8206382007-09-29 10:16:53 -06002433 **/
2434static struct scsi_cmnd *
2435mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2436{
2437 unsigned long flags;
2438 struct scsi_cmnd *scmd;
2439
2440 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2441 scmd = ioc->ScsiLookup[i];
2442 ioc->ScsiLookup[i] = NULL;
2443 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2444
2445 return scmd;
2446}
2447
2448/**
2449 * mptscsih_set_scsi_lookup
2450 *
2451 * writes a scmd entry into the ScsiLookup[] array list
2452 *
2453 * @ioc: Pointer to MPT_ADAPTER structure
2454 * @i: index into the array
2455 * @scmd: scsi_cmnd pointer
2456 *
2457 **/
2458static void
2459mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2460{
2461 unsigned long flags;
2462
2463 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2464 ioc->ScsiLookup[i] = scmd;
2465 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2466}
2467
2468/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002469 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002470 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002471 * @sc: scsi_cmnd pointer
2472 */
Eric Mooree8206382007-09-29 10:16:53 -06002473static int
2474SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2475{
2476 unsigned long flags;
2477 int i, index=-1;
2478
2479 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2480 for (i = 0; i < ioc->req_depth; i++) {
2481 if (ioc->ScsiLookup[i] == sc) {
2482 index = i;
2483 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486
Eric Mooree8206382007-09-29 10:16:53 -06002487 out:
2488 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2489 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490}
2491
2492/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002493int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2495{
2496 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
Eric Mooree7eae9f2007-09-29 10:15:59 -06002498 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302501 hd = shost_priv(ioc->sh);
2502 switch (reset_phase) {
2503 case MPT_IOC_SETUP_RESET:
2504 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2505 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302506 break;
2507 case MPT_IOC_PRE_RESET:
2508 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2509 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302510 mptscsih_flush_running_cmds(hd);
2511 break;
2512 case MPT_IOC_POST_RESET:
2513 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2514 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2515 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2516 ioc->internal_cmds.status |=
2517 MPT_MGMT_STATUS_DID_IOCRESET;
2518 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302520 break;
2521 default:
2522 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 return 1; /* currently means nothing really */
2525}
2526
2527/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002528int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2530{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2532
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302533 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2534 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2535 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
Kashyap, Desai2f187862009-05-29 16:52:37 +05302537 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2538 event == MPI_EVENT_EXT_BUS_RESET) &&
2539 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2540 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
2542 return 1; /* currently means nothing really */
2543}
2544
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2546/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 * Bus Scan and Domain Validation functionality ...
2548 */
2549
2550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2551/*
2552 * mptscsih_scandv_complete - Scan and DV callback routine registered
2553 * to Fustion MPT (base) driver.
2554 *
2555 * @ioc: Pointer to MPT_ADAPTER structure
2556 * @mf: Pointer to original MPT request frame
2557 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2558 *
2559 * This routine is called from mpt.c::mpt_interrupt() at the completion
2560 * of any SCSI IO request.
2561 * This routine is registered with the Fusion MPT (base) driver at driver
2562 * load/init time via the mpt_register() API call.
2563 *
2564 * Returns 1 indicating alloc'd request frame ptr should be freed.
2565 *
2566 * Remark: Sets a completion code and (possibly) saves sense data
2567 * in the IOC member localReply structure.
2568 * Used ONLY for DV and other internal commands.
2569 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002570int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302571mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2572 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302575 SCSIIOReply_t *pReply;
2576 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302578 u8 *sense_data;
2579 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302581 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2582 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2583 if (!reply)
2584 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002585
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302586 pReply = (SCSIIOReply_t *) reply;
2587 pReq = (SCSIIORequest_t *) req;
2588 ioc->internal_cmds.completion_code =
2589 mptscsih_get_completion_code(ioc, req, reply);
2590 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2591 memcpy(ioc->internal_cmds.reply, reply,
2592 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2593 cmd = reply->u.hdr.Function;
2594 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2595 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2596 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2597 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2598 sense_data = ((u8 *)ioc->sense_buf_pool +
2599 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2600 sz = min_t(int, pReq->SenseBufferLength,
2601 MPT_SENSE_BUFFER_ALLOC);
2602 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302604 out:
2605 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2606 return 0;
2607 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2608 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 return 1;
2610}
2611
2612/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2613/* mptscsih_timer_expired - Call back for timer process.
2614 * Used only for dv functionality.
2615 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2616 *
2617 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002618void
2619mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620{
2621 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002622 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
Eric Mooree80b0022007-09-14 18:49:03 -06002624 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 if (hd->cmdPtr) {
2627 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2628
2629 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2630 /* Desire to issue a task management request here.
2631 * TM requests MUST be single threaded.
2632 * If old eh code and no TM current, issue request.
2633 * If new eh code, do nothing. Wait for OS cmd timeout
2634 * for bus reset.
2635 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 } else {
2637 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002638 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2639 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 }
2642 } else {
2643 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002644 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
2646
2647 /* No more processing.
2648 * TM call will generate an interrupt for SCSI TM Management.
2649 * The FW will reply to all outstanding commands, callback will finish cleanup.
2650 * Hard reset clean-up will free all resources.
2651 */
Eric Mooree80b0022007-09-14 18:49:03 -06002652 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
2654 return;
2655}
2656
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302657/**
2658 * mptscsih_get_completion_code -
2659 * @ioc: Pointer to MPT_ADAPTER structure
2660 * @reply:
2661 * @cmd:
2662 *
2663 **/
2664static int
2665mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2666 MPT_FRAME_HDR *reply)
2667{
2668 SCSIIOReply_t *pReply;
2669 MpiRaidActionReply_t *pr;
2670 u8 scsi_status;
2671 u16 status;
2672 int completion_code;
2673
2674 pReply = (SCSIIOReply_t *)reply;
2675 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2676 scsi_status = pReply->SCSIStatus;
2677
2678 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2679 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2680 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2681 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2682
2683 switch (status) {
2684
2685 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2686 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2687 break;
2688
2689 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2690 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2691 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2692 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2693 completion_code = MPT_SCANDV_DID_RESET;
2694 break;
2695
2696 case MPI_IOCSTATUS_BUSY:
2697 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2698 completion_code = MPT_SCANDV_BUSY;
2699 break;
2700
2701 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2702 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2703 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2704 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2705 completion_code = MPT_SCANDV_GOOD;
2706 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2707 pr = (MpiRaidActionReply_t *)reply;
2708 if (le16_to_cpu(pr->ActionStatus) ==
2709 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2710 completion_code = MPT_SCANDV_GOOD;
2711 else
2712 completion_code = MPT_SCANDV_SOME_ERROR;
2713 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2714 completion_code = MPT_SCANDV_SENSE;
2715 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2716 if (req->u.scsireq.CDB[0] == INQUIRY)
2717 completion_code = MPT_SCANDV_ISSUE_SENSE;
2718 else
2719 completion_code = MPT_SCANDV_DID_RESET;
2720 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2721 completion_code = MPT_SCANDV_DID_RESET;
2722 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2723 completion_code = MPT_SCANDV_DID_RESET;
2724 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2725 completion_code = MPT_SCANDV_BUSY;
2726 else
2727 completion_code = MPT_SCANDV_GOOD;
2728 break;
2729
2730 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2731 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2732 completion_code = MPT_SCANDV_DID_RESET;
2733 else
2734 completion_code = MPT_SCANDV_SOME_ERROR;
2735 break;
2736 default:
2737 completion_code = MPT_SCANDV_SOME_ERROR;
2738 break;
2739
2740 } /* switch(status) */
2741
2742 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2743 " completionCode set to %08xh\n", ioc->name, completion_code));
2744 return completion_code;
2745}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
2747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2748/**
2749 * mptscsih_do_cmd - Do internal command.
2750 * @hd: MPT_SCSI_HOST pointer
2751 * @io: INTERNAL_CMD pointer.
2752 *
2753 * Issue the specified internally generated command and do command
2754 * specific cleanup. For bus scan / DV only.
2755 * NOTES: If command is Inquiry and status is good,
2756 * initialize a target structure, save the data
2757 *
2758 * Remark: Single threaded access only.
2759 *
2760 * Return:
2761 * < 0 if an illegal command or no resources
2762 *
2763 * 0 if good
2764 *
2765 * > 0 if command complete but some type of completion error.
2766 */
2767static int
2768mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2769{
2770 MPT_FRAME_HDR *mf;
2771 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302773 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 char cmdLen;
2775 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 +05302776 u8 cmd = io->cmd;
2777 MPT_ADAPTER *ioc = hd->ioc;
2778 int ret = 0;
2779 unsigned long timeleft;
2780 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302782 /* don't send internal command during diag reset */
2783 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2784 if (ioc->ioc_reset_in_progress) {
2785 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2786 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2787 "%s: busy with host reset\n", ioc->name, __func__));
2788 return MPT_SCANDV_BUSY;
2789 }
2790 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2791
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302792 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
2794 /* Set command specific information
2795 */
2796 switch (cmd) {
2797 case INQUIRY:
2798 cmdLen = 6;
2799 dir = MPI_SCSIIO_CONTROL_READ;
2800 CDB[0] = cmd;
2801 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302802 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 break;
2804
2805 case TEST_UNIT_READY:
2806 cmdLen = 6;
2807 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302808 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 break;
2810
2811 case START_STOP:
2812 cmdLen = 6;
2813 dir = MPI_SCSIIO_CONTROL_READ;
2814 CDB[0] = cmd;
2815 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302816 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 break;
2818
2819 case REQUEST_SENSE:
2820 cmdLen = 6;
2821 CDB[0] = cmd;
2822 CDB[4] = io->size;
2823 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302824 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 break;
2826
2827 case READ_BUFFER:
2828 cmdLen = 10;
2829 dir = MPI_SCSIIO_CONTROL_READ;
2830 CDB[0] = cmd;
2831 if (io->flags & MPT_ICFLAG_ECHO) {
2832 CDB[1] = 0x0A;
2833 } else {
2834 CDB[1] = 0x02;
2835 }
2836
2837 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2838 CDB[1] |= 0x01;
2839 }
2840 CDB[6] = (io->size >> 16) & 0xFF;
2841 CDB[7] = (io->size >> 8) & 0xFF;
2842 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302843 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 break;
2845
2846 case WRITE_BUFFER:
2847 cmdLen = 10;
2848 dir = MPI_SCSIIO_CONTROL_WRITE;
2849 CDB[0] = cmd;
2850 if (io->flags & MPT_ICFLAG_ECHO) {
2851 CDB[1] = 0x0A;
2852 } else {
2853 CDB[1] = 0x02;
2854 }
2855 CDB[6] = (io->size >> 16) & 0xFF;
2856 CDB[7] = (io->size >> 8) & 0xFF;
2857 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302858 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 break;
2860
2861 case RESERVE:
2862 cmdLen = 6;
2863 dir = MPI_SCSIIO_CONTROL_READ;
2864 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302865 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 break;
2867
2868 case RELEASE:
2869 cmdLen = 6;
2870 dir = MPI_SCSIIO_CONTROL_READ;
2871 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302872 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 break;
2874
2875 case SYNCHRONIZE_CACHE:
2876 cmdLen = 10;
2877 dir = MPI_SCSIIO_CONTROL_READ;
2878 CDB[0] = cmd;
2879// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302880 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 break;
2882
2883 default:
2884 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302885 ret = -EFAULT;
2886 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 }
2888
2889 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302890 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 */
Eric Mooree80b0022007-09-14 18:49:03 -06002892 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302893 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2894 ioc->name, __func__));
2895 ret = MPT_SCANDV_BUSY;
2896 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 }
2898
2899 pScsiReq = (SCSIIORequest_t *) mf;
2900
2901 /* Get the request index */
2902 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2903 ADD_INDEX_LOG(my_idx); /* for debug */
2904
2905 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2906 pScsiReq->TargetID = io->physDiskNum;
2907 pScsiReq->Bus = 0;
2908 pScsiReq->ChainOffset = 0;
2909 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2910 } else {
2911 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002912 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 pScsiReq->ChainOffset = 0;
2914 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2915 }
2916
2917 pScsiReq->CDBLength = cmdLen;
2918 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2919
2920 pScsiReq->Reserved = 0;
2921
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302922 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 /* MsgContext set in mpt_get_msg_fram call */
2924
Eric Moore793955f2007-01-29 09:42:20 -07002925 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
2927 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2928 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2929 else
2930 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2931
2932 if (cmd == REQUEST_SENSE) {
2933 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302934 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2935 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 }
2937
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302938 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 pScsiReq->CDB[ii] = CDB[ii];
2940
2941 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06002942 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
2944
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302945 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2946 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
2947 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302949 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302950 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302951 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
2952 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302953 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302954 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302956 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06002957 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302958 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
2959 timeout*HZ);
2960 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2961 ret = MPT_SCANDV_DID_RESET;
2962 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2963 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
2964 cmd));
2965 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
2966 mpt_free_msg_frame(ioc, mf);
2967 goto out;
2968 }
2969 if (!timeleft) {
2970 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
2971 ioc->name, __func__);
2972 mpt_HardResetHandler(ioc, CAN_SLEEP);
2973 mpt_free_msg_frame(ioc, mf);
2974 }
2975 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
2977
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302978 ret = ioc->internal_cmds.completion_code;
2979 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
2980 ioc->name, __func__, ret));
2981
2982 out:
2983 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
2984 mutex_unlock(&ioc->internal_cmds.mutex);
2985 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986}
2987
2988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2989/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002990 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
2991 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002992 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002993 *
2994 * Uses the ISR, but with special processing.
2995 * MUST be single-threaded.
2996 *
2997 */
2998static void
2999mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3000{
3001 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
Eric Moorecc78d302007-06-15 17:27:21 -06003003 /* Ignore hidden raid components, this is handled when the command
3004 * is sent to the volume
3005 */
3006 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3007 return;
3008
3009 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3010 !vdevice->configured_lun)
3011 return;
3012
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 /* Following parameters will not change
3014 * in this routine.
3015 */
3016 iocmd.cmd = SYNCHRONIZE_CACHE;
3017 iocmd.flags = 0;
3018 iocmd.physDiskNum = -1;
3019 iocmd.data = NULL;
3020 iocmd.data_dma = -1;
3021 iocmd.size = 0;
3022 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003023 iocmd.channel = vdevice->vtarget->channel;
3024 iocmd.id = vdevice->vtarget->id;
3025 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Eric Moorecc78d302007-06-15 17:27:21 -06003027 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028}
3029
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303030static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003031mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3032 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303033{
Tony Jonesee959b02008-02-22 00:13:36 +01003034 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003035 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303036 MPT_ADAPTER *ioc = hd->ioc;
3037
3038 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3039 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3040 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3041 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3042 ioc->facts.FWVersion.Word & 0x000000FF);
3043}
Tony Jonesee959b02008-02-22 00:13:36 +01003044static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303045
3046static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003047mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3048 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303049{
Tony Jonesee959b02008-02-22 00:13:36 +01003050 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003051 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303052 MPT_ADAPTER *ioc = hd->ioc;
3053
3054 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3055 (ioc->biosVersion & 0xFF000000) >> 24,
3056 (ioc->biosVersion & 0x00FF0000) >> 16,
3057 (ioc->biosVersion & 0x0000FF00) >> 8,
3058 ioc->biosVersion & 0x000000FF);
3059}
Tony Jonesee959b02008-02-22 00:13:36 +01003060static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303061
3062static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003063mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3064 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303065{
Tony Jonesee959b02008-02-22 00:13:36 +01003066 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003067 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303068 MPT_ADAPTER *ioc = hd->ioc;
3069
3070 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3071}
Tony Jonesee959b02008-02-22 00:13:36 +01003072static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303073
3074static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003075mptscsih_version_product_show(struct device *dev,
3076 struct device_attribute *attr,
3077char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303078{
Tony Jonesee959b02008-02-22 00:13:36 +01003079 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003080 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303081 MPT_ADAPTER *ioc = hd->ioc;
3082
3083 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3084}
Tony Jonesee959b02008-02-22 00:13:36 +01003085static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303086 mptscsih_version_product_show, NULL);
3087
3088static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003089mptscsih_version_nvdata_persistent_show(struct device *dev,
3090 struct device_attribute *attr,
3091 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303092{
Tony Jonesee959b02008-02-22 00:13:36 +01003093 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003094 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303095 MPT_ADAPTER *ioc = hd->ioc;
3096
3097 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3098 ioc->nvdata_version_persistent);
3099}
Tony Jonesee959b02008-02-22 00:13:36 +01003100static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303101 mptscsih_version_nvdata_persistent_show, NULL);
3102
3103static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003104mptscsih_version_nvdata_default_show(struct device *dev,
3105 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303106{
Tony Jonesee959b02008-02-22 00:13:36 +01003107 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003108 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303109 MPT_ADAPTER *ioc = hd->ioc;
3110
3111 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3112}
Tony Jonesee959b02008-02-22 00:13:36 +01003113static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303114 mptscsih_version_nvdata_default_show, NULL);
3115
3116static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003117mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3118 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303119{
Tony Jonesee959b02008-02-22 00:13:36 +01003120 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003121 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303122 MPT_ADAPTER *ioc = hd->ioc;
3123
3124 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3125}
Tony Jonesee959b02008-02-22 00:13:36 +01003126static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303127
3128static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003129mptscsih_board_assembly_show(struct device *dev,
3130 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303131{
Tony Jonesee959b02008-02-22 00:13:36 +01003132 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003133 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303134 MPT_ADAPTER *ioc = hd->ioc;
3135
3136 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3137}
Tony Jonesee959b02008-02-22 00:13:36 +01003138static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303139 mptscsih_board_assembly_show, NULL);
3140
3141static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003142mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3143 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303144{
Tony Jonesee959b02008-02-22 00:13:36 +01003145 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003146 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303147 MPT_ADAPTER *ioc = hd->ioc;
3148
3149 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3150}
Tony Jonesee959b02008-02-22 00:13:36 +01003151static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303152 mptscsih_board_tracer_show, NULL);
3153
3154static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003155mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3156 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303157{
Tony Jonesee959b02008-02-22 00:13:36 +01003158 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003159 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303160 MPT_ADAPTER *ioc = hd->ioc;
3161
3162 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3163}
Tony Jonesee959b02008-02-22 00:13:36 +01003164static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303165 mptscsih_io_delay_show, NULL);
3166
3167static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003168mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3169 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303170{
Tony Jonesee959b02008-02-22 00:13:36 +01003171 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003172 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303173 MPT_ADAPTER *ioc = hd->ioc;
3174
3175 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3176}
Tony Jonesee959b02008-02-22 00:13:36 +01003177static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303178 mptscsih_device_delay_show, NULL);
3179
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303180static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003181mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3182 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303183{
Tony Jonesee959b02008-02-22 00:13:36 +01003184 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003185 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303186 MPT_ADAPTER *ioc = hd->ioc;
3187
3188 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3189}
3190static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003191mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3192 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303193{
Tony Jonesee959b02008-02-22 00:13:36 +01003194 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003195 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303196 MPT_ADAPTER *ioc = hd->ioc;
3197 int val = 0;
3198
3199 if (sscanf(buf, "%x", &val) != 1)
3200 return -EINVAL;
3201
3202 ioc->debug_level = val;
3203 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3204 ioc->name, ioc->debug_level);
3205 return strlen(buf);
3206}
Tony Jonesee959b02008-02-22 00:13:36 +01003207static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3208 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303209
Tony Jonesee959b02008-02-22 00:13:36 +01003210struct device_attribute *mptscsih_host_attrs[] = {
3211 &dev_attr_version_fw,
3212 &dev_attr_version_bios,
3213 &dev_attr_version_mpi,
3214 &dev_attr_version_product,
3215 &dev_attr_version_nvdata_persistent,
3216 &dev_attr_version_nvdata_default,
3217 &dev_attr_board_name,
3218 &dev_attr_board_assembly,
3219 &dev_attr_board_tracer,
3220 &dev_attr_io_delay,
3221 &dev_attr_device_delay,
3222 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303223 NULL,
3224};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303225
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303226EXPORT_SYMBOL(mptscsih_host_attrs);
3227
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003228EXPORT_SYMBOL(mptscsih_remove);
3229EXPORT_SYMBOL(mptscsih_shutdown);
3230#ifdef CONFIG_PM
3231EXPORT_SYMBOL(mptscsih_suspend);
3232EXPORT_SYMBOL(mptscsih_resume);
3233#endif
3234EXPORT_SYMBOL(mptscsih_proc_info);
3235EXPORT_SYMBOL(mptscsih_info);
3236EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003237EXPORT_SYMBOL(mptscsih_slave_destroy);
3238EXPORT_SYMBOL(mptscsih_slave_configure);
3239EXPORT_SYMBOL(mptscsih_abort);
3240EXPORT_SYMBOL(mptscsih_dev_reset);
3241EXPORT_SYMBOL(mptscsih_bus_reset);
3242EXPORT_SYMBOL(mptscsih_host_reset);
3243EXPORT_SYMBOL(mptscsih_bios_param);
3244EXPORT_SYMBOL(mptscsih_io_done);
3245EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3246EXPORT_SYMBOL(mptscsih_scandv_complete);
3247EXPORT_SYMBOL(mptscsih_event_process);
3248EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003249EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003250EXPORT_SYMBOL(mptscsih_timer_expired);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/