blob: ced6e4dc0847a1dc76fa2d677f4e5962506322f0 [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
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05301633 /* DOORBELL ACTIVE check is not required if
1634 * MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.
1635 */
1636
1637 if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)
1638 && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&
1639 (ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301640 printk(MYIOC_s_WARN_FMT
1641 "TaskMgmt type=%x: ioc_state: "
1642 "DOORBELL_ACTIVE (0x%x)!\n",
1643 ioc->name, type, ioc_raw_state);
1644 return FAILED;
1645 }
1646
1647 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1648 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1649 mf = NULL;
1650 retval = FAILED;
1651 goto out;
1652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 /* Return Fail to calling function if no message frames available.
1655 */
Eric Mooree80b0022007-09-14 18:49:03 -06001656 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301657 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1658 "TaskMgmt no msg frames!!\n", ioc->name));
1659 retval = FAILED;
1660 mpt_clear_taskmgmt_in_progress_flag(ioc);
1661 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301663 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001664 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666 /* Format the Request
1667 */
1668 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001669 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 pScsiTm->Bus = channel;
1671 pScsiTm->ChainOffset = 0;
1672 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1673
1674 pScsiTm->Reserved = 0;
1675 pScsiTm->TaskType = type;
1676 pScsiTm->Reserved1 = 0;
1677 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1678 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1679
Eric Moore793955f2007-01-29 09:42:20 -07001680 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
1682 for (ii=0; ii < 7; ii++)
1683 pScsiTm->Reserved2[ii] = 0;
1684
1685 pScsiTm->TaskMsgContext = ctx2abort;
1686
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301687 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1688 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1689 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301691 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301693 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1694 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001695 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1696 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1697 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301698 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001699 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301700 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1701 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301702 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1703 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1704 ioc->name, mf, retval));
1705 mpt_free_msg_frame(ioc, mf);
1706 mpt_clear_taskmgmt_in_progress_flag(ioc);
1707 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 }
1710
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301711 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1712 timeout*HZ);
1713 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1714 retval = FAILED;
1715 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1716 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1717 mpt_clear_taskmgmt_in_progress_flag(ioc);
1718 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1719 goto out;
1720 issue_hard_reset = 1;
1721 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 }
1723
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301724 retval = mptscsih_taskmgmt_reply(ioc, type,
1725 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001726
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301727 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1728 "TaskMgmt completed (%d seconds)\n",
1729 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1730
1731 out:
1732
1733 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1734 if (issue_hard_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09001735 printk(MYIOC_s_WARN_FMT
1736 "Issuing Reset from %s!! doorbell=0x%08x\n",
1737 ioc->name, __func__, mpt_GetIocState(ioc, 0));
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05301738 retval = (ioc->bus_type == SAS) ?
1739 mpt_HardResetHandler(ioc, CAN_SLEEP) :
1740 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301741 mpt_free_msg_frame(ioc, mf);
1742 }
1743
1744 retval = (retval == 0) ? 0 : FAILED;
1745 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 return retval;
1747}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301748EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001750static int
1751mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1752{
1753 switch (ioc->bus_type) {
1754 case FC:
1755 return 40;
1756 case SAS:
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301757 return 30;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001758 case SPI:
1759 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001760 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001761 }
1762}
1763
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1765/**
1766 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1767 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1768 *
1769 * (linux scsi_host_template.eh_abort_handler routine)
1770 *
1771 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001772 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001773int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774mptscsih_abort(struct scsi_cmnd * SCpnt)
1775{
1776 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 MPT_FRAME_HDR *mf;
1778 u32 ctx2abort;
1779 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001780 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001781 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001782 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
1784 /* If we can't locate our host adapter structure, return FAILED status.
1785 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001786 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 SCpnt->result = DID_RESET << 16;
1788 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001789 printk(KERN_ERR MYNAM ": task abort: "
1790 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 return FAILED;
1792 }
1793
Eric Moore958d4a32007-06-15 17:24:14 -06001794 ioc = hd->ioc;
1795 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1796 ioc->name, SCpnt);
1797 scsi_print_command(SCpnt);
1798
1799 vdevice = SCpnt->device->hostdata;
1800 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001801 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1802 "task abort: device has been deleted (sc=%p)\n",
1803 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001804 SCpnt->result = DID_NO_CONNECT << 16;
1805 SCpnt->scsi_done(SCpnt);
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301806 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001807 goto out;
1808 }
1809
Eric Moorecc78d302007-06-15 17:27:21 -06001810 /* Task aborts are not supported for hidden raid components.
1811 */
1812 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001813 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1814 "task abort: hidden raid component (sc=%p)\n",
1815 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001816 SCpnt->result = DID_RESET << 16;
1817 retval = FAILED;
1818 goto out;
1819 }
1820
Kashyap, Desai69b2e9b2010-03-18 19:23:19 +05301821 /* Task aborts are not supported for volumes.
1822 */
1823 if (vdevice->vtarget->raidVolume) {
1824 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1825 "task abort: raid volume (sc=%p)\n",
1826 ioc->name, SCpnt));
1827 SCpnt->result = DID_RESET << 16;
1828 retval = FAILED;
1829 goto out;
1830 }
1831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 /* Find this command
1833 */
Eric Mooree8206382007-09-29 10:16:53 -06001834 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001835 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 * Do OS callback.
1837 */
1838 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001839 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001840 "Command not in the active list! (sc=%p)\n", ioc->name,
1841 SCpnt));
Kashyap, Desai9858ae32010-01-25 16:20:52 +05301842 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001843 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 }
1845
Kashyap, Desai2f187862009-05-29 16:52:37 +05301846 if (ioc->timeouts < -1)
1847 ioc->timeouts++;
Moore, Eric65207fe2006-04-21 16:14:35 -06001848
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301849 if (mpt_fwfault_debug)
1850 mpt_halt_firmware(ioc);
1851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1853 * (the IO to be ABORT'd)
1854 *
1855 * NOTE: Since we do not byteswap MsgContext, we do not
1856 * swap it here either. It is an opaque cookie to
1857 * the controller, so it does not matter. -DaveM
1858 */
Eric Mooree80b0022007-09-14 18:49:03 -06001859 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301861 retval = mptscsih_IssueTaskMgmt(hd,
1862 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1863 vdevice->vtarget->channel,
1864 vdevice->vtarget->id, vdevice->lun,
1865 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001867 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05301868 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1869 "task abort: command still in active list! (sc=%p)\n",
1870 ioc->name, SCpnt));
Eric Moore3dc0b032006-07-11 17:32:33 -06001871 retval = FAILED;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301872 } else {
1873 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1874 "task abort: command cleared from active list! (sc=%p)\n",
1875 ioc->name, SCpnt));
1876 retval = SUCCESS;
1877 }
Eric Moore3dc0b032006-07-11 17:32:33 -06001878
Eric Moore958d4a32007-06-15 17:24:14 -06001879 out:
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001880 printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
Kashyap, Desaibcfe42e2011-02-10 11:53:44 +05301881 ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
Christoph Hellwigaeaeb5c2011-04-04 09:42:41 -04001882 SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
Kashyap, Desai2f187862009-05-29 16:52:37 +05301884 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885}
1886
1887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1888/**
1889 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1890 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1891 *
1892 * (linux scsi_host_template.eh_dev_reset_handler routine)
1893 *
1894 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001895 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001896int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1898{
1899 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001900 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001901 VirtDevice *vdevice;
1902 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 /* If we can't locate our host adapter structure, return FAILED status.
1905 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001906 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001907 printk(KERN_ERR MYNAM ": target reset: "
1908 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 return FAILED;
1910 }
1911
Eric Moore958d4a32007-06-15 17:24:14 -06001912 ioc = hd->ioc;
1913 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1914 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001915 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
Eric Moore958d4a32007-06-15 17:24:14 -06001917 vdevice = SCpnt->device->hostdata;
1918 if (!vdevice || !vdevice->vtarget) {
Kashyap, Desaibcfe42e2011-02-10 11:53:44 +05301919 retval = 0;
Eric Moore958d4a32007-06-15 17:24:14 -06001920 goto out;
1921 }
1922
Eric Moorecc78d302007-06-15 17:27:21 -06001923 /* Target reset to hidden raid component is not supported
1924 */
1925 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1926 retval = FAILED;
1927 goto out;
1928 }
1929
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301930 retval = mptscsih_IssueTaskMgmt(hd,
1931 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1932 vdevice->vtarget->channel,
1933 vdevice->vtarget->id, 0, 0,
1934 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001935
1936 out:
1937 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1938 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001939
1940 if (retval == 0)
1941 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001942 else
1943 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944}
1945
Eric Moorecd2c6192007-01-29 09:47:47 -07001946
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1948/**
1949 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1950 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1951 *
1952 * (linux scsi_host_template.eh_bus_reset_handler routine)
1953 *
1954 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001955 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001956int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1958{
1959 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001960 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001961 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001962 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
1964 /* If we can't locate our host adapter structure, return FAILED status.
1965 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001966 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001967 printk(KERN_ERR MYNAM ": bus reset: "
1968 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 return FAILED;
1970 }
1971
Eric Moore958d4a32007-06-15 17:24:14 -06001972 ioc = hd->ioc;
1973 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1974 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001975 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Kashyap, Desai2f187862009-05-29 16:52:37 +05301977 if (ioc->timeouts < -1)
1978 ioc->timeouts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979
Eric Moorea69de502007-09-14 18:48:19 -06001980 vdevice = SCpnt->device->hostdata;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301981 if (!vdevice || !vdevice->vtarget)
1982 return SUCCESS;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301983 retval = mptscsih_IssueTaskMgmt(hd,
1984 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1985 vdevice->vtarget->channel, 0, 0, 0,
1986 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Eric Moore958d4a32007-06-15 17:24:14 -06001988 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1989 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001990
1991 if (retval == 0)
1992 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001993 else
1994 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995}
1996
1997/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1998/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001999 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
2001 *
2002 * (linux scsi_host_template.eh_host_reset_handler routine)
2003 *
2004 * Returns SUCCESS or FAILED.
2005 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002006int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007mptscsih_host_reset(struct scsi_cmnd *SCpnt)
2008{
2009 MPT_SCSI_HOST * hd;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302010 int status = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06002011 MPT_ADAPTER *ioc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302012 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
2014 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06002015 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06002016 printk(KERN_ERR MYNAM ": host reset: "
2017 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 return FAILED;
2019 }
2020
James Bottomleya6da74c2008-12-15 14:13:27 -06002021 /* make sure we have no outstanding commands at this stage */
2022 mptscsih_flush_running_cmds(hd);
2023
Eric Moore958d4a32007-06-15 17:24:14 -06002024 ioc = hd->ioc;
2025 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
2026 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028 /* If our attempts to reset the host failed, then return a failed
2029 * status. The host will be taken off line by the SCSI mid-layer.
2030 */
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302031 retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302032 if (retval < 0)
2033 status = FAILED;
2034 else
2035 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Eric Moore958d4a32007-06-15 17:24:14 -06002037 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
2038 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
Kashyap, Desai2f187862009-05-29 16:52:37 +05302040 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041}
2042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302044mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
2045 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302047 u16 iocstatus;
2048 u32 termination_count;
2049 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302051 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
2052 retval = FAILED;
2053 goto out;
2054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302056 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302058 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2059 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302061 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2062 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
2063 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
2064 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
2065 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
2066 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
2067 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302069 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2070 pScsiTmReply->ResponseCode)
2071 mptscsih_taskmgmt_response_code(ioc,
2072 pScsiTmReply->ResponseCode);
2073
2074 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
2075 retval = 0;
2076 goto out;
2077 }
2078
2079 retval = FAILED;
2080 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
2081 if (termination_count == 1)
2082 retval = 0;
2083 goto out;
2084 }
2085
2086 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
2087 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
2088 retval = 0;
2089
2090 out:
2091 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092}
2093
2094/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302095void
Moore, Eric9f63bb72006-01-16 18:53:26 -07002096mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2097{
2098 char *desc;
2099
2100 switch (response_code) {
2101 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2102 desc = "The task completed.";
2103 break;
2104 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2105 desc = "The IOC received an invalid frame status.";
2106 break;
2107 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2108 desc = "The task type is not supported.";
2109 break;
2110 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2111 desc = "The requested task failed.";
2112 break;
2113 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2114 desc = "The task completed successfully.";
2115 break;
2116 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2117 desc = "The LUN request is invalid.";
2118 break;
2119 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2120 desc = "The task is in the IOC queue and has not been sent to target.";
2121 break;
2122 default:
2123 desc = "unknown";
2124 break;
2125 }
2126 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2127 ioc->name, response_code, desc);
2128}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302129EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07002130
2131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132/**
2133 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2134 * @ioc: Pointer to MPT_ADAPTER structure
2135 * @mf: Pointer to SCSI task mgmt request frame
2136 * @mr: Pointer to SCSI task mgmt reply frame
2137 *
2138 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2139 * of any SCSI task management request.
2140 * This routine is registered with the MPT (base) driver at driver
2141 * load/init time via the mpt_register() API call.
2142 *
2143 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002144 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002145int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302146mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2147 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302149 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2150 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302152 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302154 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002155 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002156
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302157 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2158 memcpy(ioc->taskmgmt_cmds.reply, mr,
2159 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002160 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302161 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2162 mpt_clear_taskmgmt_in_progress_flag(ioc);
2163 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2164 complete(&ioc->taskmgmt_cmds.done);
Kashyap, Desaib68bf092010-06-17 14:40:56 +05302165 if (ioc->bus_type == SAS)
2166 ioc->schedule_target_reset(ioc);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302167 return 1;
2168 }
2169 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170}
2171
2172/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2173/*
2174 * This is anyones guess quite frankly.
2175 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002176int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2178 sector_t capacity, int geom[])
2179{
2180 int heads;
2181 int sectors;
2182 sector_t cylinders;
2183 ulong dummy;
2184
2185 heads = 64;
2186 sectors = 32;
2187
2188 dummy = heads * sectors;
2189 cylinders = capacity;
2190 sector_div(cylinders,dummy);
2191
2192 /*
2193 * Handle extended translation size for logical drives
2194 * > 1Gb
2195 */
2196 if ((ulong)capacity >= 0x200000) {
2197 heads = 255;
2198 sectors = 63;
2199 dummy = heads * sectors;
2200 cylinders = capacity;
2201 sector_div(cylinders,dummy);
2202 }
2203
2204 /* return result */
2205 geom[0] = heads;
2206 geom[1] = sectors;
2207 geom[2] = cylinders;
2208
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 return 0;
2210}
2211
Moore, Ericf44e5462006-03-14 09:14:21 -07002212/* Search IOC page 3 to determine if this is hidden physical disk
2213 *
2214 */
2215int
Eric Moore793955f2007-01-29 09:42:20 -07002216mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002217{
Eric Mooreb506ade2007-01-29 09:45:37 -07002218 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302219 int i, j;
2220 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002221 int rc = 0;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302222 int num_paths;
Moore, Ericf44e5462006-03-14 09:14:21 -07002223
Eric Moore793955f2007-01-29 09:42:20 -07002224 if (!ioc->raid_data.pIocPg3)
2225 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002226 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002227 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2228 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2229 rc = 1;
2230 goto out;
2231 }
2232 }
2233
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302234 if (ioc->bus_type != SAS)
2235 goto out;
2236
2237 /*
2238 * Check if dual path
2239 */
2240 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2241 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2242 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2243 if (num_paths < 2)
2244 continue;
2245 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2246 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2247 if (!phys_disk)
2248 continue;
2249 if ((mpt_raid_phys_disk_pg1(ioc,
2250 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2251 phys_disk))) {
2252 kfree(phys_disk);
2253 continue;
2254 }
2255 for (j = 0; j < num_paths; j++) {
2256 if ((phys_disk->Path[j].Flags &
2257 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2258 continue;
2259 if ((phys_disk->Path[j].Flags &
2260 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2261 continue;
2262 if ((id == phys_disk->Path[j].PhysDiskID) &&
2263 (channel == phys_disk->Path[j].PhysDiskBus)) {
2264 rc = 1;
2265 kfree(phys_disk);
2266 goto out;
2267 }
2268 }
2269 kfree(phys_disk);
2270 }
2271
2272
Eric Mooreb506ade2007-01-29 09:45:37 -07002273 /*
2274 * Check inactive list for matching phys disks
2275 */
2276 if (list_empty(&ioc->raid_data.inactive_list))
2277 goto out;
2278
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002279 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002280 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2281 list) {
2282 if ((component_info->d.PhysDiskID == id) &&
2283 (component_info->d.PhysDiskBus == channel))
2284 rc = 1;
2285 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002286 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002287
Eric Moore793955f2007-01-29 09:42:20 -07002288 out:
2289 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002290}
2291EXPORT_SYMBOL(mptscsih_is_phys_disk);
2292
Eric Moore793955f2007-01-29 09:42:20 -07002293u8
2294mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002295{
Eric Mooreb506ade2007-01-29 09:45:37 -07002296 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302297 int i, j;
2298 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002299 int rc = -ENXIO;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302300 int num_paths;
James Bottomleyc92f2222006-03-01 09:02:49 -06002301
Eric Moore793955f2007-01-29 09:42:20 -07002302 if (!ioc->raid_data.pIocPg3)
2303 goto out;
2304 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2305 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2306 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2307 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2308 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002309 }
2310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302312 if (ioc->bus_type != SAS)
2313 goto out;
2314
2315 /*
2316 * Check if dual path
2317 */
2318 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2319 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2320 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2321 if (num_paths < 2)
2322 continue;
2323 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2324 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2325 if (!phys_disk)
2326 continue;
2327 if ((mpt_raid_phys_disk_pg1(ioc,
2328 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2329 phys_disk))) {
2330 kfree(phys_disk);
2331 continue;
2332 }
2333 for (j = 0; j < num_paths; j++) {
2334 if ((phys_disk->Path[j].Flags &
2335 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2336 continue;
2337 if ((phys_disk->Path[j].Flags &
2338 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2339 continue;
2340 if ((id == phys_disk->Path[j].PhysDiskID) &&
2341 (channel == phys_disk->Path[j].PhysDiskBus)) {
2342 rc = phys_disk->PhysDiskNum;
2343 kfree(phys_disk);
2344 goto out;
2345 }
2346 }
2347 kfree(phys_disk);
2348 }
2349
Eric Mooreb506ade2007-01-29 09:45:37 -07002350 /*
2351 * Check inactive list for matching phys disks
2352 */
2353 if (list_empty(&ioc->raid_data.inactive_list))
2354 goto out;
2355
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002356 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002357 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2358 list) {
2359 if ((component_info->d.PhysDiskID == id) &&
2360 (component_info->d.PhysDiskBus == channel))
2361 rc = component_info->d.PhysDiskNum;
2362 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002363 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002364
Eric Moore793955f2007-01-29 09:42:20 -07002365 out:
2366 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002367}
Eric Moore793955f2007-01-29 09:42:20 -07002368EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002369
2370/*
2371 * OS entry point to allow for host driver to free allocated memory
2372 * Called if no device present or device being unloaded
2373 */
2374void
2375mptscsih_slave_destroy(struct scsi_device *sdev)
2376{
2377 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002378 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002379 VirtTarget *vtarget;
2380 VirtDevice *vdevice;
2381 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002383 starget = scsi_target(sdev);
2384 vtarget = starget->hostdata;
2385 vdevice = sdev->hostdata;
Kashyap, Desai08f5c5c2010-03-18 19:22:45 +05302386 if (!vdevice)
2387 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002389 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002390 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002391 mptscsih_synchronize_cache(hd, vdevice);
2392 kfree(vdevice);
2393 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394}
2395
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002396/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2397/*
2398 * mptscsih_change_queue_depth - This function will set a devices queue depth
2399 * @sdev: per scsi_device pointer
2400 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07002401 * @reason: calling context
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002402 *
2403 * Adding support for new 'change_queue_depth' api.
2404*/
2405int
Mike Christiee881a172009-10-15 17:46:39 -07002406mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002408 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002409 VirtTarget *vtarget;
2410 struct scsi_target *starget;
2411 int max_depth;
2412 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002413 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002415 starget = scsi_target(sdev);
2416 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002417
Mike Christiee881a172009-10-15 17:46:39 -07002418 if (reason != SCSI_QDEPTH_DEFAULT)
2419 return -EOPNOTSUPP;
2420
Eric Mooree80b0022007-09-14 18:49:03 -06002421 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002422 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002424 else if (sdev->type == TYPE_DISK &&
2425 vtarget->minSyncFactor <= MPT_ULTRA160)
2426 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2427 else
2428 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 } else
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05302430 max_depth = ioc->sh->can_queue;
2431
2432 if (!sdev->tagged_supported)
2433 max_depth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435 if (qdepth > max_depth)
2436 qdepth = max_depth;
2437 if (qdepth == 1)
2438 tagged = 0;
2439 else
2440 tagged = MSG_SIMPLE_TAG;
2441
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002442 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2443 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444}
2445
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446/*
2447 * OS entry point to adjust the queue_depths on a per-device basis.
2448 * Called once per device the bus scan. Use it to force the queue_depth
2449 * member to 1 if a device does not support Q tags.
2450 * Return non-zero if fails.
2451 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002452int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002453mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002455 struct Scsi_Host *sh = sdev->host;
2456 VirtTarget *vtarget;
2457 VirtDevice *vdevice;
2458 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002459 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002460 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002462 starget = scsi_target(sdev);
2463 vtarget = starget->hostdata;
2464 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Eric Mooree80b0022007-09-14 18:49:03 -06002466 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002467 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002468 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2469 if (ioc->bus_type == SPI)
2470 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002471 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002472 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002473 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
Eric Moore793955f2007-01-29 09:42:20 -07002475 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
Eric Mooree80b0022007-09-14 18:49:03 -06002477 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002479 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
Eric Mooree80b0022007-09-14 18:49:03 -06002481 if (ioc->bus_type == SPI)
2482 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002483 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002484 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002485 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
Mike Christiee881a172009-10-15 17:46:39 -07002487 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
2488 SCSI_QDEPTH_DEFAULT);
Eric Mooree80b0022007-09-14 18:49:03 -06002489 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002491 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002492 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Ryan Kuester2a1b7e52010-04-26 18:11:54 -05002494 blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
2495
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 return 0;
2497}
2498
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2500/*
2501 * Private routines...
2502 */
2503
2504/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2505/* Utility function to copy sense data from the scsi_cmnd buffer
2506 * to the FC and SCSI target structures.
2507 *
2508 */
2509static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002510mptscsih_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 -07002511{
Eric Moorea69de502007-09-14 18:48:19 -06002512 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 SCSIIORequest_t *pReq;
2514 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002515 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
2517 /* Get target structure
2518 */
2519 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002520 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
2522 if (sense_count) {
2523 u8 *sense_data;
2524 int req_index;
2525
2526 /* Copy the sense received into the scsi command block. */
2527 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002528 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2530
2531 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2532 */
Eric Mooree80b0022007-09-14 18:49:03 -06002533 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002534 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002537 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2539 ioc->events[idx].eventContext = ioc->eventContext;
2540
Dave Jones3d9780b2007-05-21 20:59:47 -04002541 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2542 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2543 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Dave Jones3d9780b2007-05-21 20:59:47 -04002545 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
2547 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002548 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002549 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002550 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002551 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2552 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002553 MPT_TARGET_FLAGS_LED_ON;
2554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 }
2556 }
2557 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002558 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2559 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 }
2561}
2562
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05302563/**
2564 * mptscsih_get_scsi_lookup - retrieves scmd entry
2565 * @ioc: Pointer to MPT_ADAPTER structure
2566 * @i: index into the array
2567 *
2568 * Returns the scsi_cmd pointer
2569 */
2570struct scsi_cmnd *
2571mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2572{
2573 unsigned long flags;
2574 struct scsi_cmnd *scmd;
2575
2576 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2577 scmd = ioc->ScsiLookup[i];
2578 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2579
2580 return scmd;
2581}
2582EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
Eric Mooree8206382007-09-29 10:16:53 -06002583
2584/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00002585 * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
Kashyap, Desai2f187862009-05-29 16:52:37 +05302586 * @ioc: Pointer to MPT_ADAPTER structure
2587 * @i: index into the array
2588 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002589 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302590 *
Eric Mooree8206382007-09-29 10:16:53 -06002591 **/
2592static struct scsi_cmnd *
2593mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2594{
2595 unsigned long flags;
2596 struct scsi_cmnd *scmd;
2597
2598 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2599 scmd = ioc->ScsiLookup[i];
2600 ioc->ScsiLookup[i] = NULL;
2601 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2602
2603 return scmd;
2604}
2605
2606/**
Ben Hutchings9b8f77a2010-05-23 17:02:30 -07002607 * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002608 *
2609 * @ioc: Pointer to MPT_ADAPTER structure
2610 * @i: index into the array
2611 * @scmd: scsi_cmnd pointer
2612 *
2613 **/
2614static void
2615mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2616{
2617 unsigned long flags;
2618
2619 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2620 ioc->ScsiLookup[i] = scmd;
2621 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2622}
2623
2624/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002625 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002626 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002627 * @sc: scsi_cmnd pointer
2628 */
Eric Mooree8206382007-09-29 10:16:53 -06002629static int
2630SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2631{
2632 unsigned long flags;
2633 int i, index=-1;
2634
2635 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2636 for (i = 0; i < ioc->req_depth; i++) {
2637 if (ioc->ScsiLookup[i] == sc) {
2638 index = i;
2639 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 }
2642
Eric Mooree8206382007-09-29 10:16:53 -06002643 out:
2644 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2645 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646}
2647
2648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002649int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2651{
2652 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
Eric Mooree7eae9f2007-09-29 10:15:59 -06002654 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302657 hd = shost_priv(ioc->sh);
2658 switch (reset_phase) {
2659 case MPT_IOC_SETUP_RESET:
2660 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2661 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302662 break;
2663 case MPT_IOC_PRE_RESET:
2664 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2665 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302666 mptscsih_flush_running_cmds(hd);
2667 break;
2668 case MPT_IOC_POST_RESET:
2669 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2670 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2671 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2672 ioc->internal_cmds.status |=
2673 MPT_MGMT_STATUS_DID_IOCRESET;
2674 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302676 break;
2677 default:
2678 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 return 1; /* currently means nothing really */
2681}
2682
2683/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002684int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2686{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2688
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302689 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2690 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2691 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Kashyap, Desai2f187862009-05-29 16:52:37 +05302693 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2694 event == MPI_EVENT_EXT_BUS_RESET) &&
2695 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2696 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
2698 return 1; /* currently means nothing really */
2699}
2700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2702/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 * Bus Scan and Domain Validation functionality ...
2704 */
2705
2706/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2707/*
2708 * mptscsih_scandv_complete - Scan and DV callback routine registered
2709 * to Fustion MPT (base) driver.
2710 *
2711 * @ioc: Pointer to MPT_ADAPTER structure
2712 * @mf: Pointer to original MPT request frame
2713 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2714 *
2715 * This routine is called from mpt.c::mpt_interrupt() at the completion
2716 * of any SCSI IO request.
2717 * This routine is registered with the Fusion MPT (base) driver at driver
2718 * load/init time via the mpt_register() API call.
2719 *
2720 * Returns 1 indicating alloc'd request frame ptr should be freed.
2721 *
2722 * Remark: Sets a completion code and (possibly) saves sense data
2723 * in the IOC member localReply structure.
2724 * Used ONLY for DV and other internal commands.
2725 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002726int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302727mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2728 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302731 SCSIIOReply_t *pReply;
2732 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302734 u8 *sense_data;
2735 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302737 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2738 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2739 if (!reply)
2740 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002741
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302742 pReply = (SCSIIOReply_t *) reply;
2743 pReq = (SCSIIORequest_t *) req;
2744 ioc->internal_cmds.completion_code =
2745 mptscsih_get_completion_code(ioc, req, reply);
2746 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2747 memcpy(ioc->internal_cmds.reply, reply,
2748 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2749 cmd = reply->u.hdr.Function;
2750 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2751 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2752 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2753 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2754 sense_data = ((u8 *)ioc->sense_buf_pool +
2755 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2756 sz = min_t(int, pReq->SenseBufferLength,
2757 MPT_SENSE_BUFFER_ALLOC);
2758 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302760 out:
2761 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2762 return 0;
2763 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2764 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 return 1;
2766}
2767
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302769/**
Ben Hutchings9b8f77a2010-05-23 17:02:30 -07002770 * mptscsih_get_completion_code - get completion code from MPT request
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302771 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap9cf46a32009-06-13 19:37:18 -07002772 * @req: Pointer to original MPT request frame
2773 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302774 *
2775 **/
2776static int
2777mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2778 MPT_FRAME_HDR *reply)
2779{
2780 SCSIIOReply_t *pReply;
2781 MpiRaidActionReply_t *pr;
2782 u8 scsi_status;
2783 u16 status;
2784 int completion_code;
2785
2786 pReply = (SCSIIOReply_t *)reply;
2787 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2788 scsi_status = pReply->SCSIStatus;
2789
2790 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2791 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2792 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2793 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2794
2795 switch (status) {
2796
2797 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2798 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2799 break;
2800
2801 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2802 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2803 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2804 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2805 completion_code = MPT_SCANDV_DID_RESET;
2806 break;
2807
2808 case MPI_IOCSTATUS_BUSY:
2809 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2810 completion_code = MPT_SCANDV_BUSY;
2811 break;
2812
2813 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2814 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2815 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2816 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2817 completion_code = MPT_SCANDV_GOOD;
2818 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2819 pr = (MpiRaidActionReply_t *)reply;
2820 if (le16_to_cpu(pr->ActionStatus) ==
2821 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2822 completion_code = MPT_SCANDV_GOOD;
2823 else
2824 completion_code = MPT_SCANDV_SOME_ERROR;
2825 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2826 completion_code = MPT_SCANDV_SENSE;
2827 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2828 if (req->u.scsireq.CDB[0] == INQUIRY)
2829 completion_code = MPT_SCANDV_ISSUE_SENSE;
2830 else
2831 completion_code = MPT_SCANDV_DID_RESET;
2832 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2833 completion_code = MPT_SCANDV_DID_RESET;
2834 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2835 completion_code = MPT_SCANDV_DID_RESET;
2836 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2837 completion_code = MPT_SCANDV_BUSY;
2838 else
2839 completion_code = MPT_SCANDV_GOOD;
2840 break;
2841
2842 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2843 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2844 completion_code = MPT_SCANDV_DID_RESET;
2845 else
2846 completion_code = MPT_SCANDV_SOME_ERROR;
2847 break;
2848 default:
2849 completion_code = MPT_SCANDV_SOME_ERROR;
2850 break;
2851
2852 } /* switch(status) */
2853
2854 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2855 " completionCode set to %08xh\n", ioc->name, completion_code));
2856 return completion_code;
2857}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2860/**
2861 * mptscsih_do_cmd - Do internal command.
2862 * @hd: MPT_SCSI_HOST pointer
2863 * @io: INTERNAL_CMD pointer.
2864 *
2865 * Issue the specified internally generated command and do command
2866 * specific cleanup. For bus scan / DV only.
2867 * NOTES: If command is Inquiry and status is good,
2868 * initialize a target structure, save the data
2869 *
2870 * Remark: Single threaded access only.
2871 *
2872 * Return:
2873 * < 0 if an illegal command or no resources
2874 *
2875 * 0 if good
2876 *
2877 * > 0 if command complete but some type of completion error.
2878 */
2879static int
2880mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2881{
2882 MPT_FRAME_HDR *mf;
2883 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302885 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 char cmdLen;
2887 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 +05302888 u8 cmd = io->cmd;
2889 MPT_ADAPTER *ioc = hd->ioc;
2890 int ret = 0;
2891 unsigned long timeleft;
2892 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302894 /* don't send internal command during diag reset */
2895 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2896 if (ioc->ioc_reset_in_progress) {
2897 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2898 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2899 "%s: busy with host reset\n", ioc->name, __func__));
2900 return MPT_SCANDV_BUSY;
2901 }
2902 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2903
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302904 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
2906 /* Set command specific information
2907 */
2908 switch (cmd) {
2909 case INQUIRY:
2910 cmdLen = 6;
2911 dir = MPI_SCSIIO_CONTROL_READ;
2912 CDB[0] = cmd;
2913 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302914 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 break;
2916
2917 case TEST_UNIT_READY:
2918 cmdLen = 6;
2919 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302920 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 break;
2922
2923 case START_STOP:
2924 cmdLen = 6;
2925 dir = MPI_SCSIIO_CONTROL_READ;
2926 CDB[0] = cmd;
2927 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302928 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 break;
2930
2931 case REQUEST_SENSE:
2932 cmdLen = 6;
2933 CDB[0] = cmd;
2934 CDB[4] = io->size;
2935 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302936 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 break;
2938
2939 case READ_BUFFER:
2940 cmdLen = 10;
2941 dir = MPI_SCSIIO_CONTROL_READ;
2942 CDB[0] = cmd;
2943 if (io->flags & MPT_ICFLAG_ECHO) {
2944 CDB[1] = 0x0A;
2945 } else {
2946 CDB[1] = 0x02;
2947 }
2948
2949 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2950 CDB[1] |= 0x01;
2951 }
2952 CDB[6] = (io->size >> 16) & 0xFF;
2953 CDB[7] = (io->size >> 8) & 0xFF;
2954 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302955 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 break;
2957
2958 case WRITE_BUFFER:
2959 cmdLen = 10;
2960 dir = MPI_SCSIIO_CONTROL_WRITE;
2961 CDB[0] = cmd;
2962 if (io->flags & MPT_ICFLAG_ECHO) {
2963 CDB[1] = 0x0A;
2964 } else {
2965 CDB[1] = 0x02;
2966 }
2967 CDB[6] = (io->size >> 16) & 0xFF;
2968 CDB[7] = (io->size >> 8) & 0xFF;
2969 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302970 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 break;
2972
2973 case RESERVE:
2974 cmdLen = 6;
2975 dir = MPI_SCSIIO_CONTROL_READ;
2976 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302977 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 break;
2979
2980 case RELEASE:
2981 cmdLen = 6;
2982 dir = MPI_SCSIIO_CONTROL_READ;
2983 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302984 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 break;
2986
2987 case SYNCHRONIZE_CACHE:
2988 cmdLen = 10;
2989 dir = MPI_SCSIIO_CONTROL_READ;
2990 CDB[0] = cmd;
2991// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302992 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 break;
2994
2995 default:
2996 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302997 ret = -EFAULT;
2998 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 }
3000
3001 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303002 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 */
Eric Mooree80b0022007-09-14 18:49:03 -06003004 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303005 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
3006 ioc->name, __func__));
3007 ret = MPT_SCANDV_BUSY;
3008 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 }
3010
3011 pScsiReq = (SCSIIORequest_t *) mf;
3012
3013 /* Get the request index */
3014 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3015 ADD_INDEX_LOG(my_idx); /* for debug */
3016
3017 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3018 pScsiReq->TargetID = io->physDiskNum;
3019 pScsiReq->Bus = 0;
3020 pScsiReq->ChainOffset = 0;
3021 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3022 } else {
3023 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003024 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 pScsiReq->ChainOffset = 0;
3026 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3027 }
3028
3029 pScsiReq->CDBLength = cmdLen;
3030 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3031
3032 pScsiReq->Reserved = 0;
3033
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303034 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 /* MsgContext set in mpt_get_msg_fram call */
3036
Eric Moore793955f2007-01-29 09:42:20 -07003037 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3040 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3041 else
3042 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3043
3044 if (cmd == REQUEST_SENSE) {
3045 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303046 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3047 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 }
3049
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303050 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pScsiReq->CDB[ii] = CDB[ii];
3052
3053 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003054 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3056
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303057 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3058 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3059 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303061 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303062 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303063 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3064 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303065 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303066 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303068 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003069 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303070 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3071 timeout*HZ);
3072 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3073 ret = MPT_SCANDV_DID_RESET;
3074 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3075 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3076 cmd));
3077 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3078 mpt_free_msg_frame(ioc, mf);
3079 goto out;
3080 }
3081 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09003082 printk(MYIOC_s_WARN_FMT
3083 "Issuing Reset from %s!! doorbell=0x%08xh"
3084 " cmd=0x%02x\n",
3085 ioc->name, __func__, mpt_GetIocState(ioc, 0),
3086 cmd);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05303087 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303088 mpt_free_msg_frame(ioc, mf);
3089 }
3090 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 }
3092
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303093 ret = ioc->internal_cmds.completion_code;
3094 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3095 ioc->name, __func__, ret));
3096
3097 out:
3098 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3099 mutex_unlock(&ioc->internal_cmds.mutex);
3100 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101}
3102
3103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3104/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003105 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3106 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003107 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003108 *
3109 * Uses the ISR, but with special processing.
3110 * MUST be single-threaded.
3111 *
3112 */
3113static void
3114mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3115{
3116 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
Eric Moorecc78d302007-06-15 17:27:21 -06003118 /* Ignore hidden raid components, this is handled when the command
3119 * is sent to the volume
3120 */
3121 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3122 return;
3123
3124 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3125 !vdevice->configured_lun)
3126 return;
3127
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 /* Following parameters will not change
3129 * in this routine.
3130 */
3131 iocmd.cmd = SYNCHRONIZE_CACHE;
3132 iocmd.flags = 0;
3133 iocmd.physDiskNum = -1;
3134 iocmd.data = NULL;
3135 iocmd.data_dma = -1;
3136 iocmd.size = 0;
3137 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003138 iocmd.channel = vdevice->vtarget->channel;
3139 iocmd.id = vdevice->vtarget->id;
3140 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
Eric Moorecc78d302007-06-15 17:27:21 -06003142 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143}
3144
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303145static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003146mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3147 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303148{
Tony Jonesee959b02008-02-22 00:13:36 +01003149 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003150 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303151 MPT_ADAPTER *ioc = hd->ioc;
3152
3153 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3154 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3155 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3156 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3157 ioc->facts.FWVersion.Word & 0x000000FF);
3158}
Tony Jonesee959b02008-02-22 00:13:36 +01003159static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303160
3161static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003162mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3163 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303164{
Tony Jonesee959b02008-02-22 00:13:36 +01003165 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003166 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303167 MPT_ADAPTER *ioc = hd->ioc;
3168
3169 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3170 (ioc->biosVersion & 0xFF000000) >> 24,
3171 (ioc->biosVersion & 0x00FF0000) >> 16,
3172 (ioc->biosVersion & 0x0000FF00) >> 8,
3173 ioc->biosVersion & 0x000000FF);
3174}
Tony Jonesee959b02008-02-22 00:13:36 +01003175static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303176
3177static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003178mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3179 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303180{
Tony Jonesee959b02008-02-22 00:13:36 +01003181 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003182 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303183 MPT_ADAPTER *ioc = hd->ioc;
3184
3185 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3186}
Tony Jonesee959b02008-02-22 00:13:36 +01003187static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303188
3189static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003190mptscsih_version_product_show(struct device *dev,
3191 struct device_attribute *attr,
3192char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303193{
Tony Jonesee959b02008-02-22 00:13:36 +01003194 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003195 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303196 MPT_ADAPTER *ioc = hd->ioc;
3197
3198 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3199}
Tony Jonesee959b02008-02-22 00:13:36 +01003200static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303201 mptscsih_version_product_show, NULL);
3202
3203static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003204mptscsih_version_nvdata_persistent_show(struct device *dev,
3205 struct device_attribute *attr,
3206 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303207{
Tony Jonesee959b02008-02-22 00:13:36 +01003208 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003209 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303210 MPT_ADAPTER *ioc = hd->ioc;
3211
3212 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3213 ioc->nvdata_version_persistent);
3214}
Tony Jonesee959b02008-02-22 00:13:36 +01003215static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303216 mptscsih_version_nvdata_persistent_show, NULL);
3217
3218static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003219mptscsih_version_nvdata_default_show(struct device *dev,
3220 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303221{
Tony Jonesee959b02008-02-22 00:13:36 +01003222 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003223 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303224 MPT_ADAPTER *ioc = hd->ioc;
3225
3226 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3227}
Tony Jonesee959b02008-02-22 00:13:36 +01003228static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303229 mptscsih_version_nvdata_default_show, NULL);
3230
3231static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003232mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3233 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303234{
Tony Jonesee959b02008-02-22 00:13:36 +01003235 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003236 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303237 MPT_ADAPTER *ioc = hd->ioc;
3238
3239 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3240}
Tony Jonesee959b02008-02-22 00:13:36 +01003241static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303242
3243static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003244mptscsih_board_assembly_show(struct device *dev,
3245 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303246{
Tony Jonesee959b02008-02-22 00:13:36 +01003247 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003248 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303249 MPT_ADAPTER *ioc = hd->ioc;
3250
3251 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3252}
Tony Jonesee959b02008-02-22 00:13:36 +01003253static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303254 mptscsih_board_assembly_show, NULL);
3255
3256static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003257mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3258 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303259{
Tony Jonesee959b02008-02-22 00:13:36 +01003260 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003261 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303262 MPT_ADAPTER *ioc = hd->ioc;
3263
3264 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3265}
Tony Jonesee959b02008-02-22 00:13:36 +01003266static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303267 mptscsih_board_tracer_show, NULL);
3268
3269static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003270mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3271 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303272{
Tony Jonesee959b02008-02-22 00:13:36 +01003273 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003274 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303275 MPT_ADAPTER *ioc = hd->ioc;
3276
3277 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3278}
Tony Jonesee959b02008-02-22 00:13:36 +01003279static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303280 mptscsih_io_delay_show, NULL);
3281
3282static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003283mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3284 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303285{
Tony Jonesee959b02008-02-22 00:13:36 +01003286 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003287 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303288 MPT_ADAPTER *ioc = hd->ioc;
3289
3290 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3291}
Tony Jonesee959b02008-02-22 00:13:36 +01003292static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303293 mptscsih_device_delay_show, NULL);
3294
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303295static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003296mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3297 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303298{
Tony Jonesee959b02008-02-22 00:13:36 +01003299 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003300 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303301 MPT_ADAPTER *ioc = hd->ioc;
3302
3303 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3304}
3305static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003306mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3307 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303308{
Tony Jonesee959b02008-02-22 00:13:36 +01003309 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003310 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303311 MPT_ADAPTER *ioc = hd->ioc;
3312 int val = 0;
3313
3314 if (sscanf(buf, "%x", &val) != 1)
3315 return -EINVAL;
3316
3317 ioc->debug_level = val;
3318 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3319 ioc->name, ioc->debug_level);
3320 return strlen(buf);
3321}
Tony Jonesee959b02008-02-22 00:13:36 +01003322static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3323 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303324
Tony Jonesee959b02008-02-22 00:13:36 +01003325struct device_attribute *mptscsih_host_attrs[] = {
3326 &dev_attr_version_fw,
3327 &dev_attr_version_bios,
3328 &dev_attr_version_mpi,
3329 &dev_attr_version_product,
3330 &dev_attr_version_nvdata_persistent,
3331 &dev_attr_version_nvdata_default,
3332 &dev_attr_board_name,
3333 &dev_attr_board_assembly,
3334 &dev_attr_board_tracer,
3335 &dev_attr_io_delay,
3336 &dev_attr_device_delay,
3337 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303338 NULL,
3339};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303340
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303341EXPORT_SYMBOL(mptscsih_host_attrs);
3342
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003343EXPORT_SYMBOL(mptscsih_remove);
3344EXPORT_SYMBOL(mptscsih_shutdown);
3345#ifdef CONFIG_PM
3346EXPORT_SYMBOL(mptscsih_suspend);
3347EXPORT_SYMBOL(mptscsih_resume);
3348#endif
3349EXPORT_SYMBOL(mptscsih_proc_info);
3350EXPORT_SYMBOL(mptscsih_info);
3351EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003352EXPORT_SYMBOL(mptscsih_slave_destroy);
3353EXPORT_SYMBOL(mptscsih_slave_configure);
3354EXPORT_SYMBOL(mptscsih_abort);
3355EXPORT_SYMBOL(mptscsih_dev_reset);
3356EXPORT_SYMBOL(mptscsih_bus_reset);
3357EXPORT_SYMBOL(mptscsih_host_reset);
3358EXPORT_SYMBOL(mptscsih_bios_param);
3359EXPORT_SYMBOL(mptscsih_io_done);
3360EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3361EXPORT_SYMBOL(mptscsih_scandv_complete);
3362EXPORT_SYMBOL(mptscsih_event_process);
3363EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003364EXPORT_SYMBOL(mptscsih_change_queue_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003366/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/