blob: 6796597dcee0c122be63e927f19ff85f49e796e4 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090049#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/workqueue.h>
58
59#include <scsi/scsi.h>
60#include <scsi/scsi_cmnd.h>
61#include <scsi/scsi_device.h>
62#include <scsi/scsi_host.h>
63#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060064#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
67#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060068#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT SCSI Host driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptscsih"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*
82 * Other private/forward protos...
83 */
Kashyap, Desaidb7051b2009-05-29 16:56:59 +053084struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
Eric Mooree8206382007-09-29 10:16:53 -060085static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
86static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
87static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040088int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040090int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
93 SCSIIORequest_t *pReq, int req_idx);
94static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040095static 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 -070096
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +053097int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
98 int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400100int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
101int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530103void
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530104mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530105static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
106 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400107int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700109static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530111static int
112mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
113 SCSITaskMgmtReply_t *pScsiTmReply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400114void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700115void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400117int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
118int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#endif
120
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900121#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * mptscsih_getFreeChainBuffer - Function to get a free chain
127 * from the MPT_SCSI_HOST FreeChainQ.
128 * @ioc: Pointer to MPT_ADAPTER structure
129 * @req_idx: Index of the SCSI IO request frame. (output)
130 *
131 * return SUCCESS or FAILED
132 */
133static inline int
134mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
135{
136 MPT_FRAME_HDR *chainBuf;
137 unsigned long flags;
138 int rc;
139 int chain_idx;
140
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530141 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600142 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 spin_lock_irqsave(&ioc->FreeQlock, flags);
144 if (!list_empty(&ioc->FreeChainQ)) {
145 int offset;
146
147 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
148 u.frame.linkage.list);
149 list_del(&chainBuf->u.frame.linkage.list);
150 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
151 chain_idx = offset / ioc->req_sz;
152 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600153 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
154 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
155 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 } else {
157 rc = FAILED;
158 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600159 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
160 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
162 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
163
164 *retIndex = chain_idx;
165 return rc;
166} /* mptscsih_getFreeChainBuffer() */
167
168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
169/*
170 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
171 * SCSIIORequest_t Message Frame.
172 * @ioc: Pointer to MPT_ADAPTER structure
173 * @SCpnt: Pointer to scsi_cmnd structure
174 * @pReq: Pointer to SCSIIORequest_t structure
175 *
176 * Returns ...
177 */
178static int
179mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
180 SCSIIORequest_t *pReq, int req_idx)
181{
182 char *psge;
183 char *chainSge;
184 struct scatterlist *sg;
185 int frm_sz;
186 int sges_left, sg_done;
187 int chain_idx = MPT_HOST_NO_CHAIN;
188 int sgeOffset;
189 int numSgeSlots, numSgeThisFrame;
190 u32 sgflags, sgdir, thisxfer = 0;
191 int chain_dma_off = 0;
192 int newIndex;
193 int ii;
194 dma_addr_t v2;
195 u32 RequestNB;
196
197 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
198 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
199 sgdir = MPT_TRANSFER_HOST_TO_IOC;
200 } else {
201 sgdir = MPT_TRANSFER_IOC_TO_HOST;
202 }
203
204 psge = (char *) &pReq->SGL;
205 frm_sz = ioc->req_sz;
206
207 /* Map the data portion, if any.
208 * sges_left = 0 if no data transfer.
209 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900210 sges_left = scsi_dma_map(SCpnt);
211 if (sges_left < 0)
212 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214 /* Handle the SG case.
215 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900216 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 sg_done = 0;
218 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
219 chainSge = NULL;
220
221 /* Prior to entering this loop - the following must be set
222 * current MF: sgeOffset (bytes)
223 * chainSge (Null if original MF is not a chain buffer)
224 * sg_done (num SGE done for this MF)
225 */
226
227nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530228 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
230
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530231 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 /* Get first (num - 1) SG elements
234 * Skip any SG entries with a length of 0
235 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
236 */
237 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
238 thisxfer = sg_dma_len(sg);
239 if (thisxfer == 0) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530240 /* Get next SG element from the OS */
241 sg = sg_next(sg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 sg_done++;
243 continue;
244 }
245
246 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530247 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Kashyap, Desai2f187862009-05-29 16:52:37 +0530249 /* Get next SG element from the OS */
250 sg = sg_next(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530251 psge += ioc->SGE_size;
252 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 sg_done++;
254 }
255
256 if (numSgeThisFrame == sges_left) {
257 /* Add last element, end of buffer and end of list flags.
258 */
259 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
260 MPT_SGE_FLAGS_END_OF_BUFFER |
261 MPT_SGE_FLAGS_END_OF_LIST;
262
263 /* Add last SGE and set termination flags.
264 * Note: Last SGE may have a length of 0 - which should be ok.
265 */
266 thisxfer = sg_dma_len(sg);
267
268 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530269 ioc->add_sge(psge, sgflags | thisxfer, v2);
270 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sg_done++;
272
273 if (chainSge) {
274 /* The current buffer is a chain buffer,
275 * but there is not another one.
276 * Update the chain element
277 * Offset and Length fields.
278 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530279 ioc->add_chain((char *)chainSge, 0, sgeOffset,
280 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 } else {
282 /* The current buffer is the original MF
283 * and there is no Chain buffer.
284 */
285 pReq->ChainOffset = 0;
286 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530287 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
289 ioc->RequestNB[req_idx] = RequestNB;
290 }
291 } else {
292 /* At least one chain buffer is needed.
293 * Complete the first MF
294 * - last SGE element, set the LastElement bit
295 * - set ChainOffset (words) for orig MF
296 * (OR finish previous MF chain buffer)
297 * - update MFStructPtr ChainIndex
298 * - Populate chain element
299 * Also
300 * Loop until done.
301 */
302
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530303 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 ioc->name, sg_done));
305
306 /* Set LAST_ELEMENT flag for last non-chain element
307 * in the buffer. Since psge points at the NEXT
308 * SGE element, go back one SGE element, update the flags
309 * and reset the pointer. (Note: sgflags & thisxfer are already
310 * set properly).
311 */
312 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530313 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 sgflags = le32_to_cpu(*ptmp);
315 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
316 *ptmp = cpu_to_le32(sgflags);
317 }
318
319 if (chainSge) {
320 /* The current buffer is a chain buffer.
321 * chainSge points to the previous Chain Element.
322 * Update its chain element Offset and Length (must
323 * include chain element size) fields.
324 * Old chain element is now complete.
325 */
326 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530327 sgeOffset += ioc->SGE_size;
328 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
329 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 } else {
331 /* The original MF buffer requires a chain buffer -
332 * set the offset.
333 * Last element in this MF is a chain element.
334 */
335 pReq->ChainOffset = (u8) (sgeOffset >> 2);
336 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530337 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 -0700338 ioc->RequestNB[req_idx] = RequestNB;
339 }
340
341 sges_left -= sg_done;
342
343
344 /* NOTE: psge points to the beginning of the chain element
345 * in current buffer. Get a chain buffer.
346 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200347 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530348 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200349 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
350 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 /* Update the tracking arrays.
355 * If chainSge == NULL, update ReqToChain, else ChainToChain
356 */
357 if (chainSge) {
358 ioc->ChainToChain[chain_idx] = newIndex;
359 } else {
360 ioc->ReqToChain[req_idx] = newIndex;
361 }
362 chain_idx = newIndex;
363 chain_dma_off = ioc->req_sz * chain_idx;
364
365 /* Populate the chainSGE for the current buffer.
366 * - Set chain buffer pointer to psge and fill
367 * out the Address and Flags fields.
368 */
369 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600370 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
371 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 /* Start the SGE for the next buffer
374 */
375 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
376 sgeOffset = 0;
377 sg_done = 0;
378
Eric Moore29dd3602007-09-14 18:46:51 -0600379 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
380 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
382 /* Start the SGE for the next buffer
383 */
384
385 goto nextSGEset;
386 }
387
388 return SUCCESS;
389} /* mptscsih_AddSGE() */
390
Eric Moore786899b2006-07-11 17:22:22 -0600391static void
392mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
393 U32 SlotStatus)
394{
395 MPT_FRAME_HDR *mf;
396 SEPRequest_t *SEPMsg;
397
Eric Moorecc78d302007-06-15 17:27:21 -0600398 if (ioc->bus_type != SAS)
399 return;
400
401 /* Not supported for hidden raid components
402 */
403 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600404 return;
405
406 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530407 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700408 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600409 return;
410 }
411
412 SEPMsg = (SEPRequest_t *)mf;
413 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700414 SEPMsg->Bus = vtarget->channel;
415 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600416 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
417 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530418 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700419 "Sending SEP cmd=%x channel=%d id=%d\n",
420 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600421 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
422}
423
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530424#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700425/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530426 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700427 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700428 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530429 * @pScsiReply: Pointer to MPT reply frame
430 *
431 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700432 *
433 * Refer to lsi/mpi.h.
434 **/
435static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530436mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700437{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530438 char *desc = NULL;
439 char *desc1 = NULL;
440 u16 ioc_status;
441 u8 skey, asc, ascq;
442
443 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700444
445 switch (ioc_status) {
446
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530447 case MPI_IOCSTATUS_SUCCESS:
448 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700449 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530450 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
451 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700452 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530453 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
454 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700455 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530456 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
457 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700458 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530459 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
460 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700461 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530462 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
463 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700464 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530465 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
466 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700467 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530468 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
469 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700470 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530471 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
472 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700473 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530474 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
475 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700476 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530477 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
478 desc = "task management failed";
479 break;
480 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
481 desc = "IOC terminated";
482 break;
483 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
484 desc = "ext terminated";
485 break;
486 default:
487 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700488 break;
489 }
490
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530491 switch (pScsiReply->SCSIStatus)
492 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700493
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530494 case MPI_SCSI_STATUS_SUCCESS:
495 desc1 = "success";
496 break;
497 case MPI_SCSI_STATUS_CHECK_CONDITION:
498 desc1 = "check condition";
499 break;
500 case MPI_SCSI_STATUS_CONDITION_MET:
501 desc1 = "condition met";
502 break;
503 case MPI_SCSI_STATUS_BUSY:
504 desc1 = "busy";
505 break;
506 case MPI_SCSI_STATUS_INTERMEDIATE:
507 desc1 = "intermediate";
508 break;
509 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
510 desc1 = "intermediate condmet";
511 break;
512 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
513 desc1 = "reservation conflict";
514 break;
515 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
516 desc1 = "command terminated";
517 break;
518 case MPI_SCSI_STATUS_TASK_SET_FULL:
519 desc1 = "task set full";
520 break;
521 case MPI_SCSI_STATUS_ACA_ACTIVE:
522 desc1 = "aca active";
523 break;
524 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
525 desc1 = "fcpext device logged out";
526 break;
527 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
528 desc1 = "fcpext no link";
529 break;
530 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
531 desc1 = "fcpext unassigned";
532 break;
533 default:
534 desc1 = "";
535 break;
536 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700537
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530538 scsi_print_command(sc);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530539 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
540 ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
Eric Moore29dd3602007-09-14 18:46:51 -0600541 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
542 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
543 scsi_get_resid(sc));
544 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
545 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530546 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530547
Eric Moore29dd3602007-09-14 18:46:51 -0600548 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530549 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600550 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530551 pScsiReply->SCSIState);
552
553 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
554 skey = sc->sense_buffer[2] & 0x0F;
555 asc = sc->sense_buffer[12];
556 ascq = sc->sense_buffer[13];
557
Eric Moore29dd3602007-09-14 18:46:51 -0600558 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
559 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530560 }
561
562 /*
563 * Look for + dump FCP ResponseInfo[]!
564 */
565 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
566 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600567 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
568 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700569}
570#endif
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
573/*
574 * mptscsih_io_done - Main SCSI IO callback routine registered to
575 * Fusion MPT (base) driver
576 * @ioc: Pointer to MPT_ADAPTER structure
577 * @mf: Pointer to original MPT request frame
578 * @r: Pointer to MPT reply frame (NULL if TurboReply)
579 *
580 * This routine is called from mpt.c::mpt_interrupt() at the completion
581 * of any SCSI IO request.
582 * This routine is registered with the Fusion MPT (base) driver at driver
583 * load/init time via the mpt_register() API call.
584 *
585 * Returns 1 indicating alloc'd request frame ptr should be freed.
586 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400587int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
589{
590 struct scsi_cmnd *sc;
591 MPT_SCSI_HOST *hd;
592 SCSIIORequest_t *pScsiReq;
593 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700594 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600595 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600596 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Eric Mooree7eae9f2007-09-29 10:15:59 -0600598 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700600 req_idx_MR = (mr != NULL) ?
601 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
Kashyap, Desai2f187862009-05-29 16:52:37 +0530602
603 /* Special case, where already freed message frame is received from
604 * Firmware. It happens with Resetting IOC.
605 * Return immediately. Do not care
606 */
Moore, Eric2254c862006-01-17 17:06:29 -0700607 if ((req_idx != req_idx_MR) ||
Kashyap, Desai2f187862009-05-29 16:52:37 +0530608 (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
Moore, Eric2254c862006-01-17 17:06:29 -0700609 return 0;
Moore, Eric2254c862006-01-17 17:06:29 -0700610
Eric Mooree8206382007-09-29 10:16:53 -0600611 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (sc == NULL) {
613 MPIHeader_t *hdr = (MPIHeader_t *)mf;
614
615 /* Remark: writeSDP1 will use the ScsiDoneCtx
616 * If a SCSI I/O cmd, device disabled by OS and
617 * completion done. Cannot touch sc struct. Just free mem.
618 */
619 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
620 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
621 ioc->name);
622
623 mptscsih_freeChainBuffers(ioc, req_idx);
624 return 1;
625 }
626
Eric Moore3dc0b032006-07-11 17:32:33 -0600627 if ((unsigned char *)mf != sc->host_scribble) {
628 mptscsih_freeChainBuffers(ioc, req_idx);
629 return 1;
630 }
631
Kashyap, Desaifea98402009-09-02 11:45:53 +0530632 if (ioc->bus_type == SAS) {
633 VirtDevice *vdevice = sc->device->hostdata;
634
635 if (!vdevice || !vdevice->vtarget ||
636 vdevice->vtarget->deleted) {
637 sc->result = DID_NO_CONNECT << 16;
638 goto out;
639 }
640 }
641
Eric Moore3dc0b032006-07-11 17:32:33 -0600642 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sc->result = DID_OK << 16; /* Set default reply as OK */
644 pScsiReq = (SCSIIORequest_t *) mf;
645 pScsiReply = (SCSIIOReply_t *) mr;
646
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200647 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530648 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200649 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
650 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
651 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530652 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200653 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
654 ioc->name, mf, mr, sc, req_idx));
655 }
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (pScsiReply == NULL) {
658 /* special context reply handling */
659 ;
660 } else {
661 u32 xfer_cnt;
662 u16 status;
663 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700664 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
667 scsi_state = pScsiReply->SCSIState;
668 scsi_status = pScsiReply->SCSIStatus;
669 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900670 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700671 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600673 /*
674 * if we get a data underrun indication, yet no data was
675 * transferred and the SCSI status indicates that the
676 * command was never started, change the data underrun
677 * to success
678 */
679 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
680 (scsi_status == MPI_SCSI_STATUS_BUSY ||
681 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
682 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
683 status = MPI_IOCSTATUS_SUCCESS;
684 }
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400687 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 /*
690 * Look for + dump FCP ResponseInfo[]!
691 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600692 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
693 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600694 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
695 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700696 sc->device->host->host_no, sc->device->channel,
697 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 le32_to_cpu(pScsiReply->ResponseInfo));
699 }
700
701 switch(status) {
702 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
Kashyap, Desaid23321b2009-08-05 12:51:25 +0530703 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 /* CHECKME!
705 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
706 * But not: DID_BUS_BUSY lest one risk
707 * killing interrupt handler:-(
708 */
709 sc->result = SAM_STAT_BUSY;
710 break;
711
712 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
713 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
714 sc->result = DID_BAD_TARGET << 16;
715 break;
716
717 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
718 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600719 if (ioc->bus_type != FC)
720 sc->result = DID_NO_CONNECT << 16;
721 /* else fibre, just stall until rescan event */
722 else
723 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
726 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600727
Eric Moorea69de502007-09-14 18:48:19 -0600728 vdevice = sc->device->hostdata;
729 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600730 break;
Eric Moorea69de502007-09-14 18:48:19 -0600731 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600732 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
733 mptscsih_issue_sep_command(ioc, vtarget,
734 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
735 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 break;
738
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600740 if ( ioc->bus_type == SAS ) {
741 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
742 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700743 if ((log_info & SAS_LOGINFO_MASK)
744 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600745 sc->result = (DID_BUS_BUSY << 16);
746 break;
747 }
748 }
Eric Moore86dd4242007-01-04 20:44:01 -0700749 } else if (ioc->bus_type == FC) {
750 /*
751 * The FC IOC may kill a request for variety of
752 * reasons, some of which may be recovered by a
753 * retry, some which are unlikely to be
754 * recovered. Return DID_ERROR instead of
755 * DID_RESET to permit retry of the command,
756 * just not an infinite number of them
757 */
758 sc->result = DID_ERROR << 16;
759 break;
Eric Moorebf451522006-07-11 17:25:35 -0600760 }
761
762 /*
763 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
764 */
765
766 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 /* Linux handles an unsolicited DID_RESET better
768 * than an unsolicited DID_ABORT.
769 */
770 sc->result = DID_RESET << 16;
771
Kashyap, Desai2f187862009-05-29 16:52:37 +0530772 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
773 if (ioc->bus_type == FC)
774 sc->result = DID_ERROR << 16;
775 else
776 sc->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 break;
778
779 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900780 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600781 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
782 sc->result=DID_SOFT_ERROR << 16;
783 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600785 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700786 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600787 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
791 /*
792 * Do upfront check for valid SenseData and give it
793 * precedence!
794 */
795 sc->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530796 if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
797
798 /*
799 * For an Errata on LSI53C1030
800 * When the length of request data
801 * and transfer data are different
802 * with result of command (READ or VERIFY),
803 * DID_SOFT_ERROR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 */
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530805 if (ioc->bus_type == SPI) {
806 if (pScsiReq->CDB[0] == READ_6 ||
807 pScsiReq->CDB[0] == READ_10 ||
808 pScsiReq->CDB[0] == READ_12 ||
809 pScsiReq->CDB[0] == READ_16 ||
810 pScsiReq->CDB[0] == VERIFY ||
811 pScsiReq->CDB[0] == VERIFY_16) {
812 if (scsi_bufflen(sc) !=
813 xfer_cnt) {
814 sc->result =
815 DID_SOFT_ERROR << 16;
816 printk(KERN_WARNING "Errata"
817 "on LSI53C1030 occurred."
818 "sc->req_bufflen=0x%02x,"
819 "xfer_cnt=0x%02x\n",
820 scsi_bufflen(sc),
821 xfer_cnt);
822 }
823 }
824 }
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600827 if (scsi_status == SAM_STAT_BUSY)
828 sc->result = SAM_STAT_BUSY;
829 else
830 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
833 /* What to do?
834 */
835 sc->result = DID_SOFT_ERROR << 16;
836 }
837 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
838 /* Not real sure here either... */
839 sc->result = DID_RESET << 16;
840 }
841 }
842
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530843
Eric Moore29dd3602007-09-14 18:46:51 -0600844 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
845 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
846 ioc->name, sc->underflow));
847 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
848 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* Report Queue Full
851 */
852 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
853 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 break;
856
Moore, Eric7e551472006-01-16 18:53:21 -0700857 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900858 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
860 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600861 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (scsi_state == 0) {
863 ;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530864 } else if (scsi_state &
865 MPI_SCSI_STATE_AUTOSENSE_VALID) {
866
867 /*
868 * For potential trouble on LSI53C1030.
869 * (date:2007.xx.)
870 * It is checked whether the length of
871 * request data is equal to
872 * the length of transfer and residual.
873 * MEDIUM_ERROR is set by incorrect data.
874 */
875 if ((ioc->bus_type == SPI) &&
876 (sc->sense_buffer[2] & 0x20)) {
877 u32 difftransfer;
878 difftransfer =
879 sc->sense_buffer[3] << 24 |
880 sc->sense_buffer[4] << 16 |
881 sc->sense_buffer[5] << 8 |
882 sc->sense_buffer[6];
883 if (((sc->sense_buffer[3] & 0x80) ==
884 0x80) && (scsi_bufflen(sc)
885 != xfer_cnt)) {
886 sc->sense_buffer[2] =
887 MEDIUM_ERROR;
888 sc->sense_buffer[12] = 0xff;
889 sc->sense_buffer[13] = 0xff;
890 printk(KERN_WARNING"Errata"
891 "on LSI53C1030 occurred."
892 "sc->req_bufflen=0x%02x,"
893 "xfer_cnt=0x%02x\n" ,
894 scsi_bufflen(sc),
895 xfer_cnt);
896 }
897 if (((sc->sense_buffer[3] & 0x80)
898 != 0x80) &&
899 (scsi_bufflen(sc) !=
900 xfer_cnt + difftransfer)) {
901 sc->sense_buffer[2] =
902 MEDIUM_ERROR;
903 sc->sense_buffer[12] = 0xff;
904 sc->sense_buffer[13] = 0xff;
905 printk(KERN_WARNING
906 "Errata on LSI53C1030 occurred"
907 "sc->req_bufflen=0x%02x,"
908 " xfer_cnt=0x%02x,"
909 "difftransfer=0x%02x\n",
910 scsi_bufflen(sc),
911 xfer_cnt,
912 difftransfer);
913 }
914 }
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 /*
917 * If running against circa 200003dd 909 MPT f/w,
918 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
919 * (QUEUE_FULL) returned from device! --> get 0x0000?128
920 * and with SenseBytes set to 0.
921 */
922 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
923 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
924
925 }
926 else if (scsi_state &
927 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
928 ) {
929 /*
930 * What to do?
931 */
932 sc->result = DID_SOFT_ERROR << 16;
933 }
934 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
935 /* Not real sure here either... */
936 sc->result = DID_RESET << 16;
937 }
938 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
939 /* Device Inq. data indicates that it supports
940 * QTags, but rejects QTag messages.
941 * This command completed OK.
942 *
943 * Not real sure here either so do nothing... */
944 }
945
946 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
947 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
948
949 /* Add handling of:
950 * Reservation Conflict, Busy,
951 * Command Terminated, CHECK
952 */
953 break;
954
955 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
956 sc->result = DID_SOFT_ERROR << 16;
957 break;
958
959 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
960 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
961 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
962 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
964 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
966 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
967 default:
968 /*
969 * What to do?
970 */
971 sc->result = DID_SOFT_ERROR << 16;
972 break;
973
974 } /* switch(status) */
975
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530976#ifdef CONFIG_FUSION_LOGGING
977 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
978 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700979#endif
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 } /* end of address reply case */
Kashyap, Desaifea98402009-09-02 11:45:53 +0530982out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900984 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 sc->scsi_done(sc); /* Issue the command callback */
987
988 /* Free Chain buffers */
989 mptscsih_freeChainBuffers(ioc, req_idx);
990 return 1;
991}
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993/*
994 * mptscsih_flush_running_cmds - For each command found, search
995 * Scsi_Host instance taskQ and reply to OS.
996 * Called only if recovering from a FW reload.
997 * @hd: Pointer to a SCSI HOST structure
998 *
999 * Returns: None.
1000 *
1001 * Must be called while new I/Os are being queued.
1002 */
1003static void
1004mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
1005{
1006 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001007 struct scsi_cmnd *sc;
1008 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 int ii;
Eric Mooree8206382007-09-29 10:16:53 -06001010 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Eric Mooree8206382007-09-29 10:16:53 -06001012 for (ii= 0; ii < ioc->req_depth; ii++) {
1013 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
1014 if (!sc)
1015 continue;
1016 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
1017 if (!mf)
1018 continue;
1019 channel = mf->Bus;
1020 id = mf->TargetID;
1021 mptscsih_freeChainBuffers(ioc, ii);
1022 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1023 if ((unsigned char *)mf != sc->host_scribble)
1024 continue;
1025 scsi_dma_unmap(sc);
1026 sc->result = DID_RESET << 16;
1027 sc->host_scribble = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301028 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
1029 "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
1030 "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
Eric Mooree8206382007-09-29 10:16:53 -06001031 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
1035/*
1036 * mptscsih_search_running_cmds - Delete any commands associated
1037 * with the specified target and lun. Function called only
1038 * when a lun is disable by mid-layer.
1039 * Do NOT access the referenced scsi_cmnd structure or
1040 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001041 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001042 * @hd: Pointer to a SCSI HOST structure
1043 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 *
1045 * Returns: None.
1046 *
1047 * Called from slave_destroy.
1048 */
1049static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001050mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051{
1052 SCSIIORequest_t *mf = NULL;
1053 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001054 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001055 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -06001056 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001057 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Eric Mooree8206382007-09-29 10:16:53 -06001059 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1060 for (ii = 0; ii < ioc->req_depth; ii++) {
1061 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Eric Mooree80b0022007-09-14 18:49:03 -06001063 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001064 if (mf == NULL)
1065 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001066 /* If the device is a hidden raid component, then its
1067 * expected that the mf->function will be RAID_SCSI_IO
1068 */
1069 if (vdevice->vtarget->tflags &
1070 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1071 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1072 continue;
1073
Eric Moore793955f2007-01-29 09:42:20 -07001074 int_to_scsilun(vdevice->lun, &lun);
1075 if ((mf->Bus != vdevice->vtarget->channel) ||
1076 (mf->TargetID != vdevice->vtarget->id) ||
1077 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 continue;
1079
Eric Moore3dc0b032006-07-11 17:32:33 -06001080 if ((unsigned char *)mf != sc->host_scribble)
1081 continue;
Eric Mooree8206382007-09-29 10:16:53 -06001082 ioc->ScsiLookup[ii] = NULL;
1083 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1084 mptscsih_freeChainBuffers(ioc, ii);
1085 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001086 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001087 sc->host_scribble = NULL;
1088 sc->result = DID_NO_CONNECT << 16;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301089 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
1090 MYIOC_s_FMT "completing cmds: fw_channel %d, "
1091 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
1092 vdevice->vtarget->channel, vdevice->vtarget->id,
1093 sc, mf, ii));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001094 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001095 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097 }
Eric Mooree8206382007-09-29 10:16:53 -06001098 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return;
1100}
1101
1102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1105/*
1106 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1107 * from a SCSI target device.
1108 * @sc: Pointer to scsi_cmnd structure
1109 * @pScsiReply: Pointer to SCSIIOReply_t
1110 * @pScsiReq: Pointer to original SCSI request
1111 *
1112 * This routine periodically reports QUEUE_FULL status returned from a
1113 * SCSI target device. It reports this to the console via kernel
1114 * printk() API call, not more than once every 10 seconds.
1115 */
1116static void
1117mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1118{
1119 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001121 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001123 if (sc->device == NULL)
1124 return;
1125 if (sc->device->host == NULL)
1126 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001127 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001128 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001129 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001130 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001131 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1132 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001133 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
1137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1138/*
1139 * mptscsih_remove - Removed scsi devices
1140 * @pdev: Pointer to pci_dev structure
1141 *
1142 *
1143 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001144void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145mptscsih_remove(struct pci_dev *pdev)
1146{
1147 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1148 struct Scsi_Host *host = ioc->sh;
1149 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001150 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001152 if(!host) {
1153 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 scsi_remove_host(host);
1158
Eric Mooree7eae9f2007-09-29 10:15:59 -06001159 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001160 return;
1161
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001162 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001164 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Eric Mooree8206382007-09-29 10:16:53 -06001166 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001167 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001168 kfree(ioc->ScsiLookup);
1169 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171
Eric Mooree80b0022007-09-14 18:49:03 -06001172 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001173 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001174 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001175
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001176 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001177
1178 /* NULL the Scsi_Host pointer
1179 */
Eric Mooree80b0022007-09-14 18:49:03 -06001180 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001181
1182 scsi_host_put(host);
1183
1184 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186}
1187
1188/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1189/*
1190 * mptscsih_shutdown - reboot notifier
1191 *
1192 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001193void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001194mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196}
1197
1198#ifdef CONFIG_PM
1199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1200/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001201 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 *
1203 *
1204 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001205int
Pavel Machek8d189f72005-04-16 15:25:28 -07001206mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301208 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1209
1210 scsi_block_requests(ioc->sh);
1211 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001212 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001213 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214}
1215
1216/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1217/*
1218 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1219 *
1220 *
1221 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001222int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223mptscsih_resume(struct pci_dev *pdev)
1224{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301225 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1226 int rc;
1227
1228 rc = mpt_resume(pdev);
1229 scsi_unblock_requests(ioc->sh);
1230 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231}
1232
1233#endif
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1236/**
1237 * mptscsih_info - Return information about MPT adapter
1238 * @SChost: Pointer to Scsi_Host structure
1239 *
1240 * (linux scsi_host_template.info routine)
1241 *
1242 * Returns pointer to buffer where information was written.
1243 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001244const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245mptscsih_info(struct Scsi_Host *SChost)
1246{
1247 MPT_SCSI_HOST *h;
1248 int size = 0;
1249
Eric Mooree7eae9f2007-09-29 10:15:59 -06001250 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001253 if (h->info_kbuf == NULL)
1254 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1255 return h->info_kbuf;
1256 h->info_kbuf[0] = '\0';
1257
1258 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1259 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
1261
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001262 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263}
1264
1265struct info_str {
1266 char *buffer;
1267 int length;
1268 int offset;
1269 int pos;
1270};
1271
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001272static void
1273mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274{
1275 if (info->pos + len > info->length)
1276 len = info->length - info->pos;
1277
1278 if (info->pos + len < info->offset) {
1279 info->pos += len;
1280 return;
1281 }
1282
1283 if (info->pos < info->offset) {
1284 data += (info->offset - info->pos);
1285 len -= (info->offset - info->pos);
1286 }
1287
1288 if (len > 0) {
1289 memcpy(info->buffer + info->pos, data, len);
1290 info->pos += len;
1291 }
1292}
1293
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001294static int
1295mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 va_list args;
1298 char buf[81];
1299 int len;
1300
1301 va_start(args, fmt);
1302 len = vsprintf(buf, fmt, args);
1303 va_end(args);
1304
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001305 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 return len;
1307}
1308
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001309static int
1310mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311{
1312 struct info_str info;
1313
1314 info.buffer = pbuf;
1315 info.length = len;
1316 info.offset = offset;
1317 info.pos = 0;
1318
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001319 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1320 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1321 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1322 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
1324 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1325}
1326
1327/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1328/**
1329 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001330 * @host: scsi host struct
1331 * @buffer: if write, user data; if read, buffer for user
1332 * @start: returns the buffer address
1333 * @offset: if write, 0; if read, the current offset into the buffer from
1334 * the previous read.
1335 * @length: if write, return length;
1336 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 *
1338 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001340int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1342 int length, int func)
1343{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001344 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 MPT_ADAPTER *ioc = hd->ioc;
1346 int size = 0;
1347
1348 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001349 /*
1350 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 */
1352 } else {
1353 if (start)
1354 *start = buffer;
1355
1356 size = mptscsih_host_info(ioc, buffer, offset, length);
1357 }
1358
1359 return size;
1360}
1361
1362/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1363#define ADD_INDEX_LOG(req_ent) do { } while(0)
1364
1365/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1366/**
1367 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1368 * @SCpnt: Pointer to scsi_cmnd structure
1369 * @done: Pointer SCSI mid-layer IO completion function
1370 *
1371 * (linux scsi_host_template.queuecommand routine)
1372 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1373 * from a linux scsi_cmnd request and send it to the IOC.
1374 *
1375 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1376 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001377int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1379{
1380 MPT_SCSI_HOST *hd;
1381 MPT_FRAME_HDR *mf;
1382 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001383 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 u32 datalen;
1385 u32 scsictl;
1386 u32 scsidir;
1387 u32 cmd_len;
1388 int my_idx;
1389 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301390 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Eric Mooree7eae9f2007-09-29 10:15:59 -06001392 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301393 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 SCpnt->scsi_done = done;
1395
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301396 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1397 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301399 if (ioc->taskmgmt_quiesce_io) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301400 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1401 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 return SCSI_MLQUEUE_HOST_BUSY;
1403 }
1404
1405 /*
1406 * Put together a MPT SCSI request...
1407 */
Eric Mooree80b0022007-09-14 18:49:03 -06001408 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301409 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1410 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return SCSI_MLQUEUE_HOST_BUSY;
1412 }
1413
1414 pScsiReq = (SCSIIORequest_t *) mf;
1415
1416 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1417
1418 ADD_INDEX_LOG(my_idx);
1419
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001420 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 * Seems we may receive a buffer (datalen>0) even when there
1422 * will be no data transfer! GRRRRR...
1423 */
1424 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001425 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1427 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001428 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1430 } else {
1431 datalen = 0;
1432 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1433 }
1434
1435 /* Default to untagged. Once a target structure has been allocated,
1436 * use the Inquiry data to determine if device supports tagged.
1437 */
Eric Moorea69de502007-09-14 18:48:19 -06001438 if (vdevice
1439 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 && (SCpnt->device->tagged_supported)) {
1441 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai65f89c22009-12-16 19:01:13 +05301442 if (SCpnt->request && SCpnt->request->ioprio) {
1443 if (((SCpnt->request->ioprio & 0x7) == 1) ||
1444 !(SCpnt->request->ioprio & 0x7))
1445 scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ;
1446 }
1447 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
Kashyap, Desai65f89c22009-12-16 19:01:13 +05301449
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451 /* Use the above information to set up the message frame
1452 */
Eric Moorea69de502007-09-14 18:48:19 -06001453 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1454 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001456 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001457 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1458 else
1459 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 pScsiReq->CDBLength = SCpnt->cmd_len;
1461 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1462 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301463 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001464 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 pScsiReq->Control = cpu_to_le32(scsictl);
1466
1467 /*
1468 * Write SCSI CDB into the message
1469 */
1470 cmd_len = SCpnt->cmd_len;
1471 for (ii=0; ii < cmd_len; ii++)
1472 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1473
1474 for (ii=cmd_len; ii < 16; ii++)
1475 pScsiReq->CDB[ii] = 0;
1476
1477 /* DataLength */
1478 pScsiReq->DataLength = cpu_to_le32(datalen);
1479
1480 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001481 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1483
1484 /* Now add the SG list
1485 * Always have a SGE even if null length.
1486 */
1487 if (datalen == 0) {
1488 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301489 ioc->add_sge((char *)&pScsiReq->SGL,
1490 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 (dma_addr_t) -1);
1492 } else {
1493 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001494 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 goto fail;
1496 }
1497
Eric Moore3dc0b032006-07-11 17:32:33 -06001498 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001499 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
Eric Mooree80b0022007-09-14 18:49:03 -06001501 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301502 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1503 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001504 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return 0;
1506
1507 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001508 mptscsih_freeChainBuffers(ioc, my_idx);
1509 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 return SCSI_MLQUEUE_HOST_BUSY;
1511}
1512
1513/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1514/*
1515 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1516 * with a SCSI IO request
1517 * @hd: Pointer to the MPT_SCSI_HOST instance
1518 * @req_idx: Index of the SCSI IO request frame.
1519 *
1520 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1521 * No return.
1522 */
1523static void
1524mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1525{
1526 MPT_FRAME_HDR *chain;
1527 unsigned long flags;
1528 int chain_idx;
1529 int next;
1530
1531 /* Get the first chain index and reset
1532 * tracker state.
1533 */
1534 chain_idx = ioc->ReqToChain[req_idx];
1535 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1536
1537 while (chain_idx != MPT_HOST_NO_CHAIN) {
1538
1539 /* Save the next chain buffer index */
1540 next = ioc->ChainToChain[chain_idx];
1541
1542 /* Free this chain buffer and reset
1543 * tracker
1544 */
1545 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1546
1547 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1548 + (chain_idx * ioc->req_sz));
1549
1550 spin_lock_irqsave(&ioc->FreeQlock, flags);
1551 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1552 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1553
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301554 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 ioc->name, chain_idx));
1556
1557 /* handle next */
1558 chain_idx = next;
1559 }
1560 return;
1561}
1562
1563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1564/*
1565 * Reset Handling
1566 */
1567
1568/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001569/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1571 * @hd: Pointer to MPT_SCSI_HOST structure
1572 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001573 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001574 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 * @lun: Logical Unit for reset (if appropriate)
1576 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001577 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 *
1579 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1580 * or a non-interrupt thread. In the former, must not call schedule().
1581 *
1582 * Not all fields are meaningfull for all task types.
1583 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001584 * Returns 0 for SUCCESS, or FAILED.
1585 *
1586 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301587int
1588mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1589 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
1591 MPT_FRAME_HDR *mf;
1592 SCSITaskMgmt_t *pScsiTm;
1593 int ii;
1594 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001595 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301596 unsigned long timeleft;
1597 u8 issue_hard_reset;
1598 u32 ioc_raw_state;
1599 unsigned long time_count;
1600
1601 issue_hard_reset = 0;
1602 ioc_raw_state = mpt_GetIocState(ioc, 0);
1603
1604 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1605 printk(MYIOC_s_WARN_FMT
1606 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1607 ioc->name, type, ioc_raw_state);
1608 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1609 ioc->name, __func__);
1610 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1611 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1612 "FAILED!!\n", ioc->name);
1613 return 0;
1614 }
1615
1616 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1617 printk(MYIOC_s_WARN_FMT
1618 "TaskMgmt type=%x: ioc_state: "
1619 "DOORBELL_ACTIVE (0x%x)!\n",
1620 ioc->name, type, ioc_raw_state);
1621 return FAILED;
1622 }
1623
1624 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1625 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1626 mf = NULL;
1627 retval = FAILED;
1628 goto out;
1629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631 /* Return Fail to calling function if no message frames available.
1632 */
Eric Mooree80b0022007-09-14 18:49:03 -06001633 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301634 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1635 "TaskMgmt no msg frames!!\n", ioc->name));
1636 retval = FAILED;
1637 mpt_clear_taskmgmt_in_progress_flag(ioc);
1638 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301640 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001641 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 /* Format the Request
1644 */
1645 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001646 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 pScsiTm->Bus = channel;
1648 pScsiTm->ChainOffset = 0;
1649 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1650
1651 pScsiTm->Reserved = 0;
1652 pScsiTm->TaskType = type;
1653 pScsiTm->Reserved1 = 0;
1654 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1655 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1656
Eric Moore793955f2007-01-29 09:42:20 -07001657 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659 for (ii=0; ii < 7; ii++)
1660 pScsiTm->Reserved2[ii] = 0;
1661
1662 pScsiTm->TaskMsgContext = ctx2abort;
1663
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301664 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1665 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1666 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301668 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301670 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1671 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001672 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1673 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1674 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301675 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001676 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301677 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1678 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301679 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1680 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1681 ioc->name, mf, retval));
1682 mpt_free_msg_frame(ioc, mf);
1683 mpt_clear_taskmgmt_in_progress_flag(ioc);
1684 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
1687
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301688 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1689 timeout*HZ);
1690 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1691 retval = FAILED;
1692 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1693 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1694 mpt_clear_taskmgmt_in_progress_flag(ioc);
1695 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1696 goto out;
1697 issue_hard_reset = 1;
1698 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 }
1700
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301701 retval = mptscsih_taskmgmt_reply(ioc, type,
1702 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001703
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301704 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1705 "TaskMgmt completed (%d seconds)\n",
1706 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1707
1708 out:
1709
1710 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1711 if (issue_hard_reset) {
1712 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
1713 ioc->name, __func__);
1714 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1715 mpt_free_msg_frame(ioc, mf);
1716 }
1717
1718 retval = (retval == 0) ? 0 : FAILED;
1719 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 return retval;
1721}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301722EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001724static int
1725mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1726{
1727 switch (ioc->bus_type) {
1728 case FC:
1729 return 40;
1730 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001731 case SPI:
1732 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001733 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001734 }
1735}
1736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1738/**
1739 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1740 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1741 *
1742 * (linux scsi_host_template.eh_abort_handler routine)
1743 *
1744 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001745 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001746int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747mptscsih_abort(struct scsi_cmnd * SCpnt)
1748{
1749 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 MPT_FRAME_HDR *mf;
1751 u32 ctx2abort;
1752 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001753 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001754 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001755 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001756 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 /* If we can't locate our host adapter structure, return FAILED status.
1759 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001760 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 SCpnt->result = DID_RESET << 16;
1762 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001763 printk(KERN_ERR MYNAM ": task abort: "
1764 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 return FAILED;
1766 }
1767
Eric Moore958d4a32007-06-15 17:24:14 -06001768 ioc = hd->ioc;
1769 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1770 ioc->name, SCpnt);
1771 scsi_print_command(SCpnt);
1772
1773 vdevice = SCpnt->device->hostdata;
1774 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001775 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1776 "task abort: device has been deleted (sc=%p)\n",
1777 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001778 SCpnt->result = DID_NO_CONNECT << 16;
1779 SCpnt->scsi_done(SCpnt);
1780 retval = 0;
1781 goto out;
1782 }
1783
Eric Moorecc78d302007-06-15 17:27:21 -06001784 /* Task aborts are not supported for hidden raid components.
1785 */
1786 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001787 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1788 "task abort: hidden raid component (sc=%p)\n",
1789 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001790 SCpnt->result = DID_RESET << 16;
1791 retval = FAILED;
1792 goto out;
1793 }
1794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 /* Find this command
1796 */
Eric Mooree8206382007-09-29 10:16:53 -06001797 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001798 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 * Do OS callback.
1800 */
1801 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001802 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001803 "Command not in the active list! (sc=%p)\n", ioc->name,
1804 SCpnt));
Kashyap, Desai9858ae32010-01-25 16:20:52 +05301805 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001806 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 }
1808
Kashyap, Desai2f187862009-05-29 16:52:37 +05301809 if (ioc->timeouts < -1)
1810 ioc->timeouts++;
Moore, Eric65207fe2006-04-21 16:14:35 -06001811
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301812 if (mpt_fwfault_debug)
1813 mpt_halt_firmware(ioc);
1814
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1816 * (the IO to be ABORT'd)
1817 *
1818 * NOTE: Since we do not byteswap MsgContext, we do not
1819 * swap it here either. It is an opaque cookie to
1820 * the controller, so it does not matter. -DaveM
1821 */
Eric Mooree80b0022007-09-14 18:49:03 -06001822 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301824 retval = mptscsih_IssueTaskMgmt(hd,
1825 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1826 vdevice->vtarget->channel,
1827 vdevice->vtarget->id, vdevice->lun,
1828 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Eric Mooree8206382007-09-29 10:16:53 -06001830 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05301831 SCpnt->serial_number == sn) {
1832 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1833 "task abort: command still in active list! (sc=%p)\n",
1834 ioc->name, SCpnt));
Eric Moore3dc0b032006-07-11 17:32:33 -06001835 retval = FAILED;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301836 } else {
1837 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1838 "task abort: command cleared from active list! (sc=%p)\n",
1839 ioc->name, SCpnt));
1840 retval = SUCCESS;
1841 }
Eric Moore3dc0b032006-07-11 17:32:33 -06001842
Eric Moore958d4a32007-06-15 17:24:14 -06001843 out:
1844 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
Kashyap, Desai2f187862009-05-29 16:52:37 +05301845 ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
Kashyap, Desai2f187862009-05-29 16:52:37 +05301847 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848}
1849
1850/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1851/**
1852 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1853 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1854 *
1855 * (linux scsi_host_template.eh_dev_reset_handler routine)
1856 *
1857 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001858 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001859int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1861{
1862 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001863 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001864 VirtDevice *vdevice;
1865 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867 /* If we can't locate our host adapter structure, return FAILED status.
1868 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001869 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001870 printk(KERN_ERR MYNAM ": target reset: "
1871 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 return FAILED;
1873 }
1874
Eric Moore958d4a32007-06-15 17:24:14 -06001875 ioc = hd->ioc;
1876 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1877 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001878 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Eric Moore958d4a32007-06-15 17:24:14 -06001880 vdevice = SCpnt->device->hostdata;
1881 if (!vdevice || !vdevice->vtarget) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05301882 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001883 goto out;
1884 }
1885
Eric Moorecc78d302007-06-15 17:27:21 -06001886 /* Target reset to hidden raid component is not supported
1887 */
1888 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1889 retval = FAILED;
1890 goto out;
1891 }
1892
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301893 retval = mptscsih_IssueTaskMgmt(hd,
1894 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1895 vdevice->vtarget->channel,
1896 vdevice->vtarget->id, 0, 0,
1897 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001898
1899 out:
1900 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1901 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001902
1903 if (retval == 0)
1904 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001905 else
1906 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907}
1908
Eric Moorecd2c6192007-01-29 09:47:47 -07001909
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1911/**
1912 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1913 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1914 *
1915 * (linux scsi_host_template.eh_bus_reset_handler routine)
1916 *
1917 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001918 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001919int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1921{
1922 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001923 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001924 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001925 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
1927 /* If we can't locate our host adapter structure, return FAILED status.
1928 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001929 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001930 printk(KERN_ERR MYNAM ": bus reset: "
1931 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 return FAILED;
1933 }
1934
Eric Moore958d4a32007-06-15 17:24:14 -06001935 ioc = hd->ioc;
1936 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1937 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001938 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
Kashyap, Desai2f187862009-05-29 16:52:37 +05301940 if (ioc->timeouts < -1)
1941 ioc->timeouts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Eric Moorea69de502007-09-14 18:48:19 -06001943 vdevice = SCpnt->device->hostdata;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301944 if (!vdevice || !vdevice->vtarget)
1945 return SUCCESS;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301946 retval = mptscsih_IssueTaskMgmt(hd,
1947 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1948 vdevice->vtarget->channel, 0, 0, 0,
1949 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Eric Moore958d4a32007-06-15 17:24:14 -06001951 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1952 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001953
1954 if (retval == 0)
1955 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001956 else
1957 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958}
1959
1960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1961/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001962 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1964 *
1965 * (linux scsi_host_template.eh_host_reset_handler routine)
1966 *
1967 * Returns SUCCESS or FAILED.
1968 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001969int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1971{
1972 MPT_SCSI_HOST * hd;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301973 int status = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001974 MPT_ADAPTER *ioc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301975 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001978 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001979 printk(KERN_ERR MYNAM ": host reset: "
1980 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 return FAILED;
1982 }
1983
James Bottomleya6da74c2008-12-15 14:13:27 -06001984 /* make sure we have no outstanding commands at this stage */
1985 mptscsih_flush_running_cmds(hd);
1986
Eric Moore958d4a32007-06-15 17:24:14 -06001987 ioc = hd->ioc;
1988 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1989 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
1991 /* If our attempts to reset the host failed, then return a failed
1992 * status. The host will be taken off line by the SCSI mid-layer.
1993 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05301994 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1995 if (retval < 0)
1996 status = FAILED;
1997 else
1998 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Eric Moore958d4a32007-06-15 17:24:14 -06002000 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2001 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
Kashyap, Desai2f187862009-05-29 16:52:37 +05302003 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004}
2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302007mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
2008 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302010 u16 iocstatus;
2011 u32 termination_count;
2012 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302014 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
2015 retval = FAILED;
2016 goto out;
2017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302019 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302021 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2022 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302024 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2025 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
2026 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
2027 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
2028 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
2029 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
2030 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302032 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2033 pScsiTmReply->ResponseCode)
2034 mptscsih_taskmgmt_response_code(ioc,
2035 pScsiTmReply->ResponseCode);
2036
2037 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
2038 retval = 0;
2039 goto out;
2040 }
2041
2042 retval = FAILED;
2043 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
2044 if (termination_count == 1)
2045 retval = 0;
2046 goto out;
2047 }
2048
2049 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
2050 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
2051 retval = 0;
2052
2053 out:
2054 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055}
2056
2057/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302058void
Moore, Eric9f63bb72006-01-16 18:53:26 -07002059mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2060{
2061 char *desc;
2062
2063 switch (response_code) {
2064 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2065 desc = "The task completed.";
2066 break;
2067 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2068 desc = "The IOC received an invalid frame status.";
2069 break;
2070 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2071 desc = "The task type is not supported.";
2072 break;
2073 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2074 desc = "The requested task failed.";
2075 break;
2076 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2077 desc = "The task completed successfully.";
2078 break;
2079 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2080 desc = "The LUN request is invalid.";
2081 break;
2082 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2083 desc = "The task is in the IOC queue and has not been sent to target.";
2084 break;
2085 default:
2086 desc = "unknown";
2087 break;
2088 }
2089 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2090 ioc->name, response_code, desc);
2091}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302092EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07002093
2094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095/**
2096 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2097 * @ioc: Pointer to MPT_ADAPTER structure
2098 * @mf: Pointer to SCSI task mgmt request frame
2099 * @mr: Pointer to SCSI task mgmt reply frame
2100 *
2101 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2102 * of any SCSI task management request.
2103 * This routine is registered with the MPT (base) driver at driver
2104 * load/init time via the mpt_register() API call.
2105 *
2106 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002107 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002108int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302109mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2110 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302112 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2113 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302115 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302117 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002118 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002119
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302120 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2121 memcpy(ioc->taskmgmt_cmds.reply, mr,
2122 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002123 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302124 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2125 mpt_clear_taskmgmt_in_progress_flag(ioc);
2126 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2127 complete(&ioc->taskmgmt_cmds.done);
2128 return 1;
2129 }
2130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131}
2132
2133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2134/*
2135 * This is anyones guess quite frankly.
2136 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002137int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2139 sector_t capacity, int geom[])
2140{
2141 int heads;
2142 int sectors;
2143 sector_t cylinders;
2144 ulong dummy;
2145
2146 heads = 64;
2147 sectors = 32;
2148
2149 dummy = heads * sectors;
2150 cylinders = capacity;
2151 sector_div(cylinders,dummy);
2152
2153 /*
2154 * Handle extended translation size for logical drives
2155 * > 1Gb
2156 */
2157 if ((ulong)capacity >= 0x200000) {
2158 heads = 255;
2159 sectors = 63;
2160 dummy = heads * sectors;
2161 cylinders = capacity;
2162 sector_div(cylinders,dummy);
2163 }
2164
2165 /* return result */
2166 geom[0] = heads;
2167 geom[1] = sectors;
2168 geom[2] = cylinders;
2169
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 return 0;
2171}
2172
Moore, Ericf44e5462006-03-14 09:14:21 -07002173/* Search IOC page 3 to determine if this is hidden physical disk
2174 *
2175 */
2176int
Eric Moore793955f2007-01-29 09:42:20 -07002177mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002178{
Eric Mooreb506ade2007-01-29 09:45:37 -07002179 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302180 int i, j;
2181 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002182 int rc = 0;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302183 int num_paths;
Moore, Ericf44e5462006-03-14 09:14:21 -07002184
Eric Moore793955f2007-01-29 09:42:20 -07002185 if (!ioc->raid_data.pIocPg3)
2186 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002187 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002188 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2189 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2190 rc = 1;
2191 goto out;
2192 }
2193 }
2194
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302195 if (ioc->bus_type != SAS)
2196 goto out;
2197
2198 /*
2199 * Check if dual path
2200 */
2201 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2202 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2203 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2204 if (num_paths < 2)
2205 continue;
2206 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2207 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2208 if (!phys_disk)
2209 continue;
2210 if ((mpt_raid_phys_disk_pg1(ioc,
2211 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2212 phys_disk))) {
2213 kfree(phys_disk);
2214 continue;
2215 }
2216 for (j = 0; j < num_paths; j++) {
2217 if ((phys_disk->Path[j].Flags &
2218 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2219 continue;
2220 if ((phys_disk->Path[j].Flags &
2221 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2222 continue;
2223 if ((id == phys_disk->Path[j].PhysDiskID) &&
2224 (channel == phys_disk->Path[j].PhysDiskBus)) {
2225 rc = 1;
2226 kfree(phys_disk);
2227 goto out;
2228 }
2229 }
2230 kfree(phys_disk);
2231 }
2232
2233
Eric Mooreb506ade2007-01-29 09:45:37 -07002234 /*
2235 * Check inactive list for matching phys disks
2236 */
2237 if (list_empty(&ioc->raid_data.inactive_list))
2238 goto out;
2239
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002240 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002241 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2242 list) {
2243 if ((component_info->d.PhysDiskID == id) &&
2244 (component_info->d.PhysDiskBus == channel))
2245 rc = 1;
2246 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002247 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002248
Eric Moore793955f2007-01-29 09:42:20 -07002249 out:
2250 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002251}
2252EXPORT_SYMBOL(mptscsih_is_phys_disk);
2253
Eric Moore793955f2007-01-29 09:42:20 -07002254u8
2255mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002256{
Eric Mooreb506ade2007-01-29 09:45:37 -07002257 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302258 int i, j;
2259 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002260 int rc = -ENXIO;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302261 int num_paths;
James Bottomleyc92f2222006-03-01 09:02:49 -06002262
Eric Moore793955f2007-01-29 09:42:20 -07002263 if (!ioc->raid_data.pIocPg3)
2264 goto out;
2265 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2266 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2267 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2268 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2269 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002270 }
2271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302273 if (ioc->bus_type != SAS)
2274 goto out;
2275
2276 /*
2277 * Check if dual path
2278 */
2279 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2280 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2281 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2282 if (num_paths < 2)
2283 continue;
2284 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2285 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2286 if (!phys_disk)
2287 continue;
2288 if ((mpt_raid_phys_disk_pg1(ioc,
2289 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2290 phys_disk))) {
2291 kfree(phys_disk);
2292 continue;
2293 }
2294 for (j = 0; j < num_paths; j++) {
2295 if ((phys_disk->Path[j].Flags &
2296 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2297 continue;
2298 if ((phys_disk->Path[j].Flags &
2299 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2300 continue;
2301 if ((id == phys_disk->Path[j].PhysDiskID) &&
2302 (channel == phys_disk->Path[j].PhysDiskBus)) {
2303 rc = phys_disk->PhysDiskNum;
2304 kfree(phys_disk);
2305 goto out;
2306 }
2307 }
2308 kfree(phys_disk);
2309 }
2310
Eric Mooreb506ade2007-01-29 09:45:37 -07002311 /*
2312 * Check inactive list for matching phys disks
2313 */
2314 if (list_empty(&ioc->raid_data.inactive_list))
2315 goto out;
2316
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002317 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002318 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2319 list) {
2320 if ((component_info->d.PhysDiskID == id) &&
2321 (component_info->d.PhysDiskBus == channel))
2322 rc = component_info->d.PhysDiskNum;
2323 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002324 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002325
Eric Moore793955f2007-01-29 09:42:20 -07002326 out:
2327 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002328}
Eric Moore793955f2007-01-29 09:42:20 -07002329EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002330
2331/*
2332 * OS entry point to allow for host driver to free allocated memory
2333 * Called if no device present or device being unloaded
2334 */
2335void
2336mptscsih_slave_destroy(struct scsi_device *sdev)
2337{
2338 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002339 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002340 VirtTarget *vtarget;
2341 VirtDevice *vdevice;
2342 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002344 starget = scsi_target(sdev);
2345 vtarget = starget->hostdata;
2346 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002348 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002349 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002350 mptscsih_synchronize_cache(hd, vdevice);
2351 kfree(vdevice);
2352 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353}
2354
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002355/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2356/*
2357 * mptscsih_change_queue_depth - This function will set a devices queue depth
2358 * @sdev: per scsi_device pointer
2359 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07002360 * @reason: calling context
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002361 *
2362 * Adding support for new 'change_queue_depth' api.
2363*/
2364int
Mike Christiee881a172009-10-15 17:46:39 -07002365mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002367 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368 VirtTarget *vtarget;
2369 struct scsi_target *starget;
2370 int max_depth;
2371 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002372 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002374 starget = scsi_target(sdev);
2375 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002376
Mike Christiee881a172009-10-15 17:46:39 -07002377 if (reason != SCSI_QDEPTH_DEFAULT)
2378 return -EOPNOTSUPP;
2379
Eric Mooree80b0022007-09-14 18:49:03 -06002380 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002381 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002383 else if (sdev->type == TYPE_DISK &&
2384 vtarget->minSyncFactor <= MPT_ULTRA160)
2385 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2386 else
2387 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 } else
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05302389 max_depth = ioc->sh->can_queue;
2390
2391 if (!sdev->tagged_supported)
2392 max_depth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
2394 if (qdepth > max_depth)
2395 qdepth = max_depth;
2396 if (qdepth == 1)
2397 tagged = 0;
2398 else
2399 tagged = MSG_SIMPLE_TAG;
2400
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002401 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2402 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403}
2404
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405/*
2406 * OS entry point to adjust the queue_depths on a per-device basis.
2407 * Called once per device the bus scan. Use it to force the queue_depth
2408 * member to 1 if a device does not support Q tags.
2409 * Return non-zero if fails.
2410 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002411int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002412mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002414 struct Scsi_Host *sh = sdev->host;
2415 VirtTarget *vtarget;
2416 VirtDevice *vdevice;
2417 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002418 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002419 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002421 starget = scsi_target(sdev);
2422 vtarget = starget->hostdata;
2423 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
Eric Mooree80b0022007-09-14 18:49:03 -06002425 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002426 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002427 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2428 if (ioc->bus_type == SPI)
2429 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002430 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002431 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002432 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Eric Moore793955f2007-01-29 09:42:20 -07002434 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Eric Mooree80b0022007-09-14 18:49:03 -06002436 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002438 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Eric Mooree80b0022007-09-14 18:49:03 -06002440 if (ioc->bus_type == SPI)
2441 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002442 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002443 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002444 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
Mike Christiee881a172009-10-15 17:46:39 -07002446 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
2447 SCSI_QDEPTH_DEFAULT);
Eric Mooree80b0022007-09-14 18:49:03 -06002448 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002450 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002451 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
2453 return 0;
2454}
2455
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2457/*
2458 * Private routines...
2459 */
2460
2461/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2462/* Utility function to copy sense data from the scsi_cmnd buffer
2463 * to the FC and SCSI target structures.
2464 *
2465 */
2466static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002467mptscsih_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 -07002468{
Eric Moorea69de502007-09-14 18:48:19 -06002469 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 SCSIIORequest_t *pReq;
2471 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002472 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
2474 /* Get target structure
2475 */
2476 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002477 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 if (sense_count) {
2480 u8 *sense_data;
2481 int req_index;
2482
2483 /* Copy the sense received into the scsi command block. */
2484 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002485 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2487
2488 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2489 */
Eric Mooree80b0022007-09-14 18:49:03 -06002490 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002491 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002494 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2496 ioc->events[idx].eventContext = ioc->eventContext;
2497
Dave Jones3d9780b2007-05-21 20:59:47 -04002498 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2499 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2500 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
Dave Jones3d9780b2007-05-21 20:59:47 -04002502 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
2504 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002505 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002506 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002507 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002508 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2509 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002510 MPT_TARGET_FLAGS_LED_ON;
2511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 }
2513 }
2514 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002515 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2516 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 }
2518}
2519
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05302520/**
2521 * mptscsih_get_scsi_lookup - retrieves scmd entry
2522 * @ioc: Pointer to MPT_ADAPTER structure
2523 * @i: index into the array
2524 *
2525 * Returns the scsi_cmd pointer
2526 */
2527struct scsi_cmnd *
2528mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2529{
2530 unsigned long flags;
2531 struct scsi_cmnd *scmd;
2532
2533 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2534 scmd = ioc->ScsiLookup[i];
2535 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2536
2537 return scmd;
2538}
2539EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
Eric Mooree8206382007-09-29 10:16:53 -06002540
2541/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00002542 * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
Kashyap, Desai2f187862009-05-29 16:52:37 +05302543 * @ioc: Pointer to MPT_ADAPTER structure
2544 * @i: index into the array
2545 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002546 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302547 *
Eric Mooree8206382007-09-29 10:16:53 -06002548 **/
2549static struct scsi_cmnd *
2550mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2551{
2552 unsigned long flags;
2553 struct scsi_cmnd *scmd;
2554
2555 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2556 scmd = ioc->ScsiLookup[i];
2557 ioc->ScsiLookup[i] = NULL;
2558 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2559
2560 return scmd;
2561}
2562
2563/**
2564 * mptscsih_set_scsi_lookup
2565 *
2566 * writes a scmd entry into the ScsiLookup[] array list
2567 *
2568 * @ioc: Pointer to MPT_ADAPTER structure
2569 * @i: index into the array
2570 * @scmd: scsi_cmnd pointer
2571 *
2572 **/
2573static void
2574mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2575{
2576 unsigned long flags;
2577
2578 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2579 ioc->ScsiLookup[i] = scmd;
2580 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2581}
2582
2583/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002584 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002585 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002586 * @sc: scsi_cmnd pointer
2587 */
Eric Mooree8206382007-09-29 10:16:53 -06002588static int
2589SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2590{
2591 unsigned long flags;
2592 int i, index=-1;
2593
2594 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2595 for (i = 0; i < ioc->req_depth; i++) {
2596 if (ioc->ScsiLookup[i] == sc) {
2597 index = i;
2598 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 }
2600 }
2601
Eric Mooree8206382007-09-29 10:16:53 -06002602 out:
2603 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2604 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605}
2606
2607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002608int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2610{
2611 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612
Eric Mooree7eae9f2007-09-29 10:15:59 -06002613 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302616 hd = shost_priv(ioc->sh);
2617 switch (reset_phase) {
2618 case MPT_IOC_SETUP_RESET:
2619 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2620 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302621 break;
2622 case MPT_IOC_PRE_RESET:
2623 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2624 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302625 mptscsih_flush_running_cmds(hd);
2626 break;
2627 case MPT_IOC_POST_RESET:
2628 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2629 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2630 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2631 ioc->internal_cmds.status |=
2632 MPT_MGMT_STATUS_DID_IOCRESET;
2633 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302635 break;
2636 default:
2637 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 return 1; /* currently means nothing really */
2640}
2641
2642/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002643int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2645{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2647
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302648 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2649 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2650 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Kashyap, Desai2f187862009-05-29 16:52:37 +05302652 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2653 event == MPI_EVENT_EXT_BUS_RESET) &&
2654 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2655 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657 return 1; /* currently means nothing really */
2658}
2659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2661/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 * Bus Scan and Domain Validation functionality ...
2663 */
2664
2665/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2666/*
2667 * mptscsih_scandv_complete - Scan and DV callback routine registered
2668 * to Fustion MPT (base) driver.
2669 *
2670 * @ioc: Pointer to MPT_ADAPTER structure
2671 * @mf: Pointer to original MPT request frame
2672 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2673 *
2674 * This routine is called from mpt.c::mpt_interrupt() at the completion
2675 * of any SCSI IO request.
2676 * This routine is registered with the Fusion MPT (base) driver at driver
2677 * load/init time via the mpt_register() API call.
2678 *
2679 * Returns 1 indicating alloc'd request frame ptr should be freed.
2680 *
2681 * Remark: Sets a completion code and (possibly) saves sense data
2682 * in the IOC member localReply structure.
2683 * Used ONLY for DV and other internal commands.
2684 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002685int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302686mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2687 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302690 SCSIIOReply_t *pReply;
2691 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302693 u8 *sense_data;
2694 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302696 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2697 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2698 if (!reply)
2699 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002700
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302701 pReply = (SCSIIOReply_t *) reply;
2702 pReq = (SCSIIORequest_t *) req;
2703 ioc->internal_cmds.completion_code =
2704 mptscsih_get_completion_code(ioc, req, reply);
2705 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2706 memcpy(ioc->internal_cmds.reply, reply,
2707 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2708 cmd = reply->u.hdr.Function;
2709 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2710 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2711 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2712 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2713 sense_data = ((u8 *)ioc->sense_buf_pool +
2714 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2715 sz = min_t(int, pReq->SenseBufferLength,
2716 MPT_SENSE_BUFFER_ALLOC);
2717 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302719 out:
2720 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2721 return 0;
2722 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2723 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return 1;
2725}
2726
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302728/**
2729 * mptscsih_get_completion_code -
2730 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap9cf46a32009-06-13 19:37:18 -07002731 * @req: Pointer to original MPT request frame
2732 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302733 *
2734 **/
2735static int
2736mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2737 MPT_FRAME_HDR *reply)
2738{
2739 SCSIIOReply_t *pReply;
2740 MpiRaidActionReply_t *pr;
2741 u8 scsi_status;
2742 u16 status;
2743 int completion_code;
2744
2745 pReply = (SCSIIOReply_t *)reply;
2746 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2747 scsi_status = pReply->SCSIStatus;
2748
2749 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2750 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2751 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2752 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2753
2754 switch (status) {
2755
2756 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2757 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2758 break;
2759
2760 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2761 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2762 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2763 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2764 completion_code = MPT_SCANDV_DID_RESET;
2765 break;
2766
2767 case MPI_IOCSTATUS_BUSY:
2768 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2769 completion_code = MPT_SCANDV_BUSY;
2770 break;
2771
2772 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2773 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2774 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2775 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2776 completion_code = MPT_SCANDV_GOOD;
2777 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2778 pr = (MpiRaidActionReply_t *)reply;
2779 if (le16_to_cpu(pr->ActionStatus) ==
2780 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2781 completion_code = MPT_SCANDV_GOOD;
2782 else
2783 completion_code = MPT_SCANDV_SOME_ERROR;
2784 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2785 completion_code = MPT_SCANDV_SENSE;
2786 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2787 if (req->u.scsireq.CDB[0] == INQUIRY)
2788 completion_code = MPT_SCANDV_ISSUE_SENSE;
2789 else
2790 completion_code = MPT_SCANDV_DID_RESET;
2791 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2792 completion_code = MPT_SCANDV_DID_RESET;
2793 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2794 completion_code = MPT_SCANDV_DID_RESET;
2795 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2796 completion_code = MPT_SCANDV_BUSY;
2797 else
2798 completion_code = MPT_SCANDV_GOOD;
2799 break;
2800
2801 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2802 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2803 completion_code = MPT_SCANDV_DID_RESET;
2804 else
2805 completion_code = MPT_SCANDV_SOME_ERROR;
2806 break;
2807 default:
2808 completion_code = MPT_SCANDV_SOME_ERROR;
2809 break;
2810
2811 } /* switch(status) */
2812
2813 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2814 " completionCode set to %08xh\n", ioc->name, completion_code));
2815 return completion_code;
2816}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817
2818/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2819/**
2820 * mptscsih_do_cmd - Do internal command.
2821 * @hd: MPT_SCSI_HOST pointer
2822 * @io: INTERNAL_CMD pointer.
2823 *
2824 * Issue the specified internally generated command and do command
2825 * specific cleanup. For bus scan / DV only.
2826 * NOTES: If command is Inquiry and status is good,
2827 * initialize a target structure, save the data
2828 *
2829 * Remark: Single threaded access only.
2830 *
2831 * Return:
2832 * < 0 if an illegal command or no resources
2833 *
2834 * 0 if good
2835 *
2836 * > 0 if command complete but some type of completion error.
2837 */
2838static int
2839mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2840{
2841 MPT_FRAME_HDR *mf;
2842 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302844 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 char cmdLen;
2846 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 +05302847 u8 cmd = io->cmd;
2848 MPT_ADAPTER *ioc = hd->ioc;
2849 int ret = 0;
2850 unsigned long timeleft;
2851 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302853 /* don't send internal command during diag reset */
2854 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2855 if (ioc->ioc_reset_in_progress) {
2856 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2857 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2858 "%s: busy with host reset\n", ioc->name, __func__));
2859 return MPT_SCANDV_BUSY;
2860 }
2861 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2862
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302863 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864
2865 /* Set command specific information
2866 */
2867 switch (cmd) {
2868 case INQUIRY:
2869 cmdLen = 6;
2870 dir = MPI_SCSIIO_CONTROL_READ;
2871 CDB[0] = cmd;
2872 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302873 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 break;
2875
2876 case TEST_UNIT_READY:
2877 cmdLen = 6;
2878 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302879 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 break;
2881
2882 case START_STOP:
2883 cmdLen = 6;
2884 dir = MPI_SCSIIO_CONTROL_READ;
2885 CDB[0] = cmd;
2886 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302887 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 break;
2889
2890 case REQUEST_SENSE:
2891 cmdLen = 6;
2892 CDB[0] = cmd;
2893 CDB[4] = io->size;
2894 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302895 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 break;
2897
2898 case READ_BUFFER:
2899 cmdLen = 10;
2900 dir = MPI_SCSIIO_CONTROL_READ;
2901 CDB[0] = cmd;
2902 if (io->flags & MPT_ICFLAG_ECHO) {
2903 CDB[1] = 0x0A;
2904 } else {
2905 CDB[1] = 0x02;
2906 }
2907
2908 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2909 CDB[1] |= 0x01;
2910 }
2911 CDB[6] = (io->size >> 16) & 0xFF;
2912 CDB[7] = (io->size >> 8) & 0xFF;
2913 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302914 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 break;
2916
2917 case WRITE_BUFFER:
2918 cmdLen = 10;
2919 dir = MPI_SCSIIO_CONTROL_WRITE;
2920 CDB[0] = cmd;
2921 if (io->flags & MPT_ICFLAG_ECHO) {
2922 CDB[1] = 0x0A;
2923 } else {
2924 CDB[1] = 0x02;
2925 }
2926 CDB[6] = (io->size >> 16) & 0xFF;
2927 CDB[7] = (io->size >> 8) & 0xFF;
2928 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302929 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 break;
2931
2932 case RESERVE:
2933 cmdLen = 6;
2934 dir = MPI_SCSIIO_CONTROL_READ;
2935 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302936 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 break;
2938
2939 case RELEASE:
2940 cmdLen = 6;
2941 dir = MPI_SCSIIO_CONTROL_READ;
2942 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302943 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 break;
2945
2946 case SYNCHRONIZE_CACHE:
2947 cmdLen = 10;
2948 dir = MPI_SCSIIO_CONTROL_READ;
2949 CDB[0] = cmd;
2950// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302951 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 break;
2953
2954 default:
2955 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302956 ret = -EFAULT;
2957 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 }
2959
2960 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302961 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 */
Eric Mooree80b0022007-09-14 18:49:03 -06002963 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302964 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2965 ioc->name, __func__));
2966 ret = MPT_SCANDV_BUSY;
2967 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 }
2969
2970 pScsiReq = (SCSIIORequest_t *) mf;
2971
2972 /* Get the request index */
2973 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2974 ADD_INDEX_LOG(my_idx); /* for debug */
2975
2976 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2977 pScsiReq->TargetID = io->physDiskNum;
2978 pScsiReq->Bus = 0;
2979 pScsiReq->ChainOffset = 0;
2980 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2981 } else {
2982 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002983 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 pScsiReq->ChainOffset = 0;
2985 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2986 }
2987
2988 pScsiReq->CDBLength = cmdLen;
2989 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2990
2991 pScsiReq->Reserved = 0;
2992
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302993 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 /* MsgContext set in mpt_get_msg_fram call */
2995
Eric Moore793955f2007-01-29 09:42:20 -07002996 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
2998 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2999 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3000 else
3001 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3002
3003 if (cmd == REQUEST_SENSE) {
3004 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303005 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3006 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 }
3008
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303009 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 pScsiReq->CDB[ii] = CDB[ii];
3011
3012 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003013 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3015
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303016 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3017 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3018 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303020 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303021 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303022 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3023 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303024 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303025 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303027 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003028 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303029 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3030 timeout*HZ);
3031 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3032 ret = MPT_SCANDV_DID_RESET;
3033 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3034 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3035 cmd));
3036 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3037 mpt_free_msg_frame(ioc, mf);
3038 goto out;
3039 }
3040 if (!timeleft) {
3041 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
3042 ioc->name, __func__);
3043 mpt_HardResetHandler(ioc, CAN_SLEEP);
3044 mpt_free_msg_frame(ioc, mf);
3045 }
3046 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 }
3048
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303049 ret = ioc->internal_cmds.completion_code;
3050 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3051 ioc->name, __func__, ret));
3052
3053 out:
3054 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3055 mutex_unlock(&ioc->internal_cmds.mutex);
3056 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057}
3058
3059/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3060/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003061 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3062 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003063 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003064 *
3065 * Uses the ISR, but with special processing.
3066 * MUST be single-threaded.
3067 *
3068 */
3069static void
3070mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3071{
3072 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
Eric Moorecc78d302007-06-15 17:27:21 -06003074 /* Ignore hidden raid components, this is handled when the command
3075 * is sent to the volume
3076 */
3077 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3078 return;
3079
3080 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3081 !vdevice->configured_lun)
3082 return;
3083
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 /* Following parameters will not change
3085 * in this routine.
3086 */
3087 iocmd.cmd = SYNCHRONIZE_CACHE;
3088 iocmd.flags = 0;
3089 iocmd.physDiskNum = -1;
3090 iocmd.data = NULL;
3091 iocmd.data_dma = -1;
3092 iocmd.size = 0;
3093 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003094 iocmd.channel = vdevice->vtarget->channel;
3095 iocmd.id = vdevice->vtarget->id;
3096 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
Eric Moorecc78d302007-06-15 17:27:21 -06003098 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099}
3100
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303101static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003102mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3103 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303104{
Tony Jonesee959b02008-02-22 00:13:36 +01003105 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003106 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303107 MPT_ADAPTER *ioc = hd->ioc;
3108
3109 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3110 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3111 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3112 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3113 ioc->facts.FWVersion.Word & 0x000000FF);
3114}
Tony Jonesee959b02008-02-22 00:13:36 +01003115static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303116
3117static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003118mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3119 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303120{
Tony Jonesee959b02008-02-22 00:13:36 +01003121 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003122 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303123 MPT_ADAPTER *ioc = hd->ioc;
3124
3125 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3126 (ioc->biosVersion & 0xFF000000) >> 24,
3127 (ioc->biosVersion & 0x00FF0000) >> 16,
3128 (ioc->biosVersion & 0x0000FF00) >> 8,
3129 ioc->biosVersion & 0x000000FF);
3130}
Tony Jonesee959b02008-02-22 00:13:36 +01003131static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303132
3133static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003134mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3135 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303136{
Tony Jonesee959b02008-02-22 00:13:36 +01003137 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003138 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303139 MPT_ADAPTER *ioc = hd->ioc;
3140
3141 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3142}
Tony Jonesee959b02008-02-22 00:13:36 +01003143static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303144
3145static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003146mptscsih_version_product_show(struct device *dev,
3147 struct device_attribute *attr,
3148char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303149{
Tony Jonesee959b02008-02-22 00:13:36 +01003150 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003151 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303152 MPT_ADAPTER *ioc = hd->ioc;
3153
3154 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3155}
Tony Jonesee959b02008-02-22 00:13:36 +01003156static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303157 mptscsih_version_product_show, NULL);
3158
3159static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003160mptscsih_version_nvdata_persistent_show(struct device *dev,
3161 struct device_attribute *attr,
3162 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303163{
Tony Jonesee959b02008-02-22 00:13:36 +01003164 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003165 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303166 MPT_ADAPTER *ioc = hd->ioc;
3167
3168 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3169 ioc->nvdata_version_persistent);
3170}
Tony Jonesee959b02008-02-22 00:13:36 +01003171static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303172 mptscsih_version_nvdata_persistent_show, NULL);
3173
3174static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003175mptscsih_version_nvdata_default_show(struct device *dev,
3176 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303177{
Tony Jonesee959b02008-02-22 00:13:36 +01003178 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003179 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303180 MPT_ADAPTER *ioc = hd->ioc;
3181
3182 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3183}
Tony Jonesee959b02008-02-22 00:13:36 +01003184static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303185 mptscsih_version_nvdata_default_show, NULL);
3186
3187static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003188mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3189 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303190{
Tony Jonesee959b02008-02-22 00:13:36 +01003191 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003192 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303193 MPT_ADAPTER *ioc = hd->ioc;
3194
3195 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3196}
Tony Jonesee959b02008-02-22 00:13:36 +01003197static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303198
3199static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003200mptscsih_board_assembly_show(struct device *dev,
3201 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303202{
Tony Jonesee959b02008-02-22 00:13:36 +01003203 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003204 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303205 MPT_ADAPTER *ioc = hd->ioc;
3206
3207 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3208}
Tony Jonesee959b02008-02-22 00:13:36 +01003209static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303210 mptscsih_board_assembly_show, NULL);
3211
3212static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003213mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3214 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303215{
Tony Jonesee959b02008-02-22 00:13:36 +01003216 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003217 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303218 MPT_ADAPTER *ioc = hd->ioc;
3219
3220 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3221}
Tony Jonesee959b02008-02-22 00:13:36 +01003222static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303223 mptscsih_board_tracer_show, NULL);
3224
3225static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003226mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3227 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303228{
Tony Jonesee959b02008-02-22 00:13:36 +01003229 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003230 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303231 MPT_ADAPTER *ioc = hd->ioc;
3232
3233 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3234}
Tony Jonesee959b02008-02-22 00:13:36 +01003235static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303236 mptscsih_io_delay_show, NULL);
3237
3238static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003239mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3240 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303241{
Tony Jonesee959b02008-02-22 00:13:36 +01003242 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003243 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303244 MPT_ADAPTER *ioc = hd->ioc;
3245
3246 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3247}
Tony Jonesee959b02008-02-22 00:13:36 +01003248static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303249 mptscsih_device_delay_show, NULL);
3250
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303251static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003252mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3253 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303254{
Tony Jonesee959b02008-02-22 00:13:36 +01003255 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003256 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303257 MPT_ADAPTER *ioc = hd->ioc;
3258
3259 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3260}
3261static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003262mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3263 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303264{
Tony Jonesee959b02008-02-22 00:13:36 +01003265 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003266 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303267 MPT_ADAPTER *ioc = hd->ioc;
3268 int val = 0;
3269
3270 if (sscanf(buf, "%x", &val) != 1)
3271 return -EINVAL;
3272
3273 ioc->debug_level = val;
3274 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3275 ioc->name, ioc->debug_level);
3276 return strlen(buf);
3277}
Tony Jonesee959b02008-02-22 00:13:36 +01003278static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3279 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303280
Tony Jonesee959b02008-02-22 00:13:36 +01003281struct device_attribute *mptscsih_host_attrs[] = {
3282 &dev_attr_version_fw,
3283 &dev_attr_version_bios,
3284 &dev_attr_version_mpi,
3285 &dev_attr_version_product,
3286 &dev_attr_version_nvdata_persistent,
3287 &dev_attr_version_nvdata_default,
3288 &dev_attr_board_name,
3289 &dev_attr_board_assembly,
3290 &dev_attr_board_tracer,
3291 &dev_attr_io_delay,
3292 &dev_attr_device_delay,
3293 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303294 NULL,
3295};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303296
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303297EXPORT_SYMBOL(mptscsih_host_attrs);
3298
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003299EXPORT_SYMBOL(mptscsih_remove);
3300EXPORT_SYMBOL(mptscsih_shutdown);
3301#ifdef CONFIG_PM
3302EXPORT_SYMBOL(mptscsih_suspend);
3303EXPORT_SYMBOL(mptscsih_resume);
3304#endif
3305EXPORT_SYMBOL(mptscsih_proc_info);
3306EXPORT_SYMBOL(mptscsih_info);
3307EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003308EXPORT_SYMBOL(mptscsih_slave_destroy);
3309EXPORT_SYMBOL(mptscsih_slave_configure);
3310EXPORT_SYMBOL(mptscsih_abort);
3311EXPORT_SYMBOL(mptscsih_dev_reset);
3312EXPORT_SYMBOL(mptscsih_bus_reset);
3313EXPORT_SYMBOL(mptscsih_host_reset);
3314EXPORT_SYMBOL(mptscsih_bios_param);
3315EXPORT_SYMBOL(mptscsih_io_done);
3316EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3317EXPORT_SYMBOL(mptscsih_scandv_complete);
3318EXPORT_SYMBOL(mptscsih_event_process);
3319EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003320EXPORT_SYMBOL(mptscsih_change_queue_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003322/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/