blob: de8cf92d8614e42fe5252dde6fb51991c8ff84ec [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;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +0530667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 scsi_state = pScsiReply->SCSIState;
669 scsi_status = pScsiReply->SCSIStatus;
670 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900671 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700672 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600674 /*
675 * if we get a data underrun indication, yet no data was
676 * transferred and the SCSI status indicates that the
677 * command was never started, change the data underrun
678 * to success
679 */
680 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
681 (scsi_status == MPI_SCSI_STATUS_BUSY ||
682 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
683 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
684 status = MPI_IOCSTATUS_SUCCESS;
685 }
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400688 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
689
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 /*
691 * Look for + dump FCP ResponseInfo[]!
692 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600693 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
694 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600695 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
696 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700697 sc->device->host->host_no, sc->device->channel,
698 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 le32_to_cpu(pScsiReply->ResponseInfo));
700 }
701
702 switch(status) {
703 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
Kashyap, Desaid23321b2009-08-05 12:51:25 +0530704 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 /* CHECKME!
706 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
707 * But not: DID_BUS_BUSY lest one risk
708 * killing interrupt handler:-(
709 */
710 sc->result = SAM_STAT_BUSY;
711 break;
712
713 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
714 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
715 sc->result = DID_BAD_TARGET << 16;
716 break;
717
718 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
719 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600720 if (ioc->bus_type != FC)
721 sc->result = DID_NO_CONNECT << 16;
722 /* else fibre, just stall until rescan event */
723 else
724 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
727 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600728
Eric Moorea69de502007-09-14 18:48:19 -0600729 vdevice = sc->device->hostdata;
730 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600731 break;
Eric Moorea69de502007-09-14 18:48:19 -0600732 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600733 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
734 mptscsih_issue_sep_command(ioc, vtarget,
735 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
736 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 break;
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600741 if ( ioc->bus_type == SAS ) {
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +0530742 u16 ioc_status =
743 le16_to_cpu(pScsiReply->IOCStatus);
744 if ((ioc_status &
745 MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
746 &&
747 ((log_info & SAS_LOGINFO_MASK) ==
748 SAS_LOGINFO_NEXUS_LOSS)) {
749 VirtDevice *vdevice =
750 sc->device->hostdata;
751
752 /* flag the device as being in
753 * device removal delay so we can
754 * notify the midlayer to hold off
755 * on timeout eh */
756 if (vdevice && vdevice->
757 vtarget &&
758 vdevice->vtarget->
759 raidVolume)
760 printk(KERN_INFO
761 "Skipping Raid Volume"
762 "for inDMD\n");
763 else if (vdevice &&
764 vdevice->vtarget)
765 vdevice->vtarget->
766 inDMD = 1;
767
768 sc->result =
769 (DID_TRANSPORT_DISRUPTED
770 << 16);
771 break;
Eric Moorebf451522006-07-11 17:25:35 -0600772 }
Eric Moore86dd4242007-01-04 20:44:01 -0700773 } else if (ioc->bus_type == FC) {
774 /*
775 * The FC IOC may kill a request for variety of
776 * reasons, some of which may be recovered by a
777 * retry, some which are unlikely to be
778 * recovered. Return DID_ERROR instead of
779 * DID_RESET to permit retry of the command,
780 * just not an infinite number of them
781 */
782 sc->result = DID_ERROR << 16;
783 break;
Eric Moorebf451522006-07-11 17:25:35 -0600784 }
785
786 /*
787 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
788 */
789
790 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 /* Linux handles an unsolicited DID_RESET better
792 * than an unsolicited DID_ABORT.
793 */
794 sc->result = DID_RESET << 16;
795
Kashyap, Desai2f187862009-05-29 16:52:37 +0530796 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
797 if (ioc->bus_type == FC)
798 sc->result = DID_ERROR << 16;
799 else
800 sc->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 break;
802
803 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900804 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600805 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
806 sc->result=DID_SOFT_ERROR << 16;
807 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600809 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700810 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600811 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
815 /*
816 * Do upfront check for valid SenseData and give it
817 * precedence!
818 */
819 sc->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530820 if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
821
822 /*
823 * For an Errata on LSI53C1030
824 * When the length of request data
825 * and transfer data are different
826 * with result of command (READ or VERIFY),
827 * DID_SOFT_ERROR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 */
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530829 if (ioc->bus_type == SPI) {
Kashyap, Desaie466e1c2011-07-20 21:28:03 +0530830 if ((pScsiReq->CDB[0] == READ_6 && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530831 pScsiReq->CDB[0] == READ_10 ||
832 pScsiReq->CDB[0] == READ_12 ||
833 pScsiReq->CDB[0] == READ_16 ||
834 pScsiReq->CDB[0] == VERIFY ||
835 pScsiReq->CDB[0] == VERIFY_16) {
836 if (scsi_bufflen(sc) !=
837 xfer_cnt) {
838 sc->result =
839 DID_SOFT_ERROR << 16;
840 printk(KERN_WARNING "Errata"
841 "on LSI53C1030 occurred."
842 "sc->req_bufflen=0x%02x,"
843 "xfer_cnt=0x%02x\n",
844 scsi_bufflen(sc),
845 xfer_cnt);
846 }
847 }
848 }
849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600851 if (scsi_status == SAM_STAT_BUSY)
852 sc->result = SAM_STAT_BUSY;
853 else
854 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
856 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
857 /* What to do?
858 */
859 sc->result = DID_SOFT_ERROR << 16;
860 }
861 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
862 /* Not real sure here either... */
863 sc->result = DID_RESET << 16;
864 }
865 }
866
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530867
Eric Moore29dd3602007-09-14 18:46:51 -0600868 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
869 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
870 ioc->name, sc->underflow));
871 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
872 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 /* Report Queue Full
875 */
876 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
877 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 break;
880
Moore, Eric7e551472006-01-16 18:53:21 -0700881 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900882 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
884 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600885 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 if (scsi_state == 0) {
887 ;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530888 } else if (scsi_state &
889 MPI_SCSI_STATE_AUTOSENSE_VALID) {
890
891 /*
892 * For potential trouble on LSI53C1030.
893 * (date:2007.xx.)
894 * It is checked whether the length of
895 * request data is equal to
896 * the length of transfer and residual.
897 * MEDIUM_ERROR is set by incorrect data.
898 */
899 if ((ioc->bus_type == SPI) &&
900 (sc->sense_buffer[2] & 0x20)) {
901 u32 difftransfer;
902 difftransfer =
903 sc->sense_buffer[3] << 24 |
904 sc->sense_buffer[4] << 16 |
905 sc->sense_buffer[5] << 8 |
906 sc->sense_buffer[6];
907 if (((sc->sense_buffer[3] & 0x80) ==
908 0x80) && (scsi_bufflen(sc)
909 != xfer_cnt)) {
910 sc->sense_buffer[2] =
911 MEDIUM_ERROR;
912 sc->sense_buffer[12] = 0xff;
913 sc->sense_buffer[13] = 0xff;
914 printk(KERN_WARNING"Errata"
915 "on LSI53C1030 occurred."
916 "sc->req_bufflen=0x%02x,"
917 "xfer_cnt=0x%02x\n" ,
918 scsi_bufflen(sc),
919 xfer_cnt);
920 }
921 if (((sc->sense_buffer[3] & 0x80)
922 != 0x80) &&
923 (scsi_bufflen(sc) !=
924 xfer_cnt + difftransfer)) {
925 sc->sense_buffer[2] =
926 MEDIUM_ERROR;
927 sc->sense_buffer[12] = 0xff;
928 sc->sense_buffer[13] = 0xff;
929 printk(KERN_WARNING
930 "Errata on LSI53C1030 occurred"
931 "sc->req_bufflen=0x%02x,"
932 " xfer_cnt=0x%02x,"
933 "difftransfer=0x%02x\n",
934 scsi_bufflen(sc),
935 xfer_cnt,
936 difftransfer);
937 }
938 }
939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /*
941 * If running against circa 200003dd 909 MPT f/w,
942 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
943 * (QUEUE_FULL) returned from device! --> get 0x0000?128
944 * and with SenseBytes set to 0.
945 */
946 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
947 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
948
949 }
950 else if (scsi_state &
951 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
952 ) {
953 /*
954 * What to do?
955 */
956 sc->result = DID_SOFT_ERROR << 16;
957 }
958 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
959 /* Not real sure here either... */
960 sc->result = DID_RESET << 16;
961 }
962 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
963 /* Device Inq. data indicates that it supports
964 * QTags, but rejects QTag messages.
965 * This command completed OK.
966 *
967 * Not real sure here either so do nothing... */
968 }
969
970 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
971 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
972
973 /* Add handling of:
974 * Reservation Conflict, Busy,
975 * Command Terminated, CHECK
976 */
977 break;
978
979 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
980 sc->result = DID_SOFT_ERROR << 16;
981 break;
982
983 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
984 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
985 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
986 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
988 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
990 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
991 default:
992 /*
993 * What to do?
994 */
995 sc->result = DID_SOFT_ERROR << 16;
996 break;
997
998 } /* switch(status) */
999
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301000#ifdef CONFIG_FUSION_LOGGING
1001 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
1002 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -07001003#endif
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 } /* end of address reply case */
Kashyap, Desaifea98402009-09-02 11:45:53 +05301006out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001008 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 sc->scsi_done(sc); /* Issue the command callback */
1011
1012 /* Free Chain buffers */
1013 mptscsih_freeChainBuffers(ioc, req_idx);
1014 return 1;
1015}
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017/*
1018 * mptscsih_flush_running_cmds - For each command found, search
1019 * Scsi_Host instance taskQ and reply to OS.
1020 * Called only if recovering from a FW reload.
1021 * @hd: Pointer to a SCSI HOST structure
1022 *
1023 * Returns: None.
1024 *
1025 * Must be called while new I/Os are being queued.
1026 */
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +05301027void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
1029{
1030 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001031 struct scsi_cmnd *sc;
1032 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 int ii;
Eric Mooree8206382007-09-29 10:16:53 -06001034 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Eric Mooree8206382007-09-29 10:16:53 -06001036 for (ii= 0; ii < ioc->req_depth; ii++) {
1037 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
1038 if (!sc)
1039 continue;
1040 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
1041 if (!mf)
1042 continue;
1043 channel = mf->Bus;
1044 id = mf->TargetID;
1045 mptscsih_freeChainBuffers(ioc, ii);
1046 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1047 if ((unsigned char *)mf != sc->host_scribble)
1048 continue;
1049 scsi_dma_unmap(sc);
1050 sc->result = DID_RESET << 16;
1051 sc->host_scribble = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301052 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
1053 "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
1054 "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
Eric Mooree8206382007-09-29 10:16:53 -06001055 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057}
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +05301058EXPORT_SYMBOL(mptscsih_flush_running_cmds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060/*
1061 * mptscsih_search_running_cmds - Delete any commands associated
1062 * with the specified target and lun. Function called only
1063 * when a lun is disable by mid-layer.
1064 * Do NOT access the referenced scsi_cmnd structure or
1065 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001066 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001067 * @hd: Pointer to a SCSI HOST structure
1068 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 *
1070 * Returns: None.
1071 *
1072 * Called from slave_destroy.
1073 */
1074static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001075mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
1077 SCSIIORequest_t *mf = NULL;
1078 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001079 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001080 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -06001081 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001082 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Eric Mooree8206382007-09-29 10:16:53 -06001084 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1085 for (ii = 0; ii < ioc->req_depth; ii++) {
1086 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
Eric Mooree80b0022007-09-14 18:49:03 -06001088 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001089 if (mf == NULL)
1090 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001091 /* If the device is a hidden raid component, then its
1092 * expected that the mf->function will be RAID_SCSI_IO
1093 */
1094 if (vdevice->vtarget->tflags &
1095 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1096 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1097 continue;
1098
Eric Moore793955f2007-01-29 09:42:20 -07001099 int_to_scsilun(vdevice->lun, &lun);
1100 if ((mf->Bus != vdevice->vtarget->channel) ||
1101 (mf->TargetID != vdevice->vtarget->id) ||
1102 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 continue;
1104
Eric Moore3dc0b032006-07-11 17:32:33 -06001105 if ((unsigned char *)mf != sc->host_scribble)
1106 continue;
Eric Mooree8206382007-09-29 10:16:53 -06001107 ioc->ScsiLookup[ii] = NULL;
1108 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1109 mptscsih_freeChainBuffers(ioc, ii);
1110 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001111 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001112 sc->host_scribble = NULL;
1113 sc->result = DID_NO_CONNECT << 16;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301114 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
1115 MYIOC_s_FMT "completing cmds: fw_channel %d, "
1116 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
1117 vdevice->vtarget->channel, vdevice->vtarget->id,
1118 sc, mf, ii));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001119 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001120 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122 }
Eric Mooree8206382007-09-29 10:16:53 -06001123 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return;
1125}
1126
1127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1130/*
1131 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1132 * from a SCSI target device.
1133 * @sc: Pointer to scsi_cmnd structure
1134 * @pScsiReply: Pointer to SCSIIOReply_t
1135 * @pScsiReq: Pointer to original SCSI request
1136 *
1137 * This routine periodically reports QUEUE_FULL status returned from a
1138 * SCSI target device. It reports this to the console via kernel
1139 * printk() API call, not more than once every 10 seconds.
1140 */
1141static void
1142mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1143{
1144 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001146 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001148 if (sc->device == NULL)
1149 return;
1150 if (sc->device->host == NULL)
1151 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001152 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001153 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001154 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001156 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1157 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001158 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160}
1161
1162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1163/*
1164 * mptscsih_remove - Removed scsi devices
1165 * @pdev: Pointer to pci_dev structure
1166 *
1167 *
1168 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001169void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170mptscsih_remove(struct pci_dev *pdev)
1171{
1172 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1173 struct Scsi_Host *host = ioc->sh;
1174 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001175 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 scsi_remove_host(host);
1178
Eric Mooree7eae9f2007-09-29 10:15:59 -06001179 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180 return;
1181
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001182 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001184 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
Eric Mooree8206382007-09-29 10:16:53 -06001186 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001187 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001188 kfree(ioc->ScsiLookup);
1189 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 }
1191
Eric Mooree80b0022007-09-14 18:49:03 -06001192 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001193 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001194 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001195
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001196 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001197
1198 /* NULL the Scsi_Host pointer
1199 */
Eric Mooree80b0022007-09-14 18:49:03 -06001200 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001201
1202 scsi_host_put(host);
1203
1204 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206}
1207
1208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1209/*
1210 * mptscsih_shutdown - reboot notifier
1211 *
1212 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001213void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001214mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216}
1217
1218#ifdef CONFIG_PM
1219/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1220/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001221 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 *
1223 *
1224 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001225int
Pavel Machek8d189f72005-04-16 15:25:28 -07001226mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301228 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1229
1230 scsi_block_requests(ioc->sh);
1231 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001232 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001233 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234}
1235
1236/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1237/*
1238 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1239 *
1240 *
1241 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001242int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243mptscsih_resume(struct pci_dev *pdev)
1244{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301245 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1246 int rc;
1247
1248 rc = mpt_resume(pdev);
1249 scsi_unblock_requests(ioc->sh);
1250 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251}
1252
1253#endif
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1256/**
1257 * mptscsih_info - Return information about MPT adapter
1258 * @SChost: Pointer to Scsi_Host structure
1259 *
1260 * (linux scsi_host_template.info routine)
1261 *
1262 * Returns pointer to buffer where information was written.
1263 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001264const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265mptscsih_info(struct Scsi_Host *SChost)
1266{
1267 MPT_SCSI_HOST *h;
1268 int size = 0;
1269
Eric Mooree7eae9f2007-09-29 10:15:59 -06001270 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001273 if (h->info_kbuf == NULL)
1274 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1275 return h->info_kbuf;
1276 h->info_kbuf[0] = '\0';
1277
1278 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1279 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 }
1281
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001282 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283}
1284
1285struct info_str {
1286 char *buffer;
1287 int length;
1288 int offset;
1289 int pos;
1290};
1291
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001292static void
1293mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
1295 if (info->pos + len > info->length)
1296 len = info->length - info->pos;
1297
1298 if (info->pos + len < info->offset) {
1299 info->pos += len;
1300 return;
1301 }
1302
1303 if (info->pos < info->offset) {
1304 data += (info->offset - info->pos);
1305 len -= (info->offset - info->pos);
1306 }
1307
1308 if (len > 0) {
1309 memcpy(info->buffer + info->pos, data, len);
1310 info->pos += len;
1311 }
1312}
1313
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001314static int
1315mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316{
1317 va_list args;
1318 char buf[81];
1319 int len;
1320
1321 va_start(args, fmt);
1322 len = vsprintf(buf, fmt, args);
1323 va_end(args);
1324
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001325 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 return len;
1327}
1328
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001329static int
1330mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331{
1332 struct info_str info;
1333
1334 info.buffer = pbuf;
1335 info.length = len;
1336 info.offset = offset;
1337 info.pos = 0;
1338
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001339 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1340 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1341 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1342 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1345}
1346
1347/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1348/**
1349 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001350 * @host: scsi host struct
1351 * @buffer: if write, user data; if read, buffer for user
1352 * @start: returns the buffer address
1353 * @offset: if write, 0; if read, the current offset into the buffer from
1354 * the previous read.
1355 * @length: if write, return length;
1356 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 *
1358 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001360int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1362 int length, int func)
1363{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001364 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 MPT_ADAPTER *ioc = hd->ioc;
1366 int size = 0;
1367
1368 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001369 /*
1370 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 */
1372 } else {
1373 if (start)
1374 *start = buffer;
1375
1376 size = mptscsih_host_info(ioc, buffer, offset, length);
1377 }
1378
1379 return size;
1380}
1381
1382/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1383#define ADD_INDEX_LOG(req_ent) do { } while(0)
1384
1385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1386/**
1387 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1388 * @SCpnt: Pointer to scsi_cmnd structure
1389 * @done: Pointer SCSI mid-layer IO completion function
1390 *
1391 * (linux scsi_host_template.queuecommand routine)
1392 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1393 * from a linux scsi_cmnd request and send it to the IOC.
1394 *
1395 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1396 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001397int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1399{
1400 MPT_SCSI_HOST *hd;
1401 MPT_FRAME_HDR *mf;
1402 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001403 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 u32 datalen;
1405 u32 scsictl;
1406 u32 scsidir;
1407 u32 cmd_len;
1408 int my_idx;
1409 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301410 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Eric Mooree7eae9f2007-09-29 10:15:59 -06001412 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301413 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 SCpnt->scsi_done = done;
1415
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301416 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1417 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Kashyap, Desai56cee8d2011-04-26 12:09:15 +05301419 if (ioc->taskmgmt_quiesce_io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422 /*
1423 * Put together a MPT SCSI request...
1424 */
Eric Mooree80b0022007-09-14 18:49:03 -06001425 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301426 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1427 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 return SCSI_MLQUEUE_HOST_BUSY;
1429 }
1430
1431 pScsiReq = (SCSIIORequest_t *) mf;
1432
1433 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1434
1435 ADD_INDEX_LOG(my_idx);
1436
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001437 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 * Seems we may receive a buffer (datalen>0) even when there
1439 * will be no data transfer! GRRRRR...
1440 */
1441 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001442 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1444 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001445 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1447 } else {
1448 datalen = 0;
1449 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1450 }
1451
1452 /* Default to untagged. Once a target structure has been allocated,
1453 * use the Inquiry data to determine if device supports tagged.
1454 */
Eric Moorea69de502007-09-14 18:48:19 -06001455 if (vdevice
1456 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 && (SCpnt->device->tagged_supported)) {
1458 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai65f89c22009-12-16 19:01:13 +05301459 if (SCpnt->request && SCpnt->request->ioprio) {
1460 if (((SCpnt->request->ioprio & 0x7) == 1) ||
1461 !(SCpnt->request->ioprio & 0x7))
1462 scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ;
1463 }
1464 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
Kashyap, Desai65f89c22009-12-16 19:01:13 +05301466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 /* Use the above information to set up the message frame
1469 */
Eric Moorea69de502007-09-14 18:48:19 -06001470 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1471 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001473 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001474 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1475 else
1476 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 pScsiReq->CDBLength = SCpnt->cmd_len;
1478 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1479 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301480 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001481 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 pScsiReq->Control = cpu_to_le32(scsictl);
1483
1484 /*
1485 * Write SCSI CDB into the message
1486 */
1487 cmd_len = SCpnt->cmd_len;
1488 for (ii=0; ii < cmd_len; ii++)
1489 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1490
1491 for (ii=cmd_len; ii < 16; ii++)
1492 pScsiReq->CDB[ii] = 0;
1493
1494 /* DataLength */
1495 pScsiReq->DataLength = cpu_to_le32(datalen);
1496
1497 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001498 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1500
1501 /* Now add the SG list
1502 * Always have a SGE even if null length.
1503 */
1504 if (datalen == 0) {
1505 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301506 ioc->add_sge((char *)&pScsiReq->SGL,
1507 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 (dma_addr_t) -1);
1509 } else {
1510 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001511 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 goto fail;
1513 }
1514
Eric Moore3dc0b032006-07-11 17:32:33 -06001515 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001516 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Eric Mooree80b0022007-09-14 18:49:03 -06001518 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301519 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1520 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001521 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 return 0;
1523
1524 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001525 mptscsih_freeChainBuffers(ioc, my_idx);
1526 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 return SCSI_MLQUEUE_HOST_BUSY;
1528}
1529
1530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1531/*
1532 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1533 * with a SCSI IO request
1534 * @hd: Pointer to the MPT_SCSI_HOST instance
1535 * @req_idx: Index of the SCSI IO request frame.
1536 *
1537 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1538 * No return.
1539 */
1540static void
1541mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1542{
1543 MPT_FRAME_HDR *chain;
1544 unsigned long flags;
1545 int chain_idx;
1546 int next;
1547
1548 /* Get the first chain index and reset
1549 * tracker state.
1550 */
1551 chain_idx = ioc->ReqToChain[req_idx];
1552 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1553
1554 while (chain_idx != MPT_HOST_NO_CHAIN) {
1555
1556 /* Save the next chain buffer index */
1557 next = ioc->ChainToChain[chain_idx];
1558
1559 /* Free this chain buffer and reset
1560 * tracker
1561 */
1562 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1563
1564 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1565 + (chain_idx * ioc->req_sz));
1566
1567 spin_lock_irqsave(&ioc->FreeQlock, flags);
1568 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1569 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1570
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301571 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 ioc->name, chain_idx));
1573
1574 /* handle next */
1575 chain_idx = next;
1576 }
1577 return;
1578}
1579
1580/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1581/*
1582 * Reset Handling
1583 */
1584
1585/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001586/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1588 * @hd: Pointer to MPT_SCSI_HOST structure
1589 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001590 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001591 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 * @lun: Logical Unit for reset (if appropriate)
1593 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001594 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 *
1596 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1597 * or a non-interrupt thread. In the former, must not call schedule().
1598 *
1599 * Not all fields are meaningfull for all task types.
1600 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001601 * Returns 0 for SUCCESS, or FAILED.
1602 *
1603 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301604int
1605mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1606 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
1608 MPT_FRAME_HDR *mf;
1609 SCSITaskMgmt_t *pScsiTm;
1610 int ii;
1611 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001612 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301613 unsigned long timeleft;
1614 u8 issue_hard_reset;
1615 u32 ioc_raw_state;
1616 unsigned long time_count;
1617
1618 issue_hard_reset = 0;
1619 ioc_raw_state = mpt_GetIocState(ioc, 0);
1620
1621 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1622 printk(MYIOC_s_WARN_FMT
1623 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1624 ioc->name, type, ioc_raw_state);
1625 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1626 ioc->name, __func__);
1627 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1628 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1629 "FAILED!!\n", ioc->name);
1630 return 0;
1631 }
1632
1633 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1634 printk(MYIOC_s_WARN_FMT
1635 "TaskMgmt type=%x: ioc_state: "
1636 "DOORBELL_ACTIVE (0x%x)!\n",
1637 ioc->name, type, ioc_raw_state);
1638 return FAILED;
1639 }
1640
1641 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1642 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1643 mf = NULL;
1644 retval = FAILED;
1645 goto out;
1646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
1648 /* Return Fail to calling function if no message frames available.
1649 */
Eric Mooree80b0022007-09-14 18:49:03 -06001650 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301651 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1652 "TaskMgmt no msg frames!!\n", ioc->name));
1653 retval = FAILED;
1654 mpt_clear_taskmgmt_in_progress_flag(ioc);
1655 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301657 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001658 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660 /* Format the Request
1661 */
1662 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001663 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 pScsiTm->Bus = channel;
1665 pScsiTm->ChainOffset = 0;
1666 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1667
1668 pScsiTm->Reserved = 0;
1669 pScsiTm->TaskType = type;
1670 pScsiTm->Reserved1 = 0;
1671 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1672 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1673
Eric Moore793955f2007-01-29 09:42:20 -07001674 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
1676 for (ii=0; ii < 7; ii++)
1677 pScsiTm->Reserved2[ii] = 0;
1678
1679 pScsiTm->TaskMsgContext = ctx2abort;
1680
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301681 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1682 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1683 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301685 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301687 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1688 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001689 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1690 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1691 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301692 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001693 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301694 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1695 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301696 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1697 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1698 ioc->name, mf, retval));
1699 mpt_free_msg_frame(ioc, mf);
1700 mpt_clear_taskmgmt_in_progress_flag(ioc);
1701 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 }
1704
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301705 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1706 timeout*HZ);
1707 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1708 retval = FAILED;
1709 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1710 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1711 mpt_clear_taskmgmt_in_progress_flag(ioc);
1712 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1713 goto out;
1714 issue_hard_reset = 1;
1715 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301718 retval = mptscsih_taskmgmt_reply(ioc, type,
1719 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001720
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301721 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1722 "TaskMgmt completed (%d seconds)\n",
1723 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1724
1725 out:
1726
1727 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1728 if (issue_hard_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09001729 printk(MYIOC_s_WARN_FMT
1730 "Issuing Reset from %s!! doorbell=0x%08x\n",
1731 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05301732 retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301733 mpt_free_msg_frame(ioc, mf);
1734 }
1735
1736 retval = (retval == 0) ? 0 : FAILED;
1737 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 return retval;
1739}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301740EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001742static int
1743mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1744{
1745 switch (ioc->bus_type) {
1746 case FC:
1747 return 40;
1748 case SAS:
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301749 return 30;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001750 case SPI:
1751 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001752 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001753 }
1754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1757/**
1758 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1759 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1760 *
1761 * (linux scsi_host_template.eh_abort_handler routine)
1762 *
1763 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001764 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001765int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766mptscsih_abort(struct scsi_cmnd * SCpnt)
1767{
1768 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 MPT_FRAME_HDR *mf;
1770 u32 ctx2abort;
1771 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001772 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001773 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001774 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
1776 /* If we can't locate our host adapter structure, return FAILED status.
1777 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001778 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 SCpnt->result = DID_RESET << 16;
1780 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001781 printk(KERN_ERR MYNAM ": task abort: "
1782 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 return FAILED;
1784 }
1785
Eric Moore958d4a32007-06-15 17:24:14 -06001786 ioc = hd->ioc;
1787 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1788 ioc->name, SCpnt);
1789 scsi_print_command(SCpnt);
1790
1791 vdevice = SCpnt->device->hostdata;
1792 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001793 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1794 "task abort: device has been deleted (sc=%p)\n",
1795 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001796 SCpnt->result = DID_NO_CONNECT << 16;
1797 SCpnt->scsi_done(SCpnt);
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301798 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001799 goto out;
1800 }
1801
Eric Moorecc78d302007-06-15 17:27:21 -06001802 /* Task aborts are not supported for hidden raid components.
1803 */
1804 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001805 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1806 "task abort: hidden raid component (sc=%p)\n",
1807 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001808 SCpnt->result = DID_RESET << 16;
1809 retval = FAILED;
1810 goto out;
1811 }
1812
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301813 /* Task aborts are not supported for volumes.
1814 */
1815 if (vdevice->vtarget->raidVolume) {
1816 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1817 "task abort: raid volume (sc=%p)\n",
1818 ioc->name, SCpnt));
1819 SCpnt->result = DID_RESET << 16;
1820 retval = FAILED;
1821 goto out;
1822 }
1823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 /* Find this command
1825 */
Eric Mooree8206382007-09-29 10:16:53 -06001826 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001827 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 * Do OS callback.
1829 */
1830 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001831 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001832 "Command not in the active list! (sc=%p)\n", ioc->name,
1833 SCpnt));
Kashyap, Desai9858ae32010-01-25 16:20:52 +05301834 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001835 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 }
1837
Kashyap, Desai2f187862009-05-29 16:52:37 +05301838 if (ioc->timeouts < -1)
1839 ioc->timeouts++;
Moore, Eric65207fe2006-04-21 16:14:35 -06001840
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301841 if (mpt_fwfault_debug)
1842 mpt_halt_firmware(ioc);
1843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1845 * (the IO to be ABORT'd)
1846 *
1847 * NOTE: Since we do not byteswap MsgContext, we do not
1848 * swap it here either. It is an opaque cookie to
1849 * the controller, so it does not matter. -DaveM
1850 */
Eric Mooree80b0022007-09-14 18:49:03 -06001851 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301853 retval = mptscsih_IssueTaskMgmt(hd,
1854 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1855 vdevice->vtarget->channel,
1856 vdevice->vtarget->id, vdevice->lun,
1857 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001859 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05301860 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1861 "task abort: command still in active list! (sc=%p)\n",
1862 ioc->name, SCpnt));
Eric Moore3dc0b032006-07-11 17:32:33 -06001863 retval = FAILED;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301864 } else {
1865 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1866 "task abort: command cleared from active list! (sc=%p)\n",
1867 ioc->name, SCpnt));
1868 retval = SUCCESS;
1869 }
Eric Moore3dc0b032006-07-11 17:32:33 -06001870
Eric Moore958d4a32007-06-15 17:24:14 -06001871 out:
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001872 printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
Kashyap, Desaibcfe42e2011-02-10 11:53:44 +05301873 ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001874 SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
Kashyap, Desai2f187862009-05-29 16:52:37 +05301876 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877}
1878
1879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1880/**
1881 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1882 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1883 *
1884 * (linux scsi_host_template.eh_dev_reset_handler routine)
1885 *
1886 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001887 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001888int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1890{
1891 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001892 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001893 VirtDevice *vdevice;
1894 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 /* If we can't locate our host adapter structure, return FAILED status.
1897 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001898 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001899 printk(KERN_ERR MYNAM ": target reset: "
1900 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 return FAILED;
1902 }
1903
Eric Moore958d4a32007-06-15 17:24:14 -06001904 ioc = hd->ioc;
1905 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1906 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001907 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Eric Moore958d4a32007-06-15 17:24:14 -06001909 vdevice = SCpnt->device->hostdata;
1910 if (!vdevice || !vdevice->vtarget) {
Kashyap, Desaibcfe42e2011-02-10 11:53:44 +05301911 retval = 0;
Eric Moore958d4a32007-06-15 17:24:14 -06001912 goto out;
1913 }
1914
Eric Moorecc78d302007-06-15 17:27:21 -06001915 /* Target reset to hidden raid component is not supported
1916 */
1917 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1918 retval = FAILED;
1919 goto out;
1920 }
1921
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301922 retval = mptscsih_IssueTaskMgmt(hd,
1923 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1924 vdevice->vtarget->channel,
1925 vdevice->vtarget->id, 0, 0,
1926 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001927
1928 out:
1929 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1930 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001931
1932 if (retval == 0)
1933 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001934 else
1935 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936}
1937
Eric Moorecd2c6192007-01-29 09:47:47 -07001938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1940/**
1941 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1942 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1943 *
1944 * (linux scsi_host_template.eh_bus_reset_handler routine)
1945 *
1946 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001947 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001948int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1950{
1951 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001952 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001953 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001954 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
1956 /* If we can't locate our host adapter structure, return FAILED status.
1957 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001958 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001959 printk(KERN_ERR MYNAM ": bus reset: "
1960 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return FAILED;
1962 }
1963
Eric Moore958d4a32007-06-15 17:24:14 -06001964 ioc = hd->ioc;
1965 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1966 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001967 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Kashyap, Desai2f187862009-05-29 16:52:37 +05301969 if (ioc->timeouts < -1)
1970 ioc->timeouts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
Eric Moorea69de502007-09-14 18:48:19 -06001972 vdevice = SCpnt->device->hostdata;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301973 if (!vdevice || !vdevice->vtarget)
1974 return SUCCESS;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301975 retval = mptscsih_IssueTaskMgmt(hd,
1976 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1977 vdevice->vtarget->channel, 0, 0, 0,
1978 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979
Eric Moore958d4a32007-06-15 17:24:14 -06001980 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1981 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001982
1983 if (retval == 0)
1984 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001985 else
1986 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987}
1988
1989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1990/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001991 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1993 *
1994 * (linux scsi_host_template.eh_host_reset_handler routine)
1995 *
1996 * Returns SUCCESS or FAILED.
1997 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001998int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2000{
2001 MPT_SCSI_HOST * hd;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302002 int status = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06002003 MPT_ADAPTER *ioc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302004 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
2006 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06002007 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06002008 printk(KERN_ERR MYNAM ": host reset: "
2009 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 return FAILED;
2011 }
2012
James Bottomleya6da74c2008-12-15 14:13:27 -06002013 /* make sure we have no outstanding commands at this stage */
2014 mptscsih_flush_running_cmds(hd);
2015
Eric Moore958d4a32007-06-15 17:24:14 -06002016 ioc = hd->ioc;
2017 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2018 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
2020 /* If our attempts to reset the host failed, then return a failed
2021 * status. The host will be taken off line by the SCSI mid-layer.
2022 */
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302023 retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302024 if (retval < 0)
2025 status = FAILED;
2026 else
2027 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Eric Moore958d4a32007-06-15 17:24:14 -06002029 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2030 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031
Kashyap, Desai2f187862009-05-29 16:52:37 +05302032 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033}
2034
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302036mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
2037 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302039 u16 iocstatus;
2040 u32 termination_count;
2041 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302043 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
2044 retval = FAILED;
2045 goto out;
2046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302048 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302050 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2051 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302053 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2054 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
2055 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
2056 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
2057 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
2058 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
2059 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302061 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2062 pScsiTmReply->ResponseCode)
2063 mptscsih_taskmgmt_response_code(ioc,
2064 pScsiTmReply->ResponseCode);
2065
2066 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
2067 retval = 0;
2068 goto out;
2069 }
2070
2071 retval = FAILED;
2072 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
2073 if (termination_count == 1)
2074 retval = 0;
2075 goto out;
2076 }
2077
2078 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
2079 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
2080 retval = 0;
2081
2082 out:
2083 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084}
2085
2086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302087void
Moore, Eric9f63bb72006-01-16 18:53:26 -07002088mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2089{
2090 char *desc;
2091
2092 switch (response_code) {
2093 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2094 desc = "The task completed.";
2095 break;
2096 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2097 desc = "The IOC received an invalid frame status.";
2098 break;
2099 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2100 desc = "The task type is not supported.";
2101 break;
2102 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2103 desc = "The requested task failed.";
2104 break;
2105 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2106 desc = "The task completed successfully.";
2107 break;
2108 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2109 desc = "The LUN request is invalid.";
2110 break;
2111 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2112 desc = "The task is in the IOC queue and has not been sent to target.";
2113 break;
2114 default:
2115 desc = "unknown";
2116 break;
2117 }
2118 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2119 ioc->name, response_code, desc);
2120}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302121EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07002122
2123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124/**
2125 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2126 * @ioc: Pointer to MPT_ADAPTER structure
2127 * @mf: Pointer to SCSI task mgmt request frame
2128 * @mr: Pointer to SCSI task mgmt reply frame
2129 *
2130 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2131 * of any SCSI task management request.
2132 * This routine is registered with the MPT (base) driver at driver
2133 * load/init time via the mpt_register() API call.
2134 *
2135 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002136 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002137int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302138mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2139 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302141 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2142 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302144 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302146 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002147 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002148
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302149 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2150 memcpy(ioc->taskmgmt_cmds.reply, mr,
2151 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002152 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302153 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2154 mpt_clear_taskmgmt_in_progress_flag(ioc);
2155 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2156 complete(&ioc->taskmgmt_cmds.done);
Kashyap, Desaib68bf092010-06-17 14:40:56 +05302157 if (ioc->bus_type == SAS)
2158 ioc->schedule_target_reset(ioc);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302159 return 1;
2160 }
2161 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162}
2163
2164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2165/*
2166 * This is anyones guess quite frankly.
2167 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002168int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2170 sector_t capacity, int geom[])
2171{
2172 int heads;
2173 int sectors;
2174 sector_t cylinders;
2175 ulong dummy;
2176
2177 heads = 64;
2178 sectors = 32;
2179
2180 dummy = heads * sectors;
2181 cylinders = capacity;
2182 sector_div(cylinders,dummy);
2183
2184 /*
2185 * Handle extended translation size for logical drives
2186 * > 1Gb
2187 */
2188 if ((ulong)capacity >= 0x200000) {
2189 heads = 255;
2190 sectors = 63;
2191 dummy = heads * sectors;
2192 cylinders = capacity;
2193 sector_div(cylinders,dummy);
2194 }
2195
2196 /* return result */
2197 geom[0] = heads;
2198 geom[1] = sectors;
2199 geom[2] = cylinders;
2200
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 return 0;
2202}
2203
Moore, Ericf44e5462006-03-14 09:14:21 -07002204/* Search IOC page 3 to determine if this is hidden physical disk
2205 *
2206 */
2207int
Eric Moore793955f2007-01-29 09:42:20 -07002208mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002209{
Eric Mooreb506ade2007-01-29 09:45:37 -07002210 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302211 int i, j;
2212 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002213 int rc = 0;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302214 int num_paths;
Moore, Ericf44e5462006-03-14 09:14:21 -07002215
Eric Moore793955f2007-01-29 09:42:20 -07002216 if (!ioc->raid_data.pIocPg3)
2217 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002218 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002219 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2220 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2221 rc = 1;
2222 goto out;
2223 }
2224 }
2225
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302226 if (ioc->bus_type != SAS)
2227 goto out;
2228
2229 /*
2230 * Check if dual path
2231 */
2232 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2233 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2234 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2235 if (num_paths < 2)
2236 continue;
2237 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2238 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2239 if (!phys_disk)
2240 continue;
2241 if ((mpt_raid_phys_disk_pg1(ioc,
2242 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2243 phys_disk))) {
2244 kfree(phys_disk);
2245 continue;
2246 }
2247 for (j = 0; j < num_paths; j++) {
2248 if ((phys_disk->Path[j].Flags &
2249 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2250 continue;
2251 if ((phys_disk->Path[j].Flags &
2252 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2253 continue;
2254 if ((id == phys_disk->Path[j].PhysDiskID) &&
2255 (channel == phys_disk->Path[j].PhysDiskBus)) {
2256 rc = 1;
2257 kfree(phys_disk);
2258 goto out;
2259 }
2260 }
2261 kfree(phys_disk);
2262 }
2263
2264
Eric Mooreb506ade2007-01-29 09:45:37 -07002265 /*
2266 * Check inactive list for matching phys disks
2267 */
2268 if (list_empty(&ioc->raid_data.inactive_list))
2269 goto out;
2270
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002271 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002272 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2273 list) {
2274 if ((component_info->d.PhysDiskID == id) &&
2275 (component_info->d.PhysDiskBus == channel))
2276 rc = 1;
2277 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002278 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002279
Eric Moore793955f2007-01-29 09:42:20 -07002280 out:
2281 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002282}
2283EXPORT_SYMBOL(mptscsih_is_phys_disk);
2284
Eric Moore793955f2007-01-29 09:42:20 -07002285u8
2286mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002287{
Eric Mooreb506ade2007-01-29 09:45:37 -07002288 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302289 int i, j;
2290 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002291 int rc = -ENXIO;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302292 int num_paths;
James Bottomleyc92f2222006-03-01 09:02:49 -06002293
Eric Moore793955f2007-01-29 09:42:20 -07002294 if (!ioc->raid_data.pIocPg3)
2295 goto out;
2296 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2297 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2298 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2299 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2300 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002301 }
2302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302304 if (ioc->bus_type != SAS)
2305 goto out;
2306
2307 /*
2308 * Check if dual path
2309 */
2310 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2311 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2312 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2313 if (num_paths < 2)
2314 continue;
2315 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2316 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2317 if (!phys_disk)
2318 continue;
2319 if ((mpt_raid_phys_disk_pg1(ioc,
2320 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2321 phys_disk))) {
2322 kfree(phys_disk);
2323 continue;
2324 }
2325 for (j = 0; j < num_paths; j++) {
2326 if ((phys_disk->Path[j].Flags &
2327 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2328 continue;
2329 if ((phys_disk->Path[j].Flags &
2330 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2331 continue;
2332 if ((id == phys_disk->Path[j].PhysDiskID) &&
2333 (channel == phys_disk->Path[j].PhysDiskBus)) {
2334 rc = phys_disk->PhysDiskNum;
2335 kfree(phys_disk);
2336 goto out;
2337 }
2338 }
2339 kfree(phys_disk);
2340 }
2341
Eric Mooreb506ade2007-01-29 09:45:37 -07002342 /*
2343 * Check inactive list for matching phys disks
2344 */
2345 if (list_empty(&ioc->raid_data.inactive_list))
2346 goto out;
2347
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002348 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002349 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2350 list) {
2351 if ((component_info->d.PhysDiskID == id) &&
2352 (component_info->d.PhysDiskBus == channel))
2353 rc = component_info->d.PhysDiskNum;
2354 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002355 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002356
Eric Moore793955f2007-01-29 09:42:20 -07002357 out:
2358 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002359}
Eric Moore793955f2007-01-29 09:42:20 -07002360EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002361
2362/*
2363 * OS entry point to allow for host driver to free allocated memory
2364 * Called if no device present or device being unloaded
2365 */
2366void
2367mptscsih_slave_destroy(struct scsi_device *sdev)
2368{
2369 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002370 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002371 VirtTarget *vtarget;
2372 VirtDevice *vdevice;
2373 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002375 starget = scsi_target(sdev);
2376 vtarget = starget->hostdata;
2377 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05302378 if (!vdevice)
2379 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002381 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002382 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002383 mptscsih_synchronize_cache(hd, vdevice);
2384 kfree(vdevice);
2385 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386}
2387
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2389/*
2390 * mptscsih_change_queue_depth - This function will set a devices queue depth
2391 * @sdev: per scsi_device pointer
2392 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07002393 * @reason: calling context
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002394 *
2395 * Adding support for new 'change_queue_depth' api.
2396*/
2397int
Mike Christiee881a172009-10-15 17:46:39 -07002398mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002400 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002401 VirtTarget *vtarget;
2402 struct scsi_target *starget;
2403 int max_depth;
2404 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002405 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002407 starget = scsi_target(sdev);
2408 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002409
Mike Christiee881a172009-10-15 17:46:39 -07002410 if (reason != SCSI_QDEPTH_DEFAULT)
2411 return -EOPNOTSUPP;
2412
Eric Mooree80b0022007-09-14 18:49:03 -06002413 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002414 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002416 else if (sdev->type == TYPE_DISK &&
2417 vtarget->minSyncFactor <= MPT_ULTRA160)
2418 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2419 else
2420 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 } else
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05302422 max_depth = ioc->sh->can_queue;
2423
2424 if (!sdev->tagged_supported)
2425 max_depth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
2427 if (qdepth > max_depth)
2428 qdepth = max_depth;
2429 if (qdepth == 1)
2430 tagged = 0;
2431 else
2432 tagged = MSG_SIMPLE_TAG;
2433
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002434 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2435 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436}
2437
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438/*
2439 * OS entry point to adjust the queue_depths on a per-device basis.
2440 * Called once per device the bus scan. Use it to force the queue_depth
2441 * member to 1 if a device does not support Q tags.
2442 * Return non-zero if fails.
2443 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002444int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002445mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002447 struct Scsi_Host *sh = sdev->host;
2448 VirtTarget *vtarget;
2449 VirtDevice *vdevice;
2450 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002451 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002452 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002454 starget = scsi_target(sdev);
2455 vtarget = starget->hostdata;
2456 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
Eric Mooree80b0022007-09-14 18:49:03 -06002458 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002459 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002460 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2461 if (ioc->bus_type == SPI)
2462 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002463 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002464 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002465 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
Eric Moore793955f2007-01-29 09:42:20 -07002467 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
Eric Mooree80b0022007-09-14 18:49:03 -06002469 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002471 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
Eric Mooree80b0022007-09-14 18:49:03 -06002473 if (ioc->bus_type == SPI)
2474 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002475 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002476 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002477 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
Mike Christiee881a172009-10-15 17:46:39 -07002479 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
2480 SCSI_QDEPTH_DEFAULT);
Eric Mooree80b0022007-09-14 18:49:03 -06002481 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002483 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002484 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
Ryan Kuester2a1b7e52010-04-26 18:11:54 -05002486 blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
2487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 return 0;
2489}
2490
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2492/*
2493 * Private routines...
2494 */
2495
2496/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2497/* Utility function to copy sense data from the scsi_cmnd buffer
2498 * to the FC and SCSI target structures.
2499 *
2500 */
2501static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002502mptscsih_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 -07002503{
Eric Moorea69de502007-09-14 18:48:19 -06002504 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 SCSIIORequest_t *pReq;
2506 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002507 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
2509 /* Get target structure
2510 */
2511 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002512 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
2514 if (sense_count) {
2515 u8 *sense_data;
2516 int req_index;
2517
2518 /* Copy the sense received into the scsi command block. */
2519 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002520 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2522
2523 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2524 */
Eric Mooree80b0022007-09-14 18:49:03 -06002525 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002526 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002529 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2531 ioc->events[idx].eventContext = ioc->eventContext;
2532
Dave Jones3d9780b2007-05-21 20:59:47 -04002533 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2534 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2535 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
Dave Jones3d9780b2007-05-21 20:59:47 -04002537 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
2539 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002540 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002541 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002542 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002543 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2544 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002545 MPT_TARGET_FLAGS_LED_ON;
2546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 }
2548 }
2549 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002550 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2551 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 }
2553}
2554
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05302555/**
2556 * mptscsih_get_scsi_lookup - retrieves scmd entry
2557 * @ioc: Pointer to MPT_ADAPTER structure
2558 * @i: index into the array
2559 *
2560 * Returns the scsi_cmd pointer
2561 */
2562struct scsi_cmnd *
2563mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2564{
2565 unsigned long flags;
2566 struct scsi_cmnd *scmd;
2567
2568 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2569 scmd = ioc->ScsiLookup[i];
2570 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2571
2572 return scmd;
2573}
2574EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
Eric Mooree8206382007-09-29 10:16:53 -06002575
2576/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00002577 * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
Kashyap, Desai2f187862009-05-29 16:52:37 +05302578 * @ioc: Pointer to MPT_ADAPTER structure
2579 * @i: index into the array
2580 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002581 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302582 *
Eric Mooree8206382007-09-29 10:16:53 -06002583 **/
2584static struct scsi_cmnd *
2585mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2586{
2587 unsigned long flags;
2588 struct scsi_cmnd *scmd;
2589
2590 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2591 scmd = ioc->ScsiLookup[i];
2592 ioc->ScsiLookup[i] = NULL;
2593 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2594
2595 return scmd;
2596}
2597
2598/**
Ben Hutchings9b8f77a2010-05-23 17:02:30 -07002599 * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002600 *
2601 * @ioc: Pointer to MPT_ADAPTER structure
2602 * @i: index into the array
2603 * @scmd: scsi_cmnd pointer
2604 *
2605 **/
2606static void
2607mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2608{
2609 unsigned long flags;
2610
2611 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2612 ioc->ScsiLookup[i] = scmd;
2613 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2614}
2615
2616/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002617 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002618 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002619 * @sc: scsi_cmnd pointer
2620 */
Eric Mooree8206382007-09-29 10:16:53 -06002621static int
2622SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2623{
2624 unsigned long flags;
2625 int i, index=-1;
2626
2627 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2628 for (i = 0; i < ioc->req_depth; i++) {
2629 if (ioc->ScsiLookup[i] == sc) {
2630 index = i;
2631 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 }
2633 }
2634
Eric Mooree8206382007-09-29 10:16:53 -06002635 out:
2636 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2637 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638}
2639
2640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002641int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2643{
2644 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
Eric Mooree7eae9f2007-09-29 10:15:59 -06002646 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302649 hd = shost_priv(ioc->sh);
2650 switch (reset_phase) {
2651 case MPT_IOC_SETUP_RESET:
2652 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2653 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302654 break;
2655 case MPT_IOC_PRE_RESET:
2656 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2657 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302658 mptscsih_flush_running_cmds(hd);
2659 break;
2660 case MPT_IOC_POST_RESET:
2661 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2662 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2663 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2664 ioc->internal_cmds.status |=
2665 MPT_MGMT_STATUS_DID_IOCRESET;
2666 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302668 break;
2669 default:
2670 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 return 1; /* currently means nothing really */
2673}
2674
2675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002676int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2678{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2680
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302681 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2682 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2683 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Kashyap, Desai2f187862009-05-29 16:52:37 +05302685 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2686 event == MPI_EVENT_EXT_BUS_RESET) &&
2687 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2688 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
2690 return 1; /* currently means nothing really */
2691}
2692
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2694/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 * Bus Scan and Domain Validation functionality ...
2696 */
2697
2698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2699/*
2700 * mptscsih_scandv_complete - Scan and DV callback routine registered
2701 * to Fustion MPT (base) driver.
2702 *
2703 * @ioc: Pointer to MPT_ADAPTER structure
2704 * @mf: Pointer to original MPT request frame
2705 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2706 *
2707 * This routine is called from mpt.c::mpt_interrupt() at the completion
2708 * of any SCSI IO request.
2709 * This routine is registered with the Fusion MPT (base) driver at driver
2710 * load/init time via the mpt_register() API call.
2711 *
2712 * Returns 1 indicating alloc'd request frame ptr should be freed.
2713 *
2714 * Remark: Sets a completion code and (possibly) saves sense data
2715 * in the IOC member localReply structure.
2716 * Used ONLY for DV and other internal commands.
2717 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002718int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302719mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2720 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302723 SCSIIOReply_t *pReply;
2724 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302726 u8 *sense_data;
2727 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302729 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2730 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2731 if (!reply)
2732 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002733
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302734 pReply = (SCSIIOReply_t *) reply;
2735 pReq = (SCSIIORequest_t *) req;
2736 ioc->internal_cmds.completion_code =
2737 mptscsih_get_completion_code(ioc, req, reply);
2738 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2739 memcpy(ioc->internal_cmds.reply, reply,
2740 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2741 cmd = reply->u.hdr.Function;
2742 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2743 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2744 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2745 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2746 sense_data = ((u8 *)ioc->sense_buf_pool +
2747 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2748 sz = min_t(int, pReq->SenseBufferLength,
2749 MPT_SENSE_BUFFER_ALLOC);
2750 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302752 out:
2753 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2754 return 0;
2755 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2756 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return 1;
2758}
2759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302761/**
Ben Hutchings9b8f77a2010-05-23 17:02:30 -07002762 * mptscsih_get_completion_code - get completion code from MPT request
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302763 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap9cf46a32009-06-13 19:37:18 -07002764 * @req: Pointer to original MPT request frame
2765 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302766 *
2767 **/
2768static int
2769mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2770 MPT_FRAME_HDR *reply)
2771{
2772 SCSIIOReply_t *pReply;
2773 MpiRaidActionReply_t *pr;
2774 u8 scsi_status;
2775 u16 status;
2776 int completion_code;
2777
2778 pReply = (SCSIIOReply_t *)reply;
2779 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2780 scsi_status = pReply->SCSIStatus;
2781
2782 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2783 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2784 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2785 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2786
2787 switch (status) {
2788
2789 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2790 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2791 break;
2792
2793 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2794 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2795 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2796 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2797 completion_code = MPT_SCANDV_DID_RESET;
2798 break;
2799
2800 case MPI_IOCSTATUS_BUSY:
2801 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2802 completion_code = MPT_SCANDV_BUSY;
2803 break;
2804
2805 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2806 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2807 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2808 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2809 completion_code = MPT_SCANDV_GOOD;
2810 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2811 pr = (MpiRaidActionReply_t *)reply;
2812 if (le16_to_cpu(pr->ActionStatus) ==
2813 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2814 completion_code = MPT_SCANDV_GOOD;
2815 else
2816 completion_code = MPT_SCANDV_SOME_ERROR;
2817 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2818 completion_code = MPT_SCANDV_SENSE;
2819 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2820 if (req->u.scsireq.CDB[0] == INQUIRY)
2821 completion_code = MPT_SCANDV_ISSUE_SENSE;
2822 else
2823 completion_code = MPT_SCANDV_DID_RESET;
2824 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2825 completion_code = MPT_SCANDV_DID_RESET;
2826 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2827 completion_code = MPT_SCANDV_DID_RESET;
2828 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2829 completion_code = MPT_SCANDV_BUSY;
2830 else
2831 completion_code = MPT_SCANDV_GOOD;
2832 break;
2833
2834 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2835 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2836 completion_code = MPT_SCANDV_DID_RESET;
2837 else
2838 completion_code = MPT_SCANDV_SOME_ERROR;
2839 break;
2840 default:
2841 completion_code = MPT_SCANDV_SOME_ERROR;
2842 break;
2843
2844 } /* switch(status) */
2845
2846 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2847 " completionCode set to %08xh\n", ioc->name, completion_code));
2848 return completion_code;
2849}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
2851/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2852/**
2853 * mptscsih_do_cmd - Do internal command.
2854 * @hd: MPT_SCSI_HOST pointer
2855 * @io: INTERNAL_CMD pointer.
2856 *
2857 * Issue the specified internally generated command and do command
2858 * specific cleanup. For bus scan / DV only.
2859 * NOTES: If command is Inquiry and status is good,
2860 * initialize a target structure, save the data
2861 *
2862 * Remark: Single threaded access only.
2863 *
2864 * Return:
2865 * < 0 if an illegal command or no resources
2866 *
2867 * 0 if good
2868 *
2869 * > 0 if command complete but some type of completion error.
2870 */
2871static int
2872mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2873{
2874 MPT_FRAME_HDR *mf;
2875 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302877 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 char cmdLen;
2879 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 +05302880 u8 cmd = io->cmd;
2881 MPT_ADAPTER *ioc = hd->ioc;
2882 int ret = 0;
2883 unsigned long timeleft;
2884 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302886 /* don't send internal command during diag reset */
2887 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2888 if (ioc->ioc_reset_in_progress) {
2889 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2890 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2891 "%s: busy with host reset\n", ioc->name, __func__));
2892 return MPT_SCANDV_BUSY;
2893 }
2894 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2895
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302896 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897
2898 /* Set command specific information
2899 */
2900 switch (cmd) {
2901 case INQUIRY:
2902 cmdLen = 6;
2903 dir = MPI_SCSIIO_CONTROL_READ;
2904 CDB[0] = cmd;
2905 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302906 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 break;
2908
2909 case TEST_UNIT_READY:
2910 cmdLen = 6;
2911 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302912 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 break;
2914
2915 case START_STOP:
2916 cmdLen = 6;
2917 dir = MPI_SCSIIO_CONTROL_READ;
2918 CDB[0] = cmd;
2919 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302920 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 break;
2922
2923 case REQUEST_SENSE:
2924 cmdLen = 6;
2925 CDB[0] = cmd;
2926 CDB[4] = io->size;
2927 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302928 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 break;
2930
2931 case READ_BUFFER:
2932 cmdLen = 10;
2933 dir = MPI_SCSIIO_CONTROL_READ;
2934 CDB[0] = cmd;
2935 if (io->flags & MPT_ICFLAG_ECHO) {
2936 CDB[1] = 0x0A;
2937 } else {
2938 CDB[1] = 0x02;
2939 }
2940
2941 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2942 CDB[1] |= 0x01;
2943 }
2944 CDB[6] = (io->size >> 16) & 0xFF;
2945 CDB[7] = (io->size >> 8) & 0xFF;
2946 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302947 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 break;
2949
2950 case WRITE_BUFFER:
2951 cmdLen = 10;
2952 dir = MPI_SCSIIO_CONTROL_WRITE;
2953 CDB[0] = cmd;
2954 if (io->flags & MPT_ICFLAG_ECHO) {
2955 CDB[1] = 0x0A;
2956 } else {
2957 CDB[1] = 0x02;
2958 }
2959 CDB[6] = (io->size >> 16) & 0xFF;
2960 CDB[7] = (io->size >> 8) & 0xFF;
2961 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302962 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 break;
2964
2965 case RESERVE:
2966 cmdLen = 6;
2967 dir = MPI_SCSIIO_CONTROL_READ;
2968 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302969 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 break;
2971
2972 case RELEASE:
2973 cmdLen = 6;
2974 dir = MPI_SCSIIO_CONTROL_READ;
2975 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302976 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 break;
2978
2979 case SYNCHRONIZE_CACHE:
2980 cmdLen = 10;
2981 dir = MPI_SCSIIO_CONTROL_READ;
2982 CDB[0] = cmd;
2983// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302984 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 break;
2986
2987 default:
2988 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302989 ret = -EFAULT;
2990 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 }
2992
2993 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302994 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 */
Eric Mooree80b0022007-09-14 18:49:03 -06002996 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302997 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2998 ioc->name, __func__));
2999 ret = MPT_SCANDV_BUSY;
3000 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 }
3002
3003 pScsiReq = (SCSIIORequest_t *) mf;
3004
3005 /* Get the request index */
3006 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3007 ADD_INDEX_LOG(my_idx); /* for debug */
3008
3009 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3010 pScsiReq->TargetID = io->physDiskNum;
3011 pScsiReq->Bus = 0;
3012 pScsiReq->ChainOffset = 0;
3013 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3014 } else {
3015 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003016 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 pScsiReq->ChainOffset = 0;
3018 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3019 }
3020
3021 pScsiReq->CDBLength = cmdLen;
3022 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3023
3024 pScsiReq->Reserved = 0;
3025
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303026 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 /* MsgContext set in mpt_get_msg_fram call */
3028
Eric Moore793955f2007-01-29 09:42:20 -07003029 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3032 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3033 else
3034 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3035
3036 if (cmd == REQUEST_SENSE) {
3037 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303038 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3039 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 }
3041
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303042 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 pScsiReq->CDB[ii] = CDB[ii];
3044
3045 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003046 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3048
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303049 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3050 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3051 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303053 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303054 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303055 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3056 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303057 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303058 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303060 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003061 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303062 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3063 timeout*HZ);
3064 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3065 ret = MPT_SCANDV_DID_RESET;
3066 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3067 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3068 cmd));
3069 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3070 mpt_free_msg_frame(ioc, mf);
3071 goto out;
3072 }
3073 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09003074 printk(MYIOC_s_WARN_FMT
3075 "Issuing Reset from %s!! doorbell=0x%08xh"
3076 " cmd=0x%02x\n",
3077 ioc->name, __func__, mpt_GetIocState(ioc, 0),
3078 cmd);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05303079 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303080 mpt_free_msg_frame(ioc, mf);
3081 }
3082 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 }
3084
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303085 ret = ioc->internal_cmds.completion_code;
3086 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3087 ioc->name, __func__, ret));
3088
3089 out:
3090 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3091 mutex_unlock(&ioc->internal_cmds.mutex);
3092 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093}
3094
3095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3096/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003097 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3098 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003099 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003100 *
3101 * Uses the ISR, but with special processing.
3102 * MUST be single-threaded.
3103 *
3104 */
3105static void
3106mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3107{
3108 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
Eric Moorecc78d302007-06-15 17:27:21 -06003110 /* Ignore hidden raid components, this is handled when the command
3111 * is sent to the volume
3112 */
3113 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3114 return;
3115
3116 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3117 !vdevice->configured_lun)
3118 return;
3119
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 /* Following parameters will not change
3121 * in this routine.
3122 */
3123 iocmd.cmd = SYNCHRONIZE_CACHE;
3124 iocmd.flags = 0;
3125 iocmd.physDiskNum = -1;
3126 iocmd.data = NULL;
3127 iocmd.data_dma = -1;
3128 iocmd.size = 0;
3129 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003130 iocmd.channel = vdevice->vtarget->channel;
3131 iocmd.id = vdevice->vtarget->id;
3132 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
Eric Moorecc78d302007-06-15 17:27:21 -06003134 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135}
3136
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303137static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003138mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3139 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303140{
Tony Jonesee959b02008-02-22 00:13:36 +01003141 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003142 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303143 MPT_ADAPTER *ioc = hd->ioc;
3144
3145 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3146 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3147 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3148 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3149 ioc->facts.FWVersion.Word & 0x000000FF);
3150}
Tony Jonesee959b02008-02-22 00:13:36 +01003151static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303152
3153static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003154mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3155 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303156{
Tony Jonesee959b02008-02-22 00:13:36 +01003157 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003158 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303159 MPT_ADAPTER *ioc = hd->ioc;
3160
3161 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3162 (ioc->biosVersion & 0xFF000000) >> 24,
3163 (ioc->biosVersion & 0x00FF0000) >> 16,
3164 (ioc->biosVersion & 0x0000FF00) >> 8,
3165 ioc->biosVersion & 0x000000FF);
3166}
Tony Jonesee959b02008-02-22 00:13:36 +01003167static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303168
3169static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003170mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3171 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303172{
Tony Jonesee959b02008-02-22 00:13:36 +01003173 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003174 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303175 MPT_ADAPTER *ioc = hd->ioc;
3176
3177 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3178}
Tony Jonesee959b02008-02-22 00:13:36 +01003179static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303180
3181static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003182mptscsih_version_product_show(struct device *dev,
3183 struct device_attribute *attr,
3184char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303185{
Tony Jonesee959b02008-02-22 00:13:36 +01003186 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003187 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303188 MPT_ADAPTER *ioc = hd->ioc;
3189
3190 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3191}
Tony Jonesee959b02008-02-22 00:13:36 +01003192static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303193 mptscsih_version_product_show, NULL);
3194
3195static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003196mptscsih_version_nvdata_persistent_show(struct device *dev,
3197 struct device_attribute *attr,
3198 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303199{
Tony Jonesee959b02008-02-22 00:13:36 +01003200 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003201 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303202 MPT_ADAPTER *ioc = hd->ioc;
3203
3204 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3205 ioc->nvdata_version_persistent);
3206}
Tony Jonesee959b02008-02-22 00:13:36 +01003207static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303208 mptscsih_version_nvdata_persistent_show, NULL);
3209
3210static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003211mptscsih_version_nvdata_default_show(struct device *dev,
3212 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303213{
Tony Jonesee959b02008-02-22 00:13:36 +01003214 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003215 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303216 MPT_ADAPTER *ioc = hd->ioc;
3217
3218 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3219}
Tony Jonesee959b02008-02-22 00:13:36 +01003220static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303221 mptscsih_version_nvdata_default_show, NULL);
3222
3223static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003224mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3225 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303226{
Tony Jonesee959b02008-02-22 00:13:36 +01003227 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003228 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303229 MPT_ADAPTER *ioc = hd->ioc;
3230
3231 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3232}
Tony Jonesee959b02008-02-22 00:13:36 +01003233static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303234
3235static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003236mptscsih_board_assembly_show(struct device *dev,
3237 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303238{
Tony Jonesee959b02008-02-22 00:13:36 +01003239 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003240 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303241 MPT_ADAPTER *ioc = hd->ioc;
3242
3243 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3244}
Tony Jonesee959b02008-02-22 00:13:36 +01003245static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303246 mptscsih_board_assembly_show, NULL);
3247
3248static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003249mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3250 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303251{
Tony Jonesee959b02008-02-22 00:13:36 +01003252 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003253 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303254 MPT_ADAPTER *ioc = hd->ioc;
3255
3256 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3257}
Tony Jonesee959b02008-02-22 00:13:36 +01003258static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303259 mptscsih_board_tracer_show, NULL);
3260
3261static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003262mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3263 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +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, Sathyaedb90682007-07-17 14:39:14 +05303267 MPT_ADAPTER *ioc = hd->ioc;
3268
3269 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3270}
Tony Jonesee959b02008-02-22 00:13:36 +01003271static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303272 mptscsih_io_delay_show, NULL);
3273
3274static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003275mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3276 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303277{
Tony Jonesee959b02008-02-22 00:13:36 +01003278 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003279 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303280 MPT_ADAPTER *ioc = hd->ioc;
3281
3282 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3283}
Tony Jonesee959b02008-02-22 00:13:36 +01003284static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303285 mptscsih_device_delay_show, NULL);
3286
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303287static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003288mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3289 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303290{
Tony Jonesee959b02008-02-22 00:13:36 +01003291 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003292 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303293 MPT_ADAPTER *ioc = hd->ioc;
3294
3295 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3296}
3297static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003298mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3299 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303300{
Tony Jonesee959b02008-02-22 00:13:36 +01003301 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003302 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303303 MPT_ADAPTER *ioc = hd->ioc;
3304 int val = 0;
3305
3306 if (sscanf(buf, "%x", &val) != 1)
3307 return -EINVAL;
3308
3309 ioc->debug_level = val;
3310 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3311 ioc->name, ioc->debug_level);
3312 return strlen(buf);
3313}
Tony Jonesee959b02008-02-22 00:13:36 +01003314static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3315 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303316
Tony Jonesee959b02008-02-22 00:13:36 +01003317struct device_attribute *mptscsih_host_attrs[] = {
3318 &dev_attr_version_fw,
3319 &dev_attr_version_bios,
3320 &dev_attr_version_mpi,
3321 &dev_attr_version_product,
3322 &dev_attr_version_nvdata_persistent,
3323 &dev_attr_version_nvdata_default,
3324 &dev_attr_board_name,
3325 &dev_attr_board_assembly,
3326 &dev_attr_board_tracer,
3327 &dev_attr_io_delay,
3328 &dev_attr_device_delay,
3329 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303330 NULL,
3331};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303332
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303333EXPORT_SYMBOL(mptscsih_host_attrs);
3334
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003335EXPORT_SYMBOL(mptscsih_remove);
3336EXPORT_SYMBOL(mptscsih_shutdown);
3337#ifdef CONFIG_PM
3338EXPORT_SYMBOL(mptscsih_suspend);
3339EXPORT_SYMBOL(mptscsih_resume);
3340#endif
3341EXPORT_SYMBOL(mptscsih_proc_info);
3342EXPORT_SYMBOL(mptscsih_info);
3343EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003344EXPORT_SYMBOL(mptscsih_slave_destroy);
3345EXPORT_SYMBOL(mptscsih_slave_configure);
3346EXPORT_SYMBOL(mptscsih_abort);
3347EXPORT_SYMBOL(mptscsih_dev_reset);
3348EXPORT_SYMBOL(mptscsih_bus_reset);
3349EXPORT_SYMBOL(mptscsih_host_reset);
3350EXPORT_SYMBOL(mptscsih_bios_param);
3351EXPORT_SYMBOL(mptscsih_io_done);
3352EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3353EXPORT_SYMBOL(mptscsih_scandv_complete);
3354EXPORT_SYMBOL(mptscsih_event_process);
3355EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003356EXPORT_SYMBOL(mptscsih_change_queue_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003358/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/