blob: 81279b3d694c670ab982520eaafbf6ef2ace54cf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptscsih.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/kdev_t.h>
52#include <linux/blkdev.h>
53#include <linux/delay.h> /* for mdelay */
54#include <linux/interrupt.h> /* needed for in_interrupt() proto */
55#include <linux/reboot.h> /* notifier code */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/workqueue.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_host.h>
62#include <scsi/scsi_tcq.h>
Moore, Eric Deane0fc15b2005-09-15 13:17:14 -060063#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "mptbase.h"
66#include "mptscsih.h"
Eric Moorebf451522006-07-11 17:25:35 -060067#include "lsi/mpi_log_sas.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT SCSI Host driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptscsih"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*
81 * Other private/forward protos...
82 */
Kashyap, Desaidb7051b2009-05-29 16:56:59 +053083struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
Eric Mooree8206382007-09-29 10:16:53 -060084static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
85static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
86static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040087int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040089int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
92 SCSIIORequest_t *pReq, int req_idx);
93static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040094static 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 -070095
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +053096int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id,
97 int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -040099int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
100int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530102void
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530103mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code);
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530104static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
105 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400106int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700108static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530110static int
111mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
112 SCSITaskMgmtReply_t *pScsiTmReply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400113void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700114void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400116int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
117int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#endif
119
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900120#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
124/*
125 * mptscsih_getFreeChainBuffer - Function to get a free chain
126 * from the MPT_SCSI_HOST FreeChainQ.
127 * @ioc: Pointer to MPT_ADAPTER structure
128 * @req_idx: Index of the SCSI IO request frame. (output)
129 *
130 * return SUCCESS or FAILED
131 */
132static inline int
133mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
134{
135 MPT_FRAME_HDR *chainBuf;
136 unsigned long flags;
137 int rc;
138 int chain_idx;
139
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530140 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600141 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 spin_lock_irqsave(&ioc->FreeQlock, flags);
143 if (!list_empty(&ioc->FreeChainQ)) {
144 int offset;
145
146 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
147 u.frame.linkage.list);
148 list_del(&chainBuf->u.frame.linkage.list);
149 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
150 chain_idx = offset / ioc->req_sz;
151 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600152 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
153 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
154 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 } else {
156 rc = FAILED;
157 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600158 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
159 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
162
163 *retIndex = chain_idx;
164 return rc;
165} /* mptscsih_getFreeChainBuffer() */
166
167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
168/*
169 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
170 * SCSIIORequest_t Message Frame.
171 * @ioc: Pointer to MPT_ADAPTER structure
172 * @SCpnt: Pointer to scsi_cmnd structure
173 * @pReq: Pointer to SCSIIORequest_t structure
174 *
175 * Returns ...
176 */
177static int
178mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
179 SCSIIORequest_t *pReq, int req_idx)
180{
181 char *psge;
182 char *chainSge;
183 struct scatterlist *sg;
184 int frm_sz;
185 int sges_left, sg_done;
186 int chain_idx = MPT_HOST_NO_CHAIN;
187 int sgeOffset;
188 int numSgeSlots, numSgeThisFrame;
189 u32 sgflags, sgdir, thisxfer = 0;
190 int chain_dma_off = 0;
191 int newIndex;
192 int ii;
193 dma_addr_t v2;
194 u32 RequestNB;
195
196 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
197 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
198 sgdir = MPT_TRANSFER_HOST_TO_IOC;
199 } else {
200 sgdir = MPT_TRANSFER_IOC_TO_HOST;
201 }
202
203 psge = (char *) &pReq->SGL;
204 frm_sz = ioc->req_sz;
205
206 /* Map the data portion, if any.
207 * sges_left = 0 if no data transfer.
208 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900209 sges_left = scsi_dma_map(SCpnt);
210 if (sges_left < 0)
211 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 /* Handle the SG case.
214 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900215 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 sg_done = 0;
217 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
218 chainSge = NULL;
219
220 /* Prior to entering this loop - the following must be set
221 * current MF: sgeOffset (bytes)
222 * chainSge (Null if original MF is not a chain buffer)
223 * sg_done (num SGE done for this MF)
224 */
225
226nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530227 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
229
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530230 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 /* Get first (num - 1) SG elements
233 * Skip any SG entries with a length of 0
234 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
235 */
236 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
237 thisxfer = sg_dma_len(sg);
238 if (thisxfer == 0) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530239 /* Get next SG element from the OS */
240 sg = sg_next(sg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 sg_done++;
242 continue;
243 }
244
245 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530246 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Kashyap, Desai2f187862009-05-29 16:52:37 +0530248 /* Get next SG element from the OS */
249 sg = sg_next(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530250 psge += ioc->SGE_size;
251 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 sg_done++;
253 }
254
255 if (numSgeThisFrame == sges_left) {
256 /* Add last element, end of buffer and end of list flags.
257 */
258 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
259 MPT_SGE_FLAGS_END_OF_BUFFER |
260 MPT_SGE_FLAGS_END_OF_LIST;
261
262 /* Add last SGE and set termination flags.
263 * Note: Last SGE may have a length of 0 - which should be ok.
264 */
265 thisxfer = sg_dma_len(sg);
266
267 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530268 ioc->add_sge(psge, sgflags | thisxfer, v2);
269 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sg_done++;
271
272 if (chainSge) {
273 /* The current buffer is a chain buffer,
274 * but there is not another one.
275 * Update the chain element
276 * Offset and Length fields.
277 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530278 ioc->add_chain((char *)chainSge, 0, sgeOffset,
279 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 } else {
281 /* The current buffer is the original MF
282 * and there is no Chain buffer.
283 */
284 pReq->ChainOffset = 0;
285 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530286 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
288 ioc->RequestNB[req_idx] = RequestNB;
289 }
290 } else {
291 /* At least one chain buffer is needed.
292 * Complete the first MF
293 * - last SGE element, set the LastElement bit
294 * - set ChainOffset (words) for orig MF
295 * (OR finish previous MF chain buffer)
296 * - update MFStructPtr ChainIndex
297 * - Populate chain element
298 * Also
299 * Loop until done.
300 */
301
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530302 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 ioc->name, sg_done));
304
305 /* Set LAST_ELEMENT flag for last non-chain element
306 * in the buffer. Since psge points at the NEXT
307 * SGE element, go back one SGE element, update the flags
308 * and reset the pointer. (Note: sgflags & thisxfer are already
309 * set properly).
310 */
311 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530312 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 sgflags = le32_to_cpu(*ptmp);
314 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
315 *ptmp = cpu_to_le32(sgflags);
316 }
317
318 if (chainSge) {
319 /* The current buffer is a chain buffer.
320 * chainSge points to the previous Chain Element.
321 * Update its chain element Offset and Length (must
322 * include chain element size) fields.
323 * Old chain element is now complete.
324 */
325 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530326 sgeOffset += ioc->SGE_size;
327 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
328 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 } else {
330 /* The original MF buffer requires a chain buffer -
331 * set the offset.
332 * Last element in this MF is a chain element.
333 */
334 pReq->ChainOffset = (u8) (sgeOffset >> 2);
335 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530336 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 -0700337 ioc->RequestNB[req_idx] = RequestNB;
338 }
339
340 sges_left -= sg_done;
341
342
343 /* NOTE: psge points to the beginning of the chain element
344 * in current buffer. Get a chain buffer.
345 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200346 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530347 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200348 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
349 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353 /* Update the tracking arrays.
354 * If chainSge == NULL, update ReqToChain, else ChainToChain
355 */
356 if (chainSge) {
357 ioc->ChainToChain[chain_idx] = newIndex;
358 } else {
359 ioc->ReqToChain[req_idx] = newIndex;
360 }
361 chain_idx = newIndex;
362 chain_dma_off = ioc->req_sz * chain_idx;
363
364 /* Populate the chainSGE for the current buffer.
365 * - Set chain buffer pointer to psge and fill
366 * out the Address and Flags fields.
367 */
368 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600369 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
370 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 /* Start the SGE for the next buffer
373 */
374 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
375 sgeOffset = 0;
376 sg_done = 0;
377
Eric Moore29dd3602007-09-14 18:46:51 -0600378 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
379 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 /* Start the SGE for the next buffer
382 */
383
384 goto nextSGEset;
385 }
386
387 return SUCCESS;
388} /* mptscsih_AddSGE() */
389
Eric Moore786899b2006-07-11 17:22:22 -0600390static void
391mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
392 U32 SlotStatus)
393{
394 MPT_FRAME_HDR *mf;
395 SEPRequest_t *SEPMsg;
396
Eric Moorecc78d302007-06-15 17:27:21 -0600397 if (ioc->bus_type != SAS)
398 return;
399
400 /* Not supported for hidden raid components
401 */
402 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600403 return;
404
405 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530406 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700407 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600408 return;
409 }
410
411 SEPMsg = (SEPRequest_t *)mf;
412 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700413 SEPMsg->Bus = vtarget->channel;
414 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600415 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
416 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530417 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700418 "Sending SEP cmd=%x channel=%d id=%d\n",
419 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600420 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
421}
422
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530423#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700424/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530425 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700426 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700427 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530428 * @pScsiReply: Pointer to MPT reply frame
429 *
430 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700431 *
432 * Refer to lsi/mpi.h.
433 **/
434static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530435mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700436{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530437 char *desc = NULL;
438 char *desc1 = NULL;
439 u16 ioc_status;
440 u8 skey, asc, ascq;
441
442 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700443
444 switch (ioc_status) {
445
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530446 case MPI_IOCSTATUS_SUCCESS:
447 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700448 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530449 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
450 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700451 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530452 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
453 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700454 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530455 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
456 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700457 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530458 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
459 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700460 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530461 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
462 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700463 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530464 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
465 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700466 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530467 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
468 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700469 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530470 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
471 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700472 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530473 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
474 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700475 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530476 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
477 desc = "task management failed";
478 break;
479 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
480 desc = "IOC terminated";
481 break;
482 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
483 desc = "ext terminated";
484 break;
485 default:
486 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700487 break;
488 }
489
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530490 switch (pScsiReply->SCSIStatus)
491 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700492
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530493 case MPI_SCSI_STATUS_SUCCESS:
494 desc1 = "success";
495 break;
496 case MPI_SCSI_STATUS_CHECK_CONDITION:
497 desc1 = "check condition";
498 break;
499 case MPI_SCSI_STATUS_CONDITION_MET:
500 desc1 = "condition met";
501 break;
502 case MPI_SCSI_STATUS_BUSY:
503 desc1 = "busy";
504 break;
505 case MPI_SCSI_STATUS_INTERMEDIATE:
506 desc1 = "intermediate";
507 break;
508 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
509 desc1 = "intermediate condmet";
510 break;
511 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
512 desc1 = "reservation conflict";
513 break;
514 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
515 desc1 = "command terminated";
516 break;
517 case MPI_SCSI_STATUS_TASK_SET_FULL:
518 desc1 = "task set full";
519 break;
520 case MPI_SCSI_STATUS_ACA_ACTIVE:
521 desc1 = "aca active";
522 break;
523 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
524 desc1 = "fcpext device logged out";
525 break;
526 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
527 desc1 = "fcpext no link";
528 break;
529 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
530 desc1 = "fcpext unassigned";
531 break;
532 default:
533 desc1 = "";
534 break;
535 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700536
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530537 scsi_print_command(sc);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530538 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n",
539 ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun);
Eric Moore29dd3602007-09-14 18:46:51 -0600540 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
541 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
542 scsi_get_resid(sc));
543 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
544 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530545 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530546
Eric Moore29dd3602007-09-14 18:46:51 -0600547 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530548 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600549 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530550 pScsiReply->SCSIState);
551
552 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
553 skey = sc->sense_buffer[2] & 0x0F;
554 asc = sc->sense_buffer[12];
555 ascq = sc->sense_buffer[13];
556
Eric Moore29dd3602007-09-14 18:46:51 -0600557 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
558 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530559 }
560
561 /*
562 * Look for + dump FCP ResponseInfo[]!
563 */
564 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
565 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600566 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
567 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700568}
569#endif
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
572/*
573 * mptscsih_io_done - Main SCSI IO callback routine registered to
574 * Fusion MPT (base) driver
575 * @ioc: Pointer to MPT_ADAPTER structure
576 * @mf: Pointer to original MPT request frame
577 * @r: Pointer to MPT reply frame (NULL if TurboReply)
578 *
579 * This routine is called from mpt.c::mpt_interrupt() at the completion
580 * of any SCSI IO request.
581 * This routine is registered with the Fusion MPT (base) driver at driver
582 * load/init time via the mpt_register() API call.
583 *
584 * Returns 1 indicating alloc'd request frame ptr should be freed.
585 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400586int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
588{
589 struct scsi_cmnd *sc;
590 MPT_SCSI_HOST *hd;
591 SCSIIORequest_t *pScsiReq;
592 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700593 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600594 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600595 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Eric Mooree7eae9f2007-09-29 10:15:59 -0600597 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700599 req_idx_MR = (mr != NULL) ?
600 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
Kashyap, Desai2f187862009-05-29 16:52:37 +0530601
602 /* Special case, where already freed message frame is received from
603 * Firmware. It happens with Resetting IOC.
604 * Return immediately. Do not care
605 */
Moore, Eric2254c862006-01-17 17:06:29 -0700606 if ((req_idx != req_idx_MR) ||
Kashyap, Desai2f187862009-05-29 16:52:37 +0530607 (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf))
Moore, Eric2254c862006-01-17 17:06:29 -0700608 return 0;
Moore, Eric2254c862006-01-17 17:06:29 -0700609
Eric Mooree8206382007-09-29 10:16:53 -0600610 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 if (sc == NULL) {
612 MPIHeader_t *hdr = (MPIHeader_t *)mf;
613
614 /* Remark: writeSDP1 will use the ScsiDoneCtx
615 * If a SCSI I/O cmd, device disabled by OS and
616 * completion done. Cannot touch sc struct. Just free mem.
617 */
618 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
619 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
620 ioc->name);
621
622 mptscsih_freeChainBuffers(ioc, req_idx);
623 return 1;
624 }
625
Eric Moore3dc0b032006-07-11 17:32:33 -0600626 if ((unsigned char *)mf != sc->host_scribble) {
627 mptscsih_freeChainBuffers(ioc, req_idx);
628 return 1;
629 }
630
Kashyap, Desaifea98402009-09-02 11:45:53 +0530631 if (ioc->bus_type == SAS) {
632 VirtDevice *vdevice = sc->device->hostdata;
633
634 if (!vdevice || !vdevice->vtarget ||
635 vdevice->vtarget->deleted) {
636 sc->result = DID_NO_CONNECT << 16;
637 goto out;
638 }
639 }
640
Eric Moore3dc0b032006-07-11 17:32:33 -0600641 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 sc->result = DID_OK << 16; /* Set default reply as OK */
643 pScsiReq = (SCSIIORequest_t *) mf;
644 pScsiReply = (SCSIIOReply_t *) mr;
645
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200646 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530647 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200648 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
649 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
650 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530651 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200652 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
653 ioc->name, mf, mr, sc, req_idx));
654 }
655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if (pScsiReply == NULL) {
657 /* special context reply handling */
658 ;
659 } else {
660 u32 xfer_cnt;
661 u16 status;
662 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700663 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
666 scsi_state = pScsiReply->SCSIState;
667 scsi_status = pScsiReply->SCSIStatus;
668 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900669 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700670 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600672 /*
673 * if we get a data underrun indication, yet no data was
674 * transferred and the SCSI status indicates that the
675 * command was never started, change the data underrun
676 * to success
677 */
678 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
679 (scsi_status == MPI_SCSI_STATUS_BUSY ||
680 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
681 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
682 status = MPI_IOCSTATUS_SUCCESS;
683 }
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400686 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 /*
689 * Look for + dump FCP ResponseInfo[]!
690 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600691 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
692 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600693 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
694 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700695 sc->device->host->host_no, sc->device->channel,
696 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 le32_to_cpu(pScsiReply->ResponseInfo));
698 }
699
700 switch(status) {
701 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
Kashyap, Desaid23321b2009-08-05 12:51:25 +0530702 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* CHECKME!
704 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
705 * But not: DID_BUS_BUSY lest one risk
706 * killing interrupt handler:-(
707 */
708 sc->result = SAM_STAT_BUSY;
709 break;
710
711 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
712 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
713 sc->result = DID_BAD_TARGET << 16;
714 break;
715
716 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
717 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600718 if (ioc->bus_type != FC)
719 sc->result = DID_NO_CONNECT << 16;
720 /* else fibre, just stall until rescan event */
721 else
722 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
725 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600726
Eric Moorea69de502007-09-14 18:48:19 -0600727 vdevice = sc->device->hostdata;
728 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600729 break;
Eric Moorea69de502007-09-14 18:48:19 -0600730 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600731 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
732 mptscsih_issue_sep_command(ioc, vtarget,
733 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
734 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 break;
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600739 if ( ioc->bus_type == SAS ) {
740 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
741 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700742 if ((log_info & SAS_LOGINFO_MASK)
743 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600744 sc->result = (DID_BUS_BUSY << 16);
745 break;
746 }
747 }
Eric Moore86dd4242007-01-04 20:44:01 -0700748 } else if (ioc->bus_type == FC) {
749 /*
750 * The FC IOC may kill a request for variety of
751 * reasons, some of which may be recovered by a
752 * retry, some which are unlikely to be
753 * recovered. Return DID_ERROR instead of
754 * DID_RESET to permit retry of the command,
755 * just not an infinite number of them
756 */
757 sc->result = DID_ERROR << 16;
758 break;
Eric Moorebf451522006-07-11 17:25:35 -0600759 }
760
761 /*
762 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
763 */
764
765 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 /* Linux handles an unsolicited DID_RESET better
767 * than an unsolicited DID_ABORT.
768 */
769 sc->result = DID_RESET << 16;
770
Kashyap, Desai2f187862009-05-29 16:52:37 +0530771 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
772 if (ioc->bus_type == FC)
773 sc->result = DID_ERROR << 16;
774 else
775 sc->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 break;
777
778 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900779 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600780 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
781 sc->result=DID_SOFT_ERROR << 16;
782 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600784 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700785 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600786 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
790 /*
791 * Do upfront check for valid SenseData and give it
792 * precedence!
793 */
794 sc->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530795 if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
796
797 /*
798 * For an Errata on LSI53C1030
799 * When the length of request data
800 * and transfer data are different
801 * with result of command (READ or VERIFY),
802 * DID_SOFT_ERROR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 */
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530804 if (ioc->bus_type == SPI) {
805 if (pScsiReq->CDB[0] == READ_6 ||
806 pScsiReq->CDB[0] == READ_10 ||
807 pScsiReq->CDB[0] == READ_12 ||
808 pScsiReq->CDB[0] == READ_16 ||
809 pScsiReq->CDB[0] == VERIFY ||
810 pScsiReq->CDB[0] == VERIFY_16) {
811 if (scsi_bufflen(sc) !=
812 xfer_cnt) {
813 sc->result =
814 DID_SOFT_ERROR << 16;
815 printk(KERN_WARNING "Errata"
816 "on LSI53C1030 occurred."
817 "sc->req_bufflen=0x%02x,"
818 "xfer_cnt=0x%02x\n",
819 scsi_bufflen(sc),
820 xfer_cnt);
821 }
822 }
823 }
824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600826 if (scsi_status == SAM_STAT_BUSY)
827 sc->result = SAM_STAT_BUSY;
828 else
829 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
832 /* What to do?
833 */
834 sc->result = DID_SOFT_ERROR << 16;
835 }
836 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
837 /* Not real sure here either... */
838 sc->result = DID_RESET << 16;
839 }
840 }
841
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530842
Eric Moore29dd3602007-09-14 18:46:51 -0600843 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
844 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
845 ioc->name, sc->underflow));
846 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
847 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 /* Report Queue Full
850 */
851 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
852 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 break;
855
Moore, Eric7e551472006-01-16 18:53:21 -0700856 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900857 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
859 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600860 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 if (scsi_state == 0) {
862 ;
Kashyap, Desai9b53b392009-10-07 11:27:40 +0530863 } else if (scsi_state &
864 MPI_SCSI_STATE_AUTOSENSE_VALID) {
865
866 /*
867 * For potential trouble on LSI53C1030.
868 * (date:2007.xx.)
869 * It is checked whether the length of
870 * request data is equal to
871 * the length of transfer and residual.
872 * MEDIUM_ERROR is set by incorrect data.
873 */
874 if ((ioc->bus_type == SPI) &&
875 (sc->sense_buffer[2] & 0x20)) {
876 u32 difftransfer;
877 difftransfer =
878 sc->sense_buffer[3] << 24 |
879 sc->sense_buffer[4] << 16 |
880 sc->sense_buffer[5] << 8 |
881 sc->sense_buffer[6];
882 if (((sc->sense_buffer[3] & 0x80) ==
883 0x80) && (scsi_bufflen(sc)
884 != xfer_cnt)) {
885 sc->sense_buffer[2] =
886 MEDIUM_ERROR;
887 sc->sense_buffer[12] = 0xff;
888 sc->sense_buffer[13] = 0xff;
889 printk(KERN_WARNING"Errata"
890 "on LSI53C1030 occurred."
891 "sc->req_bufflen=0x%02x,"
892 "xfer_cnt=0x%02x\n" ,
893 scsi_bufflen(sc),
894 xfer_cnt);
895 }
896 if (((sc->sense_buffer[3] & 0x80)
897 != 0x80) &&
898 (scsi_bufflen(sc) !=
899 xfer_cnt + difftransfer)) {
900 sc->sense_buffer[2] =
901 MEDIUM_ERROR;
902 sc->sense_buffer[12] = 0xff;
903 sc->sense_buffer[13] = 0xff;
904 printk(KERN_WARNING
905 "Errata on LSI53C1030 occurred"
906 "sc->req_bufflen=0x%02x,"
907 " xfer_cnt=0x%02x,"
908 "difftransfer=0x%02x\n",
909 scsi_bufflen(sc),
910 xfer_cnt,
911 difftransfer);
912 }
913 }
914
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 /*
916 * If running against circa 200003dd 909 MPT f/w,
917 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
918 * (QUEUE_FULL) returned from device! --> get 0x0000?128
919 * and with SenseBytes set to 0.
920 */
921 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
922 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
923
924 }
925 else if (scsi_state &
926 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
927 ) {
928 /*
929 * What to do?
930 */
931 sc->result = DID_SOFT_ERROR << 16;
932 }
933 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
934 /* Not real sure here either... */
935 sc->result = DID_RESET << 16;
936 }
937 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
938 /* Device Inq. data indicates that it supports
939 * QTags, but rejects QTag messages.
940 * This command completed OK.
941 *
942 * Not real sure here either so do nothing... */
943 }
944
945 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
946 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
947
948 /* Add handling of:
949 * Reservation Conflict, Busy,
950 * Command Terminated, CHECK
951 */
952 break;
953
954 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
955 sc->result = DID_SOFT_ERROR << 16;
956 break;
957
958 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
959 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
960 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
961 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
963 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
965 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
966 default:
967 /*
968 * What to do?
969 */
970 sc->result = DID_SOFT_ERROR << 16;
971 break;
972
973 } /* switch(status) */
974
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530975#ifdef CONFIG_FUSION_LOGGING
976 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
977 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700978#endif
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 } /* end of address reply case */
Kashyap, Desaifea98402009-09-02 11:45:53 +0530981out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900983 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 sc->scsi_done(sc); /* Issue the command callback */
986
987 /* Free Chain buffers */
988 mptscsih_freeChainBuffers(ioc, req_idx);
989 return 1;
990}
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992/*
993 * mptscsih_flush_running_cmds - For each command found, search
994 * Scsi_Host instance taskQ and reply to OS.
995 * Called only if recovering from a FW reload.
996 * @hd: Pointer to a SCSI HOST structure
997 *
998 * Returns: None.
999 *
1000 * Must be called while new I/Os are being queued.
1001 */
1002static void
1003mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
1004{
1005 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001006 struct scsi_cmnd *sc;
1007 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 int ii;
Eric Mooree8206382007-09-29 10:16:53 -06001009 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Eric Mooree8206382007-09-29 10:16:53 -06001011 for (ii= 0; ii < ioc->req_depth; ii++) {
1012 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
1013 if (!sc)
1014 continue;
1015 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
1016 if (!mf)
1017 continue;
1018 channel = mf->Bus;
1019 id = mf->TargetID;
1020 mptscsih_freeChainBuffers(ioc, ii);
1021 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
1022 if ((unsigned char *)mf != sc->host_scribble)
1023 continue;
1024 scsi_dma_unmap(sc);
1025 sc->result = DID_RESET << 16;
1026 sc->host_scribble = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301027 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
1028 "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, "
1029 "idx=%x\n", ioc->name, channel, id, sc, mf, ii));
Eric Mooree8206382007-09-29 10:16:53 -06001030 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032}
1033
1034/*
1035 * mptscsih_search_running_cmds - Delete any commands associated
1036 * with the specified target and lun. Function called only
1037 * when a lun is disable by mid-layer.
1038 * Do NOT access the referenced scsi_cmnd structure or
1039 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -06001040 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001041 * @hd: Pointer to a SCSI HOST structure
1042 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 *
1044 * Returns: None.
1045 *
1046 * Called from slave_destroy.
1047 */
1048static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001049mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050{
1051 SCSIIORequest_t *mf = NULL;
1052 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001053 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -07001054 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -06001055 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -06001056 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Eric Mooree8206382007-09-29 10:16:53 -06001058 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1059 for (ii = 0; ii < ioc->req_depth; ii++) {
1060 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Eric Mooree80b0022007-09-14 18:49:03 -06001062 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -06001063 if (mf == NULL)
1064 continue;
Eric Moorecc78d302007-06-15 17:27:21 -06001065 /* If the device is a hidden raid component, then its
1066 * expected that the mf->function will be RAID_SCSI_IO
1067 */
1068 if (vdevice->vtarget->tflags &
1069 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
1070 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
1071 continue;
1072
Eric Moore793955f2007-01-29 09:42:20 -07001073 int_to_scsilun(vdevice->lun, &lun);
1074 if ((mf->Bus != vdevice->vtarget->channel) ||
1075 (mf->TargetID != vdevice->vtarget->id) ||
1076 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 continue;
1078
Eric Moore3dc0b032006-07-11 17:32:33 -06001079 if ((unsigned char *)mf != sc->host_scribble)
1080 continue;
Eric Mooree8206382007-09-29 10:16:53 -06001081 ioc->ScsiLookup[ii] = NULL;
1082 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1083 mptscsih_freeChainBuffers(ioc, ii);
1084 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001085 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001086 sc->host_scribble = NULL;
1087 sc->result = DID_NO_CONNECT << 16;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301088 dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device,
1089 MYIOC_s_FMT "completing cmds: fw_channel %d, "
1090 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name,
1091 vdevice->vtarget->channel, vdevice->vtarget->id,
1092 sc, mf, ii));
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001093 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -06001094 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 }
Eric Mooree8206382007-09-29 10:16:53 -06001097 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return;
1099}
1100
1101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1104/*
1105 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1106 * from a SCSI target device.
1107 * @sc: Pointer to scsi_cmnd structure
1108 * @pScsiReply: Pointer to SCSIIOReply_t
1109 * @pScsiReq: Pointer to original SCSI request
1110 *
1111 * This routine periodically reports QUEUE_FULL status returned from a
1112 * SCSI target device. It reports this to the console via kernel
1113 * printk() API call, not more than once every 10 seconds.
1114 */
1115static void
1116mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1117{
1118 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001120 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001122 if (sc->device == NULL)
1123 return;
1124 if (sc->device->host == NULL)
1125 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001126 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001127 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001128 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001129 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001130 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1131 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001132 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
1136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1137/*
1138 * mptscsih_remove - Removed scsi devices
1139 * @pdev: Pointer to pci_dev structure
1140 *
1141 *
1142 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001143void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144mptscsih_remove(struct pci_dev *pdev)
1145{
1146 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1147 struct Scsi_Host *host = ioc->sh;
1148 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001149 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001151 if(!host) {
1152 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156 scsi_remove_host(host);
1157
Eric Mooree7eae9f2007-09-29 10:15:59 -06001158 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001159 return;
1160
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001161 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001163 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Eric Mooree8206382007-09-29 10:16:53 -06001165 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001166 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001167 kfree(ioc->ScsiLookup);
1168 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 }
1170
Eric Mooree80b0022007-09-14 18:49:03 -06001171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001172 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001173 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001174
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001175 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001176
1177 /* NULL the Scsi_Host pointer
1178 */
Eric Mooree80b0022007-09-14 18:49:03 -06001179 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001180
1181 scsi_host_put(host);
1182
1183 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185}
1186
1187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1188/*
1189 * mptscsih_shutdown - reboot notifier
1190 *
1191 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001192void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001193mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
1197#ifdef CONFIG_PM
1198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1199/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001200 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 *
1202 *
1203 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001204int
Pavel Machek8d189f72005-04-16 15:25:28 -07001205mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301207 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1208
1209 scsi_block_requests(ioc->sh);
1210 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001211 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001212 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213}
1214
1215/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1216/*
1217 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1218 *
1219 *
1220 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001221int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222mptscsih_resume(struct pci_dev *pdev)
1223{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301224 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1225 int rc;
1226
1227 rc = mpt_resume(pdev);
1228 scsi_unblock_requests(ioc->sh);
1229 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
1232#endif
1233
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1235/**
1236 * mptscsih_info - Return information about MPT adapter
1237 * @SChost: Pointer to Scsi_Host structure
1238 *
1239 * (linux scsi_host_template.info routine)
1240 *
1241 * Returns pointer to buffer where information was written.
1242 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001243const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244mptscsih_info(struct Scsi_Host *SChost)
1245{
1246 MPT_SCSI_HOST *h;
1247 int size = 0;
1248
Eric Mooree7eae9f2007-09-29 10:15:59 -06001249 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001252 if (h->info_kbuf == NULL)
1253 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1254 return h->info_kbuf;
1255 h->info_kbuf[0] = '\0';
1256
1257 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1258 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001261 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262}
1263
1264struct info_str {
1265 char *buffer;
1266 int length;
1267 int offset;
1268 int pos;
1269};
1270
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001271static void
1272mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
1274 if (info->pos + len > info->length)
1275 len = info->length - info->pos;
1276
1277 if (info->pos + len < info->offset) {
1278 info->pos += len;
1279 return;
1280 }
1281
1282 if (info->pos < info->offset) {
1283 data += (info->offset - info->pos);
1284 len -= (info->offset - info->pos);
1285 }
1286
1287 if (len > 0) {
1288 memcpy(info->buffer + info->pos, data, len);
1289 info->pos += len;
1290 }
1291}
1292
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001293static int
1294mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295{
1296 va_list args;
1297 char buf[81];
1298 int len;
1299
1300 va_start(args, fmt);
1301 len = vsprintf(buf, fmt, args);
1302 va_end(args);
1303
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001304 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 return len;
1306}
1307
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001308static int
1309mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
1311 struct info_str info;
1312
1313 info.buffer = pbuf;
1314 info.length = len;
1315 info.offset = offset;
1316 info.pos = 0;
1317
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001318 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1319 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1320 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1321 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
1323 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1324}
1325
1326/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1327/**
1328 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001329 * @host: scsi host struct
1330 * @buffer: if write, user data; if read, buffer for user
1331 * @start: returns the buffer address
1332 * @offset: if write, 0; if read, the current offset into the buffer from
1333 * the previous read.
1334 * @length: if write, return length;
1335 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 *
1337 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001339int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1341 int length, int func)
1342{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001343 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 MPT_ADAPTER *ioc = hd->ioc;
1345 int size = 0;
1346
1347 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001348 /*
1349 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 */
1351 } else {
1352 if (start)
1353 *start = buffer;
1354
1355 size = mptscsih_host_info(ioc, buffer, offset, length);
1356 }
1357
1358 return size;
1359}
1360
1361/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1362#define ADD_INDEX_LOG(req_ent) do { } while(0)
1363
1364/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1365/**
1366 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1367 * @SCpnt: Pointer to scsi_cmnd structure
1368 * @done: Pointer SCSI mid-layer IO completion function
1369 *
1370 * (linux scsi_host_template.queuecommand routine)
1371 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1372 * from a linux scsi_cmnd request and send it to the IOC.
1373 *
1374 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1375 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001376int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1378{
1379 MPT_SCSI_HOST *hd;
1380 MPT_FRAME_HDR *mf;
1381 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001382 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 u32 datalen;
1384 u32 scsictl;
1385 u32 scsidir;
1386 u32 cmd_len;
1387 int my_idx;
1388 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301389 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Eric Mooree7eae9f2007-09-29 10:15:59 -06001391 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301392 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 SCpnt->scsi_done = done;
1394
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301395 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1396 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301398 if (ioc->taskmgmt_quiesce_io) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301399 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1400 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 return SCSI_MLQUEUE_HOST_BUSY;
1402 }
1403
1404 /*
1405 * Put together a MPT SCSI request...
1406 */
Eric Mooree80b0022007-09-14 18:49:03 -06001407 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301408 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1409 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 return SCSI_MLQUEUE_HOST_BUSY;
1411 }
1412
1413 pScsiReq = (SCSIIORequest_t *) mf;
1414
1415 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1416
1417 ADD_INDEX_LOG(my_idx);
1418
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001419 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 * Seems we may receive a buffer (datalen>0) even when there
1421 * will be no data transfer! GRRRRR...
1422 */
1423 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001424 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1426 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001427 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1429 } else {
1430 datalen = 0;
1431 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1432 }
1433
1434 /* Default to untagged. Once a target structure has been allocated,
1435 * use the Inquiry data to determine if device supports tagged.
1436 */
Eric Moorea69de502007-09-14 18:48:19 -06001437 if (vdevice
1438 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 && (SCpnt->device->tagged_supported)) {
1440 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1441 } else {
1442 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1443 }
1444
1445 /* Use the above information to set up the message frame
1446 */
Eric Moorea69de502007-09-14 18:48:19 -06001447 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1448 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001450 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001451 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1452 else
1453 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 pScsiReq->CDBLength = SCpnt->cmd_len;
1455 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1456 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301457 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001458 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 pScsiReq->Control = cpu_to_le32(scsictl);
1460
1461 /*
1462 * Write SCSI CDB into the message
1463 */
1464 cmd_len = SCpnt->cmd_len;
1465 for (ii=0; ii < cmd_len; ii++)
1466 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1467
1468 for (ii=cmd_len; ii < 16; ii++)
1469 pScsiReq->CDB[ii] = 0;
1470
1471 /* DataLength */
1472 pScsiReq->DataLength = cpu_to_le32(datalen);
1473
1474 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001475 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1477
1478 /* Now add the SG list
1479 * Always have a SGE even if null length.
1480 */
1481 if (datalen == 0) {
1482 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301483 ioc->add_sge((char *)&pScsiReq->SGL,
1484 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 (dma_addr_t) -1);
1486 } else {
1487 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001488 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 goto fail;
1490 }
1491
Eric Moore3dc0b032006-07-11 17:32:33 -06001492 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001493 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Eric Mooree80b0022007-09-14 18:49:03 -06001495 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301496 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1497 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001498 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 return 0;
1500
1501 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001502 mptscsih_freeChainBuffers(ioc, my_idx);
1503 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 return SCSI_MLQUEUE_HOST_BUSY;
1505}
1506
1507/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1508/*
1509 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1510 * with a SCSI IO request
1511 * @hd: Pointer to the MPT_SCSI_HOST instance
1512 * @req_idx: Index of the SCSI IO request frame.
1513 *
1514 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1515 * No return.
1516 */
1517static void
1518mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1519{
1520 MPT_FRAME_HDR *chain;
1521 unsigned long flags;
1522 int chain_idx;
1523 int next;
1524
1525 /* Get the first chain index and reset
1526 * tracker state.
1527 */
1528 chain_idx = ioc->ReqToChain[req_idx];
1529 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1530
1531 while (chain_idx != MPT_HOST_NO_CHAIN) {
1532
1533 /* Save the next chain buffer index */
1534 next = ioc->ChainToChain[chain_idx];
1535
1536 /* Free this chain buffer and reset
1537 * tracker
1538 */
1539 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1540
1541 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1542 + (chain_idx * ioc->req_sz));
1543
1544 spin_lock_irqsave(&ioc->FreeQlock, flags);
1545 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1546 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1547
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301548 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 ioc->name, chain_idx));
1550
1551 /* handle next */
1552 chain_idx = next;
1553 }
1554 return;
1555}
1556
1557/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1558/*
1559 * Reset Handling
1560 */
1561
1562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001563/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1565 * @hd: Pointer to MPT_SCSI_HOST structure
1566 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001567 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001568 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 * @lun: Logical Unit for reset (if appropriate)
1570 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001571 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 *
1573 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1574 * or a non-interrupt thread. In the former, must not call schedule().
1575 *
1576 * Not all fields are meaningfull for all task types.
1577 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001578 * Returns 0 for SUCCESS, or FAILED.
1579 *
1580 **/
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301581int
1582mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
1583 int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
1585 MPT_FRAME_HDR *mf;
1586 SCSITaskMgmt_t *pScsiTm;
1587 int ii;
1588 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001589 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301590 unsigned long timeleft;
1591 u8 issue_hard_reset;
1592 u32 ioc_raw_state;
1593 unsigned long time_count;
1594
1595 issue_hard_reset = 0;
1596 ioc_raw_state = mpt_GetIocState(ioc, 0);
1597
1598 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1599 printk(MYIOC_s_WARN_FMT
1600 "TaskMgmt type=%x: IOC Not operational (0x%x)!\n",
1601 ioc->name, type, ioc_raw_state);
1602 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
1603 ioc->name, __func__);
1604 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
1605 printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset "
1606 "FAILED!!\n", ioc->name);
1607 return 0;
1608 }
1609
1610 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1611 printk(MYIOC_s_WARN_FMT
1612 "TaskMgmt type=%x: ioc_state: "
1613 "DOORBELL_ACTIVE (0x%x)!\n",
1614 ioc->name, type, ioc_raw_state);
1615 return FAILED;
1616 }
1617
1618 mutex_lock(&ioc->taskmgmt_cmds.mutex);
1619 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
1620 mf = NULL;
1621 retval = FAILED;
1622 goto out;
1623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
1625 /* Return Fail to calling function if no message frames available.
1626 */
Eric Mooree80b0022007-09-14 18:49:03 -06001627 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301628 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1629 "TaskMgmt no msg frames!!\n", ioc->name));
1630 retval = FAILED;
1631 mpt_clear_taskmgmt_in_progress_flag(ioc);
1632 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301634 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001635 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637 /* Format the Request
1638 */
1639 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001640 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 pScsiTm->Bus = channel;
1642 pScsiTm->ChainOffset = 0;
1643 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1644
1645 pScsiTm->Reserved = 0;
1646 pScsiTm->TaskType = type;
1647 pScsiTm->Reserved1 = 0;
1648 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1649 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1650
Eric Moore793955f2007-01-29 09:42:20 -07001651 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
1653 for (ii=0; ii < 7; ii++)
1654 pScsiTm->Reserved2[ii] = 0;
1655
1656 pScsiTm->TaskMsgContext = ctx2abort;
1657
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301658 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) "
1659 "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort,
1660 type, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301662 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301664 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1665 time_count = jiffies;
Eric Mooree80b0022007-09-14 18:49:03 -06001666 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1667 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1668 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301669 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001670 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301671 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1672 if (retval) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301673 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1674 "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n",
1675 ioc->name, mf, retval));
1676 mpt_free_msg_frame(ioc, mf);
1677 mpt_clear_taskmgmt_in_progress_flag(ioc);
1678 goto out;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301682 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
1683 timeout*HZ);
1684 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
1685 retval = FAILED;
1686 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
1687 "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf));
1688 mpt_clear_taskmgmt_in_progress_flag(ioc);
1689 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
1690 goto out;
1691 issue_hard_reset = 1;
1692 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 }
1694
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301695 retval = mptscsih_taskmgmt_reply(ioc, type,
1696 (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply);
Eric Moorecd2c6192007-01-29 09:47:47 -07001697
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301698 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1699 "TaskMgmt completed (%d seconds)\n",
1700 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000));
1701
1702 out:
1703
1704 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
1705 if (issue_hard_reset) {
1706 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
1707 ioc->name, __func__);
1708 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1709 mpt_free_msg_frame(ioc, mf);
1710 }
1711
1712 retval = (retval == 0) ? 0 : FAILED;
1713 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 return retval;
1715}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301716EXPORT_SYMBOL(mptscsih_IssueTaskMgmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001718static int
1719mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1720{
1721 switch (ioc->bus_type) {
1722 case FC:
1723 return 40;
1724 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001725 case SPI:
1726 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001727 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001728 }
1729}
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1732/**
1733 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1734 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1735 *
1736 * (linux scsi_host_template.eh_abort_handler routine)
1737 *
1738 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001739 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001740int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741mptscsih_abort(struct scsi_cmnd * SCpnt)
1742{
1743 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 MPT_FRAME_HDR *mf;
1745 u32 ctx2abort;
1746 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001747 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001748 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001749 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001750 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 /* If we can't locate our host adapter structure, return FAILED status.
1753 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001754 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 SCpnt->result = DID_RESET << 16;
1756 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001757 printk(KERN_ERR MYNAM ": task abort: "
1758 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 return FAILED;
1760 }
1761
Eric Moore958d4a32007-06-15 17:24:14 -06001762 ioc = hd->ioc;
1763 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1764 ioc->name, SCpnt);
1765 scsi_print_command(SCpnt);
1766
1767 vdevice = SCpnt->device->hostdata;
1768 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001769 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1770 "task abort: device has been deleted (sc=%p)\n",
1771 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001772 SCpnt->result = DID_NO_CONNECT << 16;
1773 SCpnt->scsi_done(SCpnt);
1774 retval = 0;
1775 goto out;
1776 }
1777
Eric Moorecc78d302007-06-15 17:27:21 -06001778 /* Task aborts are not supported for hidden raid components.
1779 */
1780 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001781 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1782 "task abort: hidden raid component (sc=%p)\n",
1783 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001784 SCpnt->result = DID_RESET << 16;
1785 retval = FAILED;
1786 goto out;
1787 }
1788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 /* Find this command
1790 */
Eric Mooree8206382007-09-29 10:16:53 -06001791 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001792 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 * Do OS callback.
1794 */
1795 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001796 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001797 "Command not in the active list! (sc=%p)\n", ioc->name,
1798 SCpnt));
Kashyap, Desai9858ae32010-01-25 16:20:52 +05301799 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001800 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 }
1802
Kashyap, Desai2f187862009-05-29 16:52:37 +05301803 if (ioc->timeouts < -1)
1804 ioc->timeouts++;
Moore, Eric65207fe2006-04-21 16:14:35 -06001805
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301806 if (mpt_fwfault_debug)
1807 mpt_halt_firmware(ioc);
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1810 * (the IO to be ABORT'd)
1811 *
1812 * NOTE: Since we do not byteswap MsgContext, we do not
1813 * swap it here either. It is an opaque cookie to
1814 * the controller, so it does not matter. -DaveM
1815 */
Eric Mooree80b0022007-09-14 18:49:03 -06001816 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301818 retval = mptscsih_IssueTaskMgmt(hd,
1819 MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
1820 vdevice->vtarget->channel,
1821 vdevice->vtarget->id, vdevice->lun,
1822 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
Eric Mooree8206382007-09-29 10:16:53 -06001824 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05301825 SCpnt->serial_number == sn) {
1826 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1827 "task abort: command still in active list! (sc=%p)\n",
1828 ioc->name, SCpnt));
Eric Moore3dc0b032006-07-11 17:32:33 -06001829 retval = FAILED;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301830 } else {
1831 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1832 "task abort: command cleared from active list! (sc=%p)\n",
1833 ioc->name, SCpnt));
1834 retval = SUCCESS;
1835 }
Eric Moore3dc0b032006-07-11 17:32:33 -06001836
Eric Moore958d4a32007-06-15 17:24:14 -06001837 out:
1838 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
Kashyap, Desai2f187862009-05-29 16:52:37 +05301839 ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
Kashyap, Desai2f187862009-05-29 16:52:37 +05301841 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842}
1843
1844/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1845/**
1846 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1847 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1848 *
1849 * (linux scsi_host_template.eh_dev_reset_handler routine)
1850 *
1851 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001852 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001853int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1855{
1856 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001857 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001858 VirtDevice *vdevice;
1859 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861 /* If we can't locate our host adapter structure, return FAILED status.
1862 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001863 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001864 printk(KERN_ERR MYNAM ": target reset: "
1865 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 return FAILED;
1867 }
1868
Eric Moore958d4a32007-06-15 17:24:14 -06001869 ioc = hd->ioc;
1870 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1871 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001872 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
Eric Moore958d4a32007-06-15 17:24:14 -06001874 vdevice = SCpnt->device->hostdata;
1875 if (!vdevice || !vdevice->vtarget) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05301876 retval = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001877 goto out;
1878 }
1879
Eric Moorecc78d302007-06-15 17:27:21 -06001880 /* Target reset to hidden raid component is not supported
1881 */
1882 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1883 retval = FAILED;
1884 goto out;
1885 }
1886
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301887 retval = mptscsih_IssueTaskMgmt(hd,
1888 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1889 vdevice->vtarget->channel,
1890 vdevice->vtarget->id, 0, 0,
1891 mptscsih_get_tm_timeout(ioc));
Eric Moore958d4a32007-06-15 17:24:14 -06001892
1893 out:
1894 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1895 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001896
1897 if (retval == 0)
1898 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001899 else
1900 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901}
1902
Eric Moorecd2c6192007-01-29 09:47:47 -07001903
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1905/**
1906 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1907 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1908 *
1909 * (linux scsi_host_template.eh_bus_reset_handler routine)
1910 *
1911 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001912 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001913int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1915{
1916 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001917 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001918 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001919 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
1921 /* If we can't locate our host adapter structure, return FAILED status.
1922 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001923 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001924 printk(KERN_ERR MYNAM ": bus reset: "
1925 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 return FAILED;
1927 }
1928
Eric Moore958d4a32007-06-15 17:24:14 -06001929 ioc = hd->ioc;
1930 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1931 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001932 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
Kashyap, Desai2f187862009-05-29 16:52:37 +05301934 if (ioc->timeouts < -1)
1935 ioc->timeouts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
Eric Moorea69de502007-09-14 18:48:19 -06001937 vdevice = SCpnt->device->hostdata;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301938 if (!vdevice || !vdevice->vtarget)
1939 return SUCCESS;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301940 retval = mptscsih_IssueTaskMgmt(hd,
1941 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1942 vdevice->vtarget->channel, 0, 0, 0,
1943 mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Eric Moore958d4a32007-06-15 17:24:14 -06001945 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1946 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001947
1948 if (retval == 0)
1949 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001950 else
1951 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952}
1953
1954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1955/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001956 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1958 *
1959 * (linux scsi_host_template.eh_host_reset_handler routine)
1960 *
1961 * Returns SUCCESS or FAILED.
1962 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001963int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1965{
1966 MPT_SCSI_HOST * hd;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301967 int status = SUCCESS;
Eric Moore958d4a32007-06-15 17:24:14 -06001968 MPT_ADAPTER *ioc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301969 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001972 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001973 printk(KERN_ERR MYNAM ": host reset: "
1974 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 return FAILED;
1976 }
1977
James Bottomleya6da74c2008-12-15 14:13:27 -06001978 /* make sure we have no outstanding commands at this stage */
1979 mptscsih_flush_running_cmds(hd);
1980
Eric Moore958d4a32007-06-15 17:24:14 -06001981 ioc = hd->ioc;
1982 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1983 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985 /* If our attempts to reset the host failed, then return a failed
1986 * status. The host will be taken off line by the SCSI mid-layer.
1987 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05301988 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1989 if (retval < 0)
1990 status = FAILED;
1991 else
1992 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Eric Moore958d4a32007-06-15 17:24:14 -06001994 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1995 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Kashyap, Desai2f187862009-05-29 16:52:37 +05301997 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998}
1999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000static int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302001mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type,
2002 SCSITaskMgmtReply_t *pScsiTmReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302004 u16 iocstatus;
2005 u32 termination_count;
2006 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302008 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
2009 retval = FAILED;
2010 goto out;
2011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302013 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302015 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2016 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302018 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2019 "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n"
2020 "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n"
2021 "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus,
2022 pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus),
2023 le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode,
2024 termination_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302026 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2027 pScsiTmReply->ResponseCode)
2028 mptscsih_taskmgmt_response_code(ioc,
2029 pScsiTmReply->ResponseCode);
2030
2031 if (iocstatus == MPI_IOCSTATUS_SUCCESS) {
2032 retval = 0;
2033 goto out;
2034 }
2035
2036 retval = FAILED;
2037 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
2038 if (termination_count == 1)
2039 retval = 0;
2040 goto out;
2041 }
2042
2043 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
2044 iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
2045 retval = 0;
2046
2047 out:
2048 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049}
2050
2051/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302052void
Moore, Eric9f63bb72006-01-16 18:53:26 -07002053mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2054{
2055 char *desc;
2056
2057 switch (response_code) {
2058 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2059 desc = "The task completed.";
2060 break;
2061 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2062 desc = "The IOC received an invalid frame status.";
2063 break;
2064 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2065 desc = "The task type is not supported.";
2066 break;
2067 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2068 desc = "The requested task failed.";
2069 break;
2070 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2071 desc = "The task completed successfully.";
2072 break;
2073 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2074 desc = "The LUN request is invalid.";
2075 break;
2076 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2077 desc = "The task is in the IOC queue and has not been sent to target.";
2078 break;
2079 default:
2080 desc = "unknown";
2081 break;
2082 }
2083 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2084 ioc->name, response_code, desc);
2085}
Kashyap, Desaie7deff32009-05-29 16:46:07 +05302086EXPORT_SYMBOL(mptscsih_taskmgmt_response_code);
Moore, Eric9f63bb72006-01-16 18:53:26 -07002087
2088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089/**
2090 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2091 * @ioc: Pointer to MPT_ADAPTER structure
2092 * @mf: Pointer to SCSI task mgmt request frame
2093 * @mr: Pointer to SCSI task mgmt reply frame
2094 *
2095 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2096 * of any SCSI task management request.
2097 * This routine is registered with the MPT (base) driver at driver
2098 * load/init time via the mpt_register() API call.
2099 *
2100 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002101 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002102int
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302103mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
2104 MPT_FRAME_HDR *mr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105{
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302106 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2107 "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302109 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302111 if (!mr)
Eric Moorecd2c6192007-01-29 09:47:47 -07002112 goto out;
Eric Moorecd2c6192007-01-29 09:47:47 -07002113
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302114 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2115 memcpy(ioc->taskmgmt_cmds.reply, mr,
2116 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
Eric Moorecd2c6192007-01-29 09:47:47 -07002117 out:
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302118 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
2119 mpt_clear_taskmgmt_in_progress_flag(ioc);
2120 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2121 complete(&ioc->taskmgmt_cmds.done);
2122 return 1;
2123 }
2124 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125}
2126
2127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2128/*
2129 * This is anyones guess quite frankly.
2130 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002131int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2133 sector_t capacity, int geom[])
2134{
2135 int heads;
2136 int sectors;
2137 sector_t cylinders;
2138 ulong dummy;
2139
2140 heads = 64;
2141 sectors = 32;
2142
2143 dummy = heads * sectors;
2144 cylinders = capacity;
2145 sector_div(cylinders,dummy);
2146
2147 /*
2148 * Handle extended translation size for logical drives
2149 * > 1Gb
2150 */
2151 if ((ulong)capacity >= 0x200000) {
2152 heads = 255;
2153 sectors = 63;
2154 dummy = heads * sectors;
2155 cylinders = capacity;
2156 sector_div(cylinders,dummy);
2157 }
2158
2159 /* return result */
2160 geom[0] = heads;
2161 geom[1] = sectors;
2162 geom[2] = cylinders;
2163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 return 0;
2165}
2166
Moore, Ericf44e5462006-03-14 09:14:21 -07002167/* Search IOC page 3 to determine if this is hidden physical disk
2168 *
2169 */
2170int
Eric Moore793955f2007-01-29 09:42:20 -07002171mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002172{
Eric Mooreb506ade2007-01-29 09:45:37 -07002173 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302174 int i, j;
2175 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002176 int rc = 0;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302177 int num_paths;
Moore, Ericf44e5462006-03-14 09:14:21 -07002178
Eric Moore793955f2007-01-29 09:42:20 -07002179 if (!ioc->raid_data.pIocPg3)
2180 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002181 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002182 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2183 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2184 rc = 1;
2185 goto out;
2186 }
2187 }
2188
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302189 if (ioc->bus_type != SAS)
2190 goto out;
2191
2192 /*
2193 * Check if dual path
2194 */
2195 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2196 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2197 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2198 if (num_paths < 2)
2199 continue;
2200 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2201 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2202 if (!phys_disk)
2203 continue;
2204 if ((mpt_raid_phys_disk_pg1(ioc,
2205 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2206 phys_disk))) {
2207 kfree(phys_disk);
2208 continue;
2209 }
2210 for (j = 0; j < num_paths; j++) {
2211 if ((phys_disk->Path[j].Flags &
2212 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2213 continue;
2214 if ((phys_disk->Path[j].Flags &
2215 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2216 continue;
2217 if ((id == phys_disk->Path[j].PhysDiskID) &&
2218 (channel == phys_disk->Path[j].PhysDiskBus)) {
2219 rc = 1;
2220 kfree(phys_disk);
2221 goto out;
2222 }
2223 }
2224 kfree(phys_disk);
2225 }
2226
2227
Eric Mooreb506ade2007-01-29 09:45:37 -07002228 /*
2229 * Check inactive list for matching phys disks
2230 */
2231 if (list_empty(&ioc->raid_data.inactive_list))
2232 goto out;
2233
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002234 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002235 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2236 list) {
2237 if ((component_info->d.PhysDiskID == id) &&
2238 (component_info->d.PhysDiskBus == channel))
2239 rc = 1;
2240 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002241 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002242
Eric Moore793955f2007-01-29 09:42:20 -07002243 out:
2244 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002245}
2246EXPORT_SYMBOL(mptscsih_is_phys_disk);
2247
Eric Moore793955f2007-01-29 09:42:20 -07002248u8
2249mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002250{
Eric Mooreb506ade2007-01-29 09:45:37 -07002251 struct inactive_raid_component_info *component_info;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302252 int i, j;
2253 RaidPhysDiskPage1_t *phys_disk;
Eric Moore793955f2007-01-29 09:42:20 -07002254 int rc = -ENXIO;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302255 int num_paths;
James Bottomleyc92f2222006-03-01 09:02:49 -06002256
Eric Moore793955f2007-01-29 09:42:20 -07002257 if (!ioc->raid_data.pIocPg3)
2258 goto out;
2259 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2260 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2261 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2262 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2263 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002264 }
2265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Kashyap, Desaia7938b02009-05-29 16:53:56 +05302267 if (ioc->bus_type != SAS)
2268 goto out;
2269
2270 /*
2271 * Check if dual path
2272 */
2273 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2274 num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
2275 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
2276 if (num_paths < 2)
2277 continue;
2278 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
2279 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
2280 if (!phys_disk)
2281 continue;
2282 if ((mpt_raid_phys_disk_pg1(ioc,
2283 ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
2284 phys_disk))) {
2285 kfree(phys_disk);
2286 continue;
2287 }
2288 for (j = 0; j < num_paths; j++) {
2289 if ((phys_disk->Path[j].Flags &
2290 MPI_RAID_PHYSDISK1_FLAG_INVALID))
2291 continue;
2292 if ((phys_disk->Path[j].Flags &
2293 MPI_RAID_PHYSDISK1_FLAG_BROKEN))
2294 continue;
2295 if ((id == phys_disk->Path[j].PhysDiskID) &&
2296 (channel == phys_disk->Path[j].PhysDiskBus)) {
2297 rc = phys_disk->PhysDiskNum;
2298 kfree(phys_disk);
2299 goto out;
2300 }
2301 }
2302 kfree(phys_disk);
2303 }
2304
Eric Mooreb506ade2007-01-29 09:45:37 -07002305 /*
2306 * Check inactive list for matching phys disks
2307 */
2308 if (list_empty(&ioc->raid_data.inactive_list))
2309 goto out;
2310
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002311 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002312 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2313 list) {
2314 if ((component_info->d.PhysDiskID == id) &&
2315 (component_info->d.PhysDiskBus == channel))
2316 rc = component_info->d.PhysDiskNum;
2317 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002318 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002319
Eric Moore793955f2007-01-29 09:42:20 -07002320 out:
2321 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002322}
Eric Moore793955f2007-01-29 09:42:20 -07002323EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002324
2325/*
2326 * OS entry point to allow for host driver to free allocated memory
2327 * Called if no device present or device being unloaded
2328 */
2329void
2330mptscsih_slave_destroy(struct scsi_device *sdev)
2331{
2332 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002333 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002334 VirtTarget *vtarget;
2335 VirtDevice *vdevice;
2336 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002338 starget = scsi_target(sdev);
2339 vtarget = starget->hostdata;
2340 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002342 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002343 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002344 mptscsih_synchronize_cache(hd, vdevice);
2345 kfree(vdevice);
2346 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347}
2348
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002349/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2350/*
2351 * mptscsih_change_queue_depth - This function will set a devices queue depth
2352 * @sdev: per scsi_device pointer
2353 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07002354 * @reason: calling context
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002355 *
2356 * Adding support for new 'change_queue_depth' api.
2357*/
2358int
Mike Christiee881a172009-10-15 17:46:39 -07002359mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002361 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002362 VirtTarget *vtarget;
2363 struct scsi_target *starget;
2364 int max_depth;
2365 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002366 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002368 starget = scsi_target(sdev);
2369 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002370
Mike Christiee881a172009-10-15 17:46:39 -07002371 if (reason != SCSI_QDEPTH_DEFAULT)
2372 return -EOPNOTSUPP;
2373
Eric Mooree80b0022007-09-14 18:49:03 -06002374 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002375 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002377 else if (sdev->type == TYPE_DISK &&
2378 vtarget->minSyncFactor <= MPT_ULTRA160)
2379 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2380 else
2381 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 } else
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05302383 max_depth = ioc->sh->can_queue;
2384
2385 if (!sdev->tagged_supported)
2386 max_depth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
2388 if (qdepth > max_depth)
2389 qdepth = max_depth;
2390 if (qdepth == 1)
2391 tagged = 0;
2392 else
2393 tagged = MSG_SIMPLE_TAG;
2394
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002395 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2396 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397}
2398
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399/*
2400 * OS entry point to adjust the queue_depths on a per-device basis.
2401 * Called once per device the bus scan. Use it to force the queue_depth
2402 * member to 1 if a device does not support Q tags.
2403 * Return non-zero if fails.
2404 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002405int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002406mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002408 struct Scsi_Host *sh = sdev->host;
2409 VirtTarget *vtarget;
2410 VirtDevice *vdevice;
2411 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002412 MPT_SCSI_HOST *hd = shost_priv(sh);
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;
2417 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Eric Mooree80b0022007-09-14 18:49:03 -06002419 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002420 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002421 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2422 if (ioc->bus_type == SPI)
2423 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002424 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002425 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002426 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Eric Moore793955f2007-01-29 09:42:20 -07002428 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
Eric Mooree80b0022007-09-14 18:49:03 -06002430 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002432 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Eric Mooree80b0022007-09-14 18:49:03 -06002434 if (ioc->bus_type == SPI)
2435 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002436 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002437 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002438 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Mike Christiee881a172009-10-15 17:46:39 -07002440 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
2441 SCSI_QDEPTH_DEFAULT);
Eric Mooree80b0022007-09-14 18:49:03 -06002442 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002444 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002445 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
2447 return 0;
2448}
2449
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2451/*
2452 * Private routines...
2453 */
2454
2455/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2456/* Utility function to copy sense data from the scsi_cmnd buffer
2457 * to the FC and SCSI target structures.
2458 *
2459 */
2460static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002461mptscsih_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 -07002462{
Eric Moorea69de502007-09-14 18:48:19 -06002463 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 SCSIIORequest_t *pReq;
2465 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002466 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468 /* Get target structure
2469 */
2470 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002471 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473 if (sense_count) {
2474 u8 *sense_data;
2475 int req_index;
2476
2477 /* Copy the sense received into the scsi command block. */
2478 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002479 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2481
2482 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2483 */
Eric Mooree80b0022007-09-14 18:49:03 -06002484 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002485 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002488 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2490 ioc->events[idx].eventContext = ioc->eventContext;
2491
Dave Jones3d9780b2007-05-21 20:59:47 -04002492 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2493 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2494 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
Dave Jones3d9780b2007-05-21 20:59:47 -04002496 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
2498 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002499 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002500 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002501 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002502 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2503 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002504 MPT_TARGET_FLAGS_LED_ON;
2505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507 }
2508 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002509 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2510 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
2512}
2513
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05302514/**
2515 * mptscsih_get_scsi_lookup - retrieves scmd entry
2516 * @ioc: Pointer to MPT_ADAPTER structure
2517 * @i: index into the array
2518 *
2519 * Returns the scsi_cmd pointer
2520 */
2521struct scsi_cmnd *
2522mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2523{
2524 unsigned long flags;
2525 struct scsi_cmnd *scmd;
2526
2527 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2528 scmd = ioc->ScsiLookup[i];
2529 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2530
2531 return scmd;
2532}
2533EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
Eric Mooree8206382007-09-29 10:16:53 -06002534
2535/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00002536 * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
Kashyap, Desai2f187862009-05-29 16:52:37 +05302537 * @ioc: Pointer to MPT_ADAPTER structure
2538 * @i: index into the array
2539 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002540 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302541 *
Eric Mooree8206382007-09-29 10:16:53 -06002542 **/
2543static struct scsi_cmnd *
2544mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2545{
2546 unsigned long flags;
2547 struct scsi_cmnd *scmd;
2548
2549 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2550 scmd = ioc->ScsiLookup[i];
2551 ioc->ScsiLookup[i] = NULL;
2552 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2553
2554 return scmd;
2555}
2556
2557/**
2558 * mptscsih_set_scsi_lookup
2559 *
2560 * writes a scmd entry into the ScsiLookup[] array list
2561 *
2562 * @ioc: Pointer to MPT_ADAPTER structure
2563 * @i: index into the array
2564 * @scmd: scsi_cmnd pointer
2565 *
2566 **/
2567static void
2568mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2569{
2570 unsigned long flags;
2571
2572 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2573 ioc->ScsiLookup[i] = scmd;
2574 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2575}
2576
2577/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002578 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002579 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002580 * @sc: scsi_cmnd pointer
2581 */
Eric Mooree8206382007-09-29 10:16:53 -06002582static int
2583SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2584{
2585 unsigned long flags;
2586 int i, index=-1;
2587
2588 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2589 for (i = 0; i < ioc->req_depth; i++) {
2590 if (ioc->ScsiLookup[i] == sc) {
2591 index = i;
2592 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
2594 }
2595
Eric Mooree8206382007-09-29 10:16:53 -06002596 out:
2597 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2598 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599}
2600
2601/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002602int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2604{
2605 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Eric Mooree7eae9f2007-09-29 10:15:59 -06002607 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302610 hd = shost_priv(ioc->sh);
2611 switch (reset_phase) {
2612 case MPT_IOC_SETUP_RESET:
2613 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2614 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302615 break;
2616 case MPT_IOC_PRE_RESET:
2617 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2618 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302619 mptscsih_flush_running_cmds(hd);
2620 break;
2621 case MPT_IOC_POST_RESET:
2622 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2623 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2624 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2625 ioc->internal_cmds.status |=
2626 MPT_MGMT_STATUS_DID_IOCRESET;
2627 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302629 break;
2630 default:
2631 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return 1; /* currently means nothing really */
2634}
2635
2636/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002637int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2639{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2641
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302642 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2643 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2644 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
Kashyap, Desai2f187862009-05-29 16:52:37 +05302646 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2647 event == MPI_EVENT_EXT_BUS_RESET) &&
2648 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2649 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
2651 return 1; /* currently means nothing really */
2652}
2653
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2655/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 * Bus Scan and Domain Validation functionality ...
2657 */
2658
2659/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2660/*
2661 * mptscsih_scandv_complete - Scan and DV callback routine registered
2662 * to Fustion MPT (base) driver.
2663 *
2664 * @ioc: Pointer to MPT_ADAPTER structure
2665 * @mf: Pointer to original MPT request frame
2666 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2667 *
2668 * This routine is called from mpt.c::mpt_interrupt() at the completion
2669 * of any SCSI IO request.
2670 * This routine is registered with the Fusion MPT (base) driver at driver
2671 * load/init time via the mpt_register() API call.
2672 *
2673 * Returns 1 indicating alloc'd request frame ptr should be freed.
2674 *
2675 * Remark: Sets a completion code and (possibly) saves sense data
2676 * in the IOC member localReply structure.
2677 * Used ONLY for DV and other internal commands.
2678 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002679int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302680mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2681 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302684 SCSIIOReply_t *pReply;
2685 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302687 u8 *sense_data;
2688 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302690 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2691 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2692 if (!reply)
2693 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002694
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302695 pReply = (SCSIIOReply_t *) reply;
2696 pReq = (SCSIIORequest_t *) req;
2697 ioc->internal_cmds.completion_code =
2698 mptscsih_get_completion_code(ioc, req, reply);
2699 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2700 memcpy(ioc->internal_cmds.reply, reply,
2701 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2702 cmd = reply->u.hdr.Function;
2703 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2704 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2705 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2706 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2707 sense_data = ((u8 *)ioc->sense_buf_pool +
2708 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2709 sz = min_t(int, pReq->SenseBufferLength,
2710 MPT_SENSE_BUFFER_ALLOC);
2711 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302713 out:
2714 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2715 return 0;
2716 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2717 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return 1;
2719}
2720
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302722/**
2723 * mptscsih_get_completion_code -
2724 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap9cf46a32009-06-13 19:37:18 -07002725 * @req: Pointer to original MPT request frame
2726 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302727 *
2728 **/
2729static int
2730mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2731 MPT_FRAME_HDR *reply)
2732{
2733 SCSIIOReply_t *pReply;
2734 MpiRaidActionReply_t *pr;
2735 u8 scsi_status;
2736 u16 status;
2737 int completion_code;
2738
2739 pReply = (SCSIIOReply_t *)reply;
2740 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2741 scsi_status = pReply->SCSIStatus;
2742
2743 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2744 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2745 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2746 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2747
2748 switch (status) {
2749
2750 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2751 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2752 break;
2753
2754 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2755 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2756 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2757 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2758 completion_code = MPT_SCANDV_DID_RESET;
2759 break;
2760
2761 case MPI_IOCSTATUS_BUSY:
2762 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2763 completion_code = MPT_SCANDV_BUSY;
2764 break;
2765
2766 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2767 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2768 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2769 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2770 completion_code = MPT_SCANDV_GOOD;
2771 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2772 pr = (MpiRaidActionReply_t *)reply;
2773 if (le16_to_cpu(pr->ActionStatus) ==
2774 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2775 completion_code = MPT_SCANDV_GOOD;
2776 else
2777 completion_code = MPT_SCANDV_SOME_ERROR;
2778 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2779 completion_code = MPT_SCANDV_SENSE;
2780 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2781 if (req->u.scsireq.CDB[0] == INQUIRY)
2782 completion_code = MPT_SCANDV_ISSUE_SENSE;
2783 else
2784 completion_code = MPT_SCANDV_DID_RESET;
2785 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2786 completion_code = MPT_SCANDV_DID_RESET;
2787 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2788 completion_code = MPT_SCANDV_DID_RESET;
2789 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2790 completion_code = MPT_SCANDV_BUSY;
2791 else
2792 completion_code = MPT_SCANDV_GOOD;
2793 break;
2794
2795 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2796 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2797 completion_code = MPT_SCANDV_DID_RESET;
2798 else
2799 completion_code = MPT_SCANDV_SOME_ERROR;
2800 break;
2801 default:
2802 completion_code = MPT_SCANDV_SOME_ERROR;
2803 break;
2804
2805 } /* switch(status) */
2806
2807 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2808 " completionCode set to %08xh\n", ioc->name, completion_code));
2809 return completion_code;
2810}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
2812/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2813/**
2814 * mptscsih_do_cmd - Do internal command.
2815 * @hd: MPT_SCSI_HOST pointer
2816 * @io: INTERNAL_CMD pointer.
2817 *
2818 * Issue the specified internally generated command and do command
2819 * specific cleanup. For bus scan / DV only.
2820 * NOTES: If command is Inquiry and status is good,
2821 * initialize a target structure, save the data
2822 *
2823 * Remark: Single threaded access only.
2824 *
2825 * Return:
2826 * < 0 if an illegal command or no resources
2827 *
2828 * 0 if good
2829 *
2830 * > 0 if command complete but some type of completion error.
2831 */
2832static int
2833mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2834{
2835 MPT_FRAME_HDR *mf;
2836 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302838 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 char cmdLen;
2840 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 +05302841 u8 cmd = io->cmd;
2842 MPT_ADAPTER *ioc = hd->ioc;
2843 int ret = 0;
2844 unsigned long timeleft;
2845 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302847 /* don't send internal command during diag reset */
2848 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2849 if (ioc->ioc_reset_in_progress) {
2850 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2851 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2852 "%s: busy with host reset\n", ioc->name, __func__));
2853 return MPT_SCANDV_BUSY;
2854 }
2855 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2856
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302857 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859 /* Set command specific information
2860 */
2861 switch (cmd) {
2862 case INQUIRY:
2863 cmdLen = 6;
2864 dir = MPI_SCSIIO_CONTROL_READ;
2865 CDB[0] = cmd;
2866 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302867 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 break;
2869
2870 case TEST_UNIT_READY:
2871 cmdLen = 6;
2872 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302873 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 break;
2875
2876 case START_STOP:
2877 cmdLen = 6;
2878 dir = MPI_SCSIIO_CONTROL_READ;
2879 CDB[0] = cmd;
2880 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302881 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 break;
2883
2884 case REQUEST_SENSE:
2885 cmdLen = 6;
2886 CDB[0] = cmd;
2887 CDB[4] = io->size;
2888 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302889 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 break;
2891
2892 case READ_BUFFER:
2893 cmdLen = 10;
2894 dir = MPI_SCSIIO_CONTROL_READ;
2895 CDB[0] = cmd;
2896 if (io->flags & MPT_ICFLAG_ECHO) {
2897 CDB[1] = 0x0A;
2898 } else {
2899 CDB[1] = 0x02;
2900 }
2901
2902 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2903 CDB[1] |= 0x01;
2904 }
2905 CDB[6] = (io->size >> 16) & 0xFF;
2906 CDB[7] = (io->size >> 8) & 0xFF;
2907 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302908 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 break;
2910
2911 case WRITE_BUFFER:
2912 cmdLen = 10;
2913 dir = MPI_SCSIIO_CONTROL_WRITE;
2914 CDB[0] = cmd;
2915 if (io->flags & MPT_ICFLAG_ECHO) {
2916 CDB[1] = 0x0A;
2917 } else {
2918 CDB[1] = 0x02;
2919 }
2920 CDB[6] = (io->size >> 16) & 0xFF;
2921 CDB[7] = (io->size >> 8) & 0xFF;
2922 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302923 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 break;
2925
2926 case RESERVE:
2927 cmdLen = 6;
2928 dir = MPI_SCSIIO_CONTROL_READ;
2929 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302930 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 break;
2932
2933 case RELEASE:
2934 cmdLen = 6;
2935 dir = MPI_SCSIIO_CONTROL_READ;
2936 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302937 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 break;
2939
2940 case SYNCHRONIZE_CACHE:
2941 cmdLen = 10;
2942 dir = MPI_SCSIIO_CONTROL_READ;
2943 CDB[0] = cmd;
2944// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302945 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 break;
2947
2948 default:
2949 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302950 ret = -EFAULT;
2951 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 }
2953
2954 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302955 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 */
Eric Mooree80b0022007-09-14 18:49:03 -06002957 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302958 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2959 ioc->name, __func__));
2960 ret = MPT_SCANDV_BUSY;
2961 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 }
2963
2964 pScsiReq = (SCSIIORequest_t *) mf;
2965
2966 /* Get the request index */
2967 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2968 ADD_INDEX_LOG(my_idx); /* for debug */
2969
2970 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2971 pScsiReq->TargetID = io->physDiskNum;
2972 pScsiReq->Bus = 0;
2973 pScsiReq->ChainOffset = 0;
2974 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2975 } else {
2976 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002977 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 pScsiReq->ChainOffset = 0;
2979 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2980 }
2981
2982 pScsiReq->CDBLength = cmdLen;
2983 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2984
2985 pScsiReq->Reserved = 0;
2986
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302987 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 /* MsgContext set in mpt_get_msg_fram call */
2989
Eric Moore793955f2007-01-29 09:42:20 -07002990 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991
2992 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2993 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2994 else
2995 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2996
2997 if (cmd == REQUEST_SENSE) {
2998 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302999 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3000 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 }
3002
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303003 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 pScsiReq->CDB[ii] = CDB[ii];
3005
3006 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003007 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3009
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303010 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3011 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3012 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303014 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303015 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303016 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3017 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303018 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303019 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303021 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003022 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303023 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3024 timeout*HZ);
3025 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3026 ret = MPT_SCANDV_DID_RESET;
3027 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3028 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3029 cmd));
3030 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3031 mpt_free_msg_frame(ioc, mf);
3032 goto out;
3033 }
3034 if (!timeleft) {
3035 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
3036 ioc->name, __func__);
3037 mpt_HardResetHandler(ioc, CAN_SLEEP);
3038 mpt_free_msg_frame(ioc, mf);
3039 }
3040 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 }
3042
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303043 ret = ioc->internal_cmds.completion_code;
3044 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3045 ioc->name, __func__, ret));
3046
3047 out:
3048 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3049 mutex_unlock(&ioc->internal_cmds.mutex);
3050 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051}
3052
3053/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3054/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003055 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3056 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003057 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003058 *
3059 * Uses the ISR, but with special processing.
3060 * MUST be single-threaded.
3061 *
3062 */
3063static void
3064mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3065{
3066 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Eric Moorecc78d302007-06-15 17:27:21 -06003068 /* Ignore hidden raid components, this is handled when the command
3069 * is sent to the volume
3070 */
3071 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3072 return;
3073
3074 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3075 !vdevice->configured_lun)
3076 return;
3077
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 /* Following parameters will not change
3079 * in this routine.
3080 */
3081 iocmd.cmd = SYNCHRONIZE_CACHE;
3082 iocmd.flags = 0;
3083 iocmd.physDiskNum = -1;
3084 iocmd.data = NULL;
3085 iocmd.data_dma = -1;
3086 iocmd.size = 0;
3087 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003088 iocmd.channel = vdevice->vtarget->channel;
3089 iocmd.id = vdevice->vtarget->id;
3090 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Eric Moorecc78d302007-06-15 17:27:21 -06003092 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093}
3094
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303095static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003096mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3097 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303098{
Tony Jonesee959b02008-02-22 00:13:36 +01003099 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003100 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303101 MPT_ADAPTER *ioc = hd->ioc;
3102
3103 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3104 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3105 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3106 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3107 ioc->facts.FWVersion.Word & 0x000000FF);
3108}
Tony Jonesee959b02008-02-22 00:13:36 +01003109static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303110
3111static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003112mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3113 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303114{
Tony Jonesee959b02008-02-22 00:13:36 +01003115 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003116 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303117 MPT_ADAPTER *ioc = hd->ioc;
3118
3119 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3120 (ioc->biosVersion & 0xFF000000) >> 24,
3121 (ioc->biosVersion & 0x00FF0000) >> 16,
3122 (ioc->biosVersion & 0x0000FF00) >> 8,
3123 ioc->biosVersion & 0x000000FF);
3124}
Tony Jonesee959b02008-02-22 00:13:36 +01003125static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303126
3127static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003128mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3129 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303130{
Tony Jonesee959b02008-02-22 00:13:36 +01003131 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003132 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303133 MPT_ADAPTER *ioc = hd->ioc;
3134
3135 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3136}
Tony Jonesee959b02008-02-22 00:13:36 +01003137static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303138
3139static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003140mptscsih_version_product_show(struct device *dev,
3141 struct device_attribute *attr,
3142char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303143{
Tony Jonesee959b02008-02-22 00:13:36 +01003144 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003145 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303146 MPT_ADAPTER *ioc = hd->ioc;
3147
3148 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3149}
Tony Jonesee959b02008-02-22 00:13:36 +01003150static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303151 mptscsih_version_product_show, NULL);
3152
3153static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003154mptscsih_version_nvdata_persistent_show(struct device *dev,
3155 struct device_attribute *attr,
3156 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303157{
Tony Jonesee959b02008-02-22 00:13:36 +01003158 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003159 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303160 MPT_ADAPTER *ioc = hd->ioc;
3161
3162 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3163 ioc->nvdata_version_persistent);
3164}
Tony Jonesee959b02008-02-22 00:13:36 +01003165static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303166 mptscsih_version_nvdata_persistent_show, NULL);
3167
3168static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003169mptscsih_version_nvdata_default_show(struct device *dev,
3170 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303171{
Tony Jonesee959b02008-02-22 00:13:36 +01003172 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003173 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303174 MPT_ADAPTER *ioc = hd->ioc;
3175
3176 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3177}
Tony Jonesee959b02008-02-22 00:13:36 +01003178static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303179 mptscsih_version_nvdata_default_show, NULL);
3180
3181static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003182mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3183 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303184{
Tony Jonesee959b02008-02-22 00:13:36 +01003185 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003186 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303187 MPT_ADAPTER *ioc = hd->ioc;
3188
3189 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3190}
Tony Jonesee959b02008-02-22 00:13:36 +01003191static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303192
3193static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003194mptscsih_board_assembly_show(struct device *dev,
3195 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303196{
Tony Jonesee959b02008-02-22 00:13:36 +01003197 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003198 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303199 MPT_ADAPTER *ioc = hd->ioc;
3200
3201 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3202}
Tony Jonesee959b02008-02-22 00:13:36 +01003203static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303204 mptscsih_board_assembly_show, NULL);
3205
3206static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003207mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3208 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303209{
Tony Jonesee959b02008-02-22 00:13:36 +01003210 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003211 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303212 MPT_ADAPTER *ioc = hd->ioc;
3213
3214 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3215}
Tony Jonesee959b02008-02-22 00:13:36 +01003216static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303217 mptscsih_board_tracer_show, NULL);
3218
3219static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003220mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3221 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303222{
Tony Jonesee959b02008-02-22 00:13:36 +01003223 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003224 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303225 MPT_ADAPTER *ioc = hd->ioc;
3226
3227 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3228}
Tony Jonesee959b02008-02-22 00:13:36 +01003229static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303230 mptscsih_io_delay_show, NULL);
3231
3232static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003233mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3234 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303235{
Tony Jonesee959b02008-02-22 00:13:36 +01003236 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003237 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303238 MPT_ADAPTER *ioc = hd->ioc;
3239
3240 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3241}
Tony Jonesee959b02008-02-22 00:13:36 +01003242static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303243 mptscsih_device_delay_show, NULL);
3244
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303245static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003246mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3247 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303248{
Tony Jonesee959b02008-02-22 00:13:36 +01003249 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003250 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303251 MPT_ADAPTER *ioc = hd->ioc;
3252
3253 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3254}
3255static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003256mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3257 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303258{
Tony Jonesee959b02008-02-22 00:13:36 +01003259 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003260 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303261 MPT_ADAPTER *ioc = hd->ioc;
3262 int val = 0;
3263
3264 if (sscanf(buf, "%x", &val) != 1)
3265 return -EINVAL;
3266
3267 ioc->debug_level = val;
3268 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3269 ioc->name, ioc->debug_level);
3270 return strlen(buf);
3271}
Tony Jonesee959b02008-02-22 00:13:36 +01003272static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3273 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303274
Tony Jonesee959b02008-02-22 00:13:36 +01003275struct device_attribute *mptscsih_host_attrs[] = {
3276 &dev_attr_version_fw,
3277 &dev_attr_version_bios,
3278 &dev_attr_version_mpi,
3279 &dev_attr_version_product,
3280 &dev_attr_version_nvdata_persistent,
3281 &dev_attr_version_nvdata_default,
3282 &dev_attr_board_name,
3283 &dev_attr_board_assembly,
3284 &dev_attr_board_tracer,
3285 &dev_attr_io_delay,
3286 &dev_attr_device_delay,
3287 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303288 NULL,
3289};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303290
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303291EXPORT_SYMBOL(mptscsih_host_attrs);
3292
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003293EXPORT_SYMBOL(mptscsih_remove);
3294EXPORT_SYMBOL(mptscsih_shutdown);
3295#ifdef CONFIG_PM
3296EXPORT_SYMBOL(mptscsih_suspend);
3297EXPORT_SYMBOL(mptscsih_resume);
3298#endif
3299EXPORT_SYMBOL(mptscsih_proc_info);
3300EXPORT_SYMBOL(mptscsih_info);
3301EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003302EXPORT_SYMBOL(mptscsih_slave_destroy);
3303EXPORT_SYMBOL(mptscsih_slave_configure);
3304EXPORT_SYMBOL(mptscsih_abort);
3305EXPORT_SYMBOL(mptscsih_dev_reset);
3306EXPORT_SYMBOL(mptscsih_bus_reset);
3307EXPORT_SYMBOL(mptscsih_host_reset);
3308EXPORT_SYMBOL(mptscsih_bios_param);
3309EXPORT_SYMBOL(mptscsih_io_done);
3310EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3311EXPORT_SYMBOL(mptscsih_scandv_complete);
3312EXPORT_SYMBOL(mptscsih_event_process);
3313EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003314EXPORT_SYMBOL(mptscsih_change_queue_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003316/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/