blob: f68ec48a881e1fb6cf32c58456886f227d807668 [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));
1799 retval = 0;
1800 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
2354 *
2355 * Adding support for new 'change_queue_depth' api.
2356*/
2357int
2358mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002360 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002361 VirtTarget *vtarget;
2362 struct scsi_target *starget;
2363 int max_depth;
2364 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002365 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002367 starget = scsi_target(sdev);
2368 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002369
Eric Mooree80b0022007-09-14 18:49:03 -06002370 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002371 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002373 else if (sdev->type == TYPE_DISK &&
2374 vtarget->minSyncFactor <= MPT_ULTRA160)
2375 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2376 else
2377 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 } else
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05302379 max_depth = ioc->sh->can_queue;
2380
2381 if (!sdev->tagged_supported)
2382 max_depth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
2384 if (qdepth > max_depth)
2385 qdepth = max_depth;
2386 if (qdepth == 1)
2387 tagged = 0;
2388 else
2389 tagged = MSG_SIMPLE_TAG;
2390
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002391 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2392 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393}
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395/*
2396 * OS entry point to adjust the queue_depths on a per-device basis.
2397 * Called once per device the bus scan. Use it to force the queue_depth
2398 * member to 1 if a device does not support Q tags.
2399 * Return non-zero if fails.
2400 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002401int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002402mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002404 struct Scsi_Host *sh = sdev->host;
2405 VirtTarget *vtarget;
2406 VirtDevice *vdevice;
2407 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002408 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002409 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 starget = scsi_target(sdev);
2412 vtarget = starget->hostdata;
2413 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
Eric Mooree80b0022007-09-14 18:49:03 -06002415 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002416 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002417 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2418 if (ioc->bus_type == SPI)
2419 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002420 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002421 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002422 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
Eric Moore793955f2007-01-29 09:42:20 -07002424 vdevice->configured_lun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
Eric Mooree80b0022007-09-14 18:49:03 -06002426 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002428 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
Eric Mooree80b0022007-09-14 18:49:03 -06002430 if (ioc->bus_type == SPI)
2431 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002432 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002433 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002434 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Kashyap, Desai2f187862009-05-29 16:52:37 +05302436 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Eric Mooree80b0022007-09-14 18:49:03 -06002437 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002439 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002440 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442 return 0;
2443}
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2446/*
2447 * Private routines...
2448 */
2449
2450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2451/* Utility function to copy sense data from the scsi_cmnd buffer
2452 * to the FC and SCSI target structures.
2453 *
2454 */
2455static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002456mptscsih_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 -07002457{
Eric Moorea69de502007-09-14 18:48:19 -06002458 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 SCSIIORequest_t *pReq;
2460 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002461 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
2463 /* Get target structure
2464 */
2465 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002466 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
2468 if (sense_count) {
2469 u8 *sense_data;
2470 int req_index;
2471
2472 /* Copy the sense received into the scsi command block. */
2473 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002474 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2476
2477 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2478 */
Eric Mooree80b0022007-09-14 18:49:03 -06002479 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002480 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002483 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2485 ioc->events[idx].eventContext = ioc->eventContext;
2486
Dave Jones3d9780b2007-05-21 20:59:47 -04002487 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2488 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2489 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
Dave Jones3d9780b2007-05-21 20:59:47 -04002491 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
2493 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002494 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002495 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002496 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002497 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2498 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002499 MPT_TARGET_FLAGS_LED_ON;
2500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
2502 }
2503 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002504 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2505 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507}
2508
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05302509/**
2510 * mptscsih_get_scsi_lookup - retrieves scmd entry
2511 * @ioc: Pointer to MPT_ADAPTER structure
2512 * @i: index into the array
2513 *
2514 * Returns the scsi_cmd pointer
2515 */
2516struct scsi_cmnd *
2517mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
2518{
2519 unsigned long flags;
2520 struct scsi_cmnd *scmd;
2521
2522 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2523 scmd = ioc->ScsiLookup[i];
2524 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2525
2526 return scmd;
2527}
2528EXPORT_SYMBOL(mptscsih_get_scsi_lookup);
Eric Mooree8206382007-09-29 10:16:53 -06002529
2530/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00002531 * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list
Kashyap, Desai2f187862009-05-29 16:52:37 +05302532 * @ioc: Pointer to MPT_ADAPTER structure
2533 * @i: index into the array
2534 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002535 * Returns the scsi_cmd pointer
Kashyap, Desai2f187862009-05-29 16:52:37 +05302536 *
Eric Mooree8206382007-09-29 10:16:53 -06002537 **/
2538static struct scsi_cmnd *
2539mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2540{
2541 unsigned long flags;
2542 struct scsi_cmnd *scmd;
2543
2544 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2545 scmd = ioc->ScsiLookup[i];
2546 ioc->ScsiLookup[i] = NULL;
2547 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2548
2549 return scmd;
2550}
2551
2552/**
2553 * mptscsih_set_scsi_lookup
2554 *
2555 * writes a scmd entry into the ScsiLookup[] array list
2556 *
2557 * @ioc: Pointer to MPT_ADAPTER structure
2558 * @i: index into the array
2559 * @scmd: scsi_cmnd pointer
2560 *
2561 **/
2562static void
2563mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2564{
2565 unsigned long flags;
2566
2567 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2568 ioc->ScsiLookup[i] = scmd;
2569 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2570}
2571
2572/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002573 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002574 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002575 * @sc: scsi_cmnd pointer
2576 */
Eric Mooree8206382007-09-29 10:16:53 -06002577static int
2578SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2579{
2580 unsigned long flags;
2581 int i, index=-1;
2582
2583 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2584 for (i = 0; i < ioc->req_depth; i++) {
2585 if (ioc->ScsiLookup[i] == sc) {
2586 index = i;
2587 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 }
2589 }
2590
Eric Mooree8206382007-09-29 10:16:53 -06002591 out:
2592 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2593 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594}
2595
2596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002597int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2599{
2600 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
Eric Mooree7eae9f2007-09-29 10:15:59 -06002602 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302605 hd = shost_priv(ioc->sh);
2606 switch (reset_phase) {
2607 case MPT_IOC_SETUP_RESET:
2608 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2609 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302610 break;
2611 case MPT_IOC_PRE_RESET:
2612 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2613 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302614 mptscsih_flush_running_cmds(hd);
2615 break;
2616 case MPT_IOC_POST_RESET:
2617 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2618 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2619 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2620 ioc->internal_cmds.status |=
2621 MPT_MGMT_STATUS_DID_IOCRESET;
2622 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302624 break;
2625 default:
2626 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 return 1; /* currently means nothing really */
2629}
2630
2631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002632int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2634{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2636
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302637 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2638 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2639 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
Kashyap, Desai2f187862009-05-29 16:52:37 +05302641 if ((event == MPI_EVENT_IOC_BUS_RESET ||
2642 event == MPI_EVENT_EXT_BUS_RESET) &&
2643 (ioc->bus_type == SPI) && (ioc->soft_resets < -1))
2644 ioc->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 return 1; /* currently means nothing really */
2647}
2648
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2650/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 * Bus Scan and Domain Validation functionality ...
2652 */
2653
2654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2655/*
2656 * mptscsih_scandv_complete - Scan and DV callback routine registered
2657 * to Fustion MPT (base) driver.
2658 *
2659 * @ioc: Pointer to MPT_ADAPTER structure
2660 * @mf: Pointer to original MPT request frame
2661 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2662 *
2663 * This routine is called from mpt.c::mpt_interrupt() at the completion
2664 * of any SCSI IO request.
2665 * This routine is registered with the Fusion MPT (base) driver at driver
2666 * load/init time via the mpt_register() API call.
2667 *
2668 * Returns 1 indicating alloc'd request frame ptr should be freed.
2669 *
2670 * Remark: Sets a completion code and (possibly) saves sense data
2671 * in the IOC member localReply structure.
2672 * Used ONLY for DV and other internal commands.
2673 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002674int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302675mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2676 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302679 SCSIIOReply_t *pReply;
2680 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302682 u8 *sense_data;
2683 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302685 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2686 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2687 if (!reply)
2688 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002689
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302690 pReply = (SCSIIOReply_t *) reply;
2691 pReq = (SCSIIORequest_t *) req;
2692 ioc->internal_cmds.completion_code =
2693 mptscsih_get_completion_code(ioc, req, reply);
2694 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2695 memcpy(ioc->internal_cmds.reply, reply,
2696 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2697 cmd = reply->u.hdr.Function;
2698 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2699 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2700 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2701 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2702 sense_data = ((u8 *)ioc->sense_buf_pool +
2703 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2704 sz = min_t(int, pReq->SenseBufferLength,
2705 MPT_SENSE_BUFFER_ALLOC);
2706 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302708 out:
2709 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2710 return 0;
2711 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2712 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 return 1;
2714}
2715
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302717/**
2718 * mptscsih_get_completion_code -
2719 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap9cf46a32009-06-13 19:37:18 -07002720 * @req: Pointer to original MPT request frame
2721 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302722 *
2723 **/
2724static int
2725mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2726 MPT_FRAME_HDR *reply)
2727{
2728 SCSIIOReply_t *pReply;
2729 MpiRaidActionReply_t *pr;
2730 u8 scsi_status;
2731 u16 status;
2732 int completion_code;
2733
2734 pReply = (SCSIIOReply_t *)reply;
2735 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2736 scsi_status = pReply->SCSIStatus;
2737
2738 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2739 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2740 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2741 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2742
2743 switch (status) {
2744
2745 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2746 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2747 break;
2748
2749 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2750 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2751 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2752 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2753 completion_code = MPT_SCANDV_DID_RESET;
2754 break;
2755
2756 case MPI_IOCSTATUS_BUSY:
2757 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2758 completion_code = MPT_SCANDV_BUSY;
2759 break;
2760
2761 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2762 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2763 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2764 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2765 completion_code = MPT_SCANDV_GOOD;
2766 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2767 pr = (MpiRaidActionReply_t *)reply;
2768 if (le16_to_cpu(pr->ActionStatus) ==
2769 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2770 completion_code = MPT_SCANDV_GOOD;
2771 else
2772 completion_code = MPT_SCANDV_SOME_ERROR;
2773 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2774 completion_code = MPT_SCANDV_SENSE;
2775 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2776 if (req->u.scsireq.CDB[0] == INQUIRY)
2777 completion_code = MPT_SCANDV_ISSUE_SENSE;
2778 else
2779 completion_code = MPT_SCANDV_DID_RESET;
2780 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2781 completion_code = MPT_SCANDV_DID_RESET;
2782 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2783 completion_code = MPT_SCANDV_DID_RESET;
2784 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2785 completion_code = MPT_SCANDV_BUSY;
2786 else
2787 completion_code = MPT_SCANDV_GOOD;
2788 break;
2789
2790 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2791 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2792 completion_code = MPT_SCANDV_DID_RESET;
2793 else
2794 completion_code = MPT_SCANDV_SOME_ERROR;
2795 break;
2796 default:
2797 completion_code = MPT_SCANDV_SOME_ERROR;
2798 break;
2799
2800 } /* switch(status) */
2801
2802 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2803 " completionCode set to %08xh\n", ioc->name, completion_code));
2804 return completion_code;
2805}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
2807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2808/**
2809 * mptscsih_do_cmd - Do internal command.
2810 * @hd: MPT_SCSI_HOST pointer
2811 * @io: INTERNAL_CMD pointer.
2812 *
2813 * Issue the specified internally generated command and do command
2814 * specific cleanup. For bus scan / DV only.
2815 * NOTES: If command is Inquiry and status is good,
2816 * initialize a target structure, save the data
2817 *
2818 * Remark: Single threaded access only.
2819 *
2820 * Return:
2821 * < 0 if an illegal command or no resources
2822 *
2823 * 0 if good
2824 *
2825 * > 0 if command complete but some type of completion error.
2826 */
2827static int
2828mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2829{
2830 MPT_FRAME_HDR *mf;
2831 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302833 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 char cmdLen;
2835 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 +05302836 u8 cmd = io->cmd;
2837 MPT_ADAPTER *ioc = hd->ioc;
2838 int ret = 0;
2839 unsigned long timeleft;
2840 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05302842 /* don't send internal command during diag reset */
2843 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2844 if (ioc->ioc_reset_in_progress) {
2845 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2846 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2847 "%s: busy with host reset\n", ioc->name, __func__));
2848 return MPT_SCANDV_BUSY;
2849 }
2850 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2851
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302852 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853
2854 /* Set command specific information
2855 */
2856 switch (cmd) {
2857 case INQUIRY:
2858 cmdLen = 6;
2859 dir = MPI_SCSIIO_CONTROL_READ;
2860 CDB[0] = cmd;
2861 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302862 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 break;
2864
2865 case TEST_UNIT_READY:
2866 cmdLen = 6;
2867 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302868 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 break;
2870
2871 case START_STOP:
2872 cmdLen = 6;
2873 dir = MPI_SCSIIO_CONTROL_READ;
2874 CDB[0] = cmd;
2875 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302876 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 break;
2878
2879 case REQUEST_SENSE:
2880 cmdLen = 6;
2881 CDB[0] = cmd;
2882 CDB[4] = io->size;
2883 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302884 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 break;
2886
2887 case READ_BUFFER:
2888 cmdLen = 10;
2889 dir = MPI_SCSIIO_CONTROL_READ;
2890 CDB[0] = cmd;
2891 if (io->flags & MPT_ICFLAG_ECHO) {
2892 CDB[1] = 0x0A;
2893 } else {
2894 CDB[1] = 0x02;
2895 }
2896
2897 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2898 CDB[1] |= 0x01;
2899 }
2900 CDB[6] = (io->size >> 16) & 0xFF;
2901 CDB[7] = (io->size >> 8) & 0xFF;
2902 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302903 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 break;
2905
2906 case WRITE_BUFFER:
2907 cmdLen = 10;
2908 dir = MPI_SCSIIO_CONTROL_WRITE;
2909 CDB[0] = cmd;
2910 if (io->flags & MPT_ICFLAG_ECHO) {
2911 CDB[1] = 0x0A;
2912 } else {
2913 CDB[1] = 0x02;
2914 }
2915 CDB[6] = (io->size >> 16) & 0xFF;
2916 CDB[7] = (io->size >> 8) & 0xFF;
2917 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302918 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 break;
2920
2921 case RESERVE:
2922 cmdLen = 6;
2923 dir = MPI_SCSIIO_CONTROL_READ;
2924 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302925 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 break;
2927
2928 case RELEASE:
2929 cmdLen = 6;
2930 dir = MPI_SCSIIO_CONTROL_READ;
2931 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302932 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 break;
2934
2935 case SYNCHRONIZE_CACHE:
2936 cmdLen = 10;
2937 dir = MPI_SCSIIO_CONTROL_READ;
2938 CDB[0] = cmd;
2939// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302940 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 break;
2942
2943 default:
2944 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302945 ret = -EFAULT;
2946 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 }
2948
2949 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302950 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 */
Eric Mooree80b0022007-09-14 18:49:03 -06002952 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302953 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
2954 ioc->name, __func__));
2955 ret = MPT_SCANDV_BUSY;
2956 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 }
2958
2959 pScsiReq = (SCSIIORequest_t *) mf;
2960
2961 /* Get the request index */
2962 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
2963 ADD_INDEX_LOG(my_idx); /* for debug */
2964
2965 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
2966 pScsiReq->TargetID = io->physDiskNum;
2967 pScsiReq->Bus = 0;
2968 pScsiReq->ChainOffset = 0;
2969 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2970 } else {
2971 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07002972 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 pScsiReq->ChainOffset = 0;
2974 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
2975 }
2976
2977 pScsiReq->CDBLength = cmdLen;
2978 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
2979
2980 pScsiReq->Reserved = 0;
2981
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302982 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 /* MsgContext set in mpt_get_msg_fram call */
2984
Eric Moore793955f2007-01-29 09:42:20 -07002985 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
2987 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
2988 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
2989 else
2990 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
2991
2992 if (cmd == REQUEST_SENSE) {
2993 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302994 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2995 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 }
2997
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302998 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 pScsiReq->CDB[ii] = CDB[ii];
3000
3001 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003002 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3004
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303005 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3006 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3007 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303009 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303010 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303011 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3012 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303013 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303014 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303016 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003017 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303018 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3019 timeout*HZ);
3020 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3021 ret = MPT_SCANDV_DID_RESET;
3022 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3023 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3024 cmd));
3025 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3026 mpt_free_msg_frame(ioc, mf);
3027 goto out;
3028 }
3029 if (!timeleft) {
3030 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
3031 ioc->name, __func__);
3032 mpt_HardResetHandler(ioc, CAN_SLEEP);
3033 mpt_free_msg_frame(ioc, mf);
3034 }
3035 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 }
3037
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303038 ret = ioc->internal_cmds.completion_code;
3039 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3040 ioc->name, __func__, ret));
3041
3042 out:
3043 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3044 mutex_unlock(&ioc->internal_cmds.mutex);
3045 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046}
3047
3048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3049/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003050 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3051 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003052 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003053 *
3054 * Uses the ISR, but with special processing.
3055 * MUST be single-threaded.
3056 *
3057 */
3058static void
3059mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3060{
3061 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
Eric Moorecc78d302007-06-15 17:27:21 -06003063 /* Ignore hidden raid components, this is handled when the command
3064 * is sent to the volume
3065 */
3066 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3067 return;
3068
3069 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3070 !vdevice->configured_lun)
3071 return;
3072
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 /* Following parameters will not change
3074 * in this routine.
3075 */
3076 iocmd.cmd = SYNCHRONIZE_CACHE;
3077 iocmd.flags = 0;
3078 iocmd.physDiskNum = -1;
3079 iocmd.data = NULL;
3080 iocmd.data_dma = -1;
3081 iocmd.size = 0;
3082 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003083 iocmd.channel = vdevice->vtarget->channel;
3084 iocmd.id = vdevice->vtarget->id;
3085 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
Eric Moorecc78d302007-06-15 17:27:21 -06003087 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088}
3089
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303090static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003091mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3092 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303093{
Tony Jonesee959b02008-02-22 00:13:36 +01003094 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003095 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303096 MPT_ADAPTER *ioc = hd->ioc;
3097
3098 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3099 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3100 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3101 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3102 ioc->facts.FWVersion.Word & 0x000000FF);
3103}
Tony Jonesee959b02008-02-22 00:13:36 +01003104static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303105
3106static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003107mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3108 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303109{
Tony Jonesee959b02008-02-22 00:13:36 +01003110 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003111 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303112 MPT_ADAPTER *ioc = hd->ioc;
3113
3114 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3115 (ioc->biosVersion & 0xFF000000) >> 24,
3116 (ioc->biosVersion & 0x00FF0000) >> 16,
3117 (ioc->biosVersion & 0x0000FF00) >> 8,
3118 ioc->biosVersion & 0x000000FF);
3119}
Tony Jonesee959b02008-02-22 00:13:36 +01003120static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303121
3122static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003123mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3124 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303125{
Tony Jonesee959b02008-02-22 00:13:36 +01003126 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003127 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303128 MPT_ADAPTER *ioc = hd->ioc;
3129
3130 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3131}
Tony Jonesee959b02008-02-22 00:13:36 +01003132static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303133
3134static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003135mptscsih_version_product_show(struct device *dev,
3136 struct device_attribute *attr,
3137char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303138{
Tony Jonesee959b02008-02-22 00:13:36 +01003139 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003140 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303141 MPT_ADAPTER *ioc = hd->ioc;
3142
3143 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3144}
Tony Jonesee959b02008-02-22 00:13:36 +01003145static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303146 mptscsih_version_product_show, NULL);
3147
3148static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003149mptscsih_version_nvdata_persistent_show(struct device *dev,
3150 struct device_attribute *attr,
3151 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303152{
Tony Jonesee959b02008-02-22 00:13:36 +01003153 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003154 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303155 MPT_ADAPTER *ioc = hd->ioc;
3156
3157 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3158 ioc->nvdata_version_persistent);
3159}
Tony Jonesee959b02008-02-22 00:13:36 +01003160static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303161 mptscsih_version_nvdata_persistent_show, NULL);
3162
3163static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003164mptscsih_version_nvdata_default_show(struct device *dev,
3165 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303166{
Tony Jonesee959b02008-02-22 00:13:36 +01003167 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003168 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303169 MPT_ADAPTER *ioc = hd->ioc;
3170
3171 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3172}
Tony Jonesee959b02008-02-22 00:13:36 +01003173static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303174 mptscsih_version_nvdata_default_show, NULL);
3175
3176static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003177mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3178 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303179{
Tony Jonesee959b02008-02-22 00:13:36 +01003180 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003181 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303182 MPT_ADAPTER *ioc = hd->ioc;
3183
3184 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3185}
Tony Jonesee959b02008-02-22 00:13:36 +01003186static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303187
3188static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003189mptscsih_board_assembly_show(struct device *dev,
3190 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303191{
Tony Jonesee959b02008-02-22 00:13:36 +01003192 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003193 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303194 MPT_ADAPTER *ioc = hd->ioc;
3195
3196 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3197}
Tony Jonesee959b02008-02-22 00:13:36 +01003198static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303199 mptscsih_board_assembly_show, NULL);
3200
3201static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003202mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3203 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303204{
Tony Jonesee959b02008-02-22 00:13:36 +01003205 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003206 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303207 MPT_ADAPTER *ioc = hd->ioc;
3208
3209 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3210}
Tony Jonesee959b02008-02-22 00:13:36 +01003211static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303212 mptscsih_board_tracer_show, NULL);
3213
3214static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003215mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3216 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303217{
Tony Jonesee959b02008-02-22 00:13:36 +01003218 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003219 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303220 MPT_ADAPTER *ioc = hd->ioc;
3221
3222 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3223}
Tony Jonesee959b02008-02-22 00:13:36 +01003224static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303225 mptscsih_io_delay_show, NULL);
3226
3227static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003228mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3229 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303230{
Tony Jonesee959b02008-02-22 00:13:36 +01003231 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003232 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303233 MPT_ADAPTER *ioc = hd->ioc;
3234
3235 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3236}
Tony Jonesee959b02008-02-22 00:13:36 +01003237static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303238 mptscsih_device_delay_show, NULL);
3239
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303240static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003241mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3242 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303243{
Tony Jonesee959b02008-02-22 00:13:36 +01003244 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003245 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303246 MPT_ADAPTER *ioc = hd->ioc;
3247
3248 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3249}
3250static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003251mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3252 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303253{
Tony Jonesee959b02008-02-22 00:13:36 +01003254 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003255 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303256 MPT_ADAPTER *ioc = hd->ioc;
3257 int val = 0;
3258
3259 if (sscanf(buf, "%x", &val) != 1)
3260 return -EINVAL;
3261
3262 ioc->debug_level = val;
3263 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3264 ioc->name, ioc->debug_level);
3265 return strlen(buf);
3266}
Tony Jonesee959b02008-02-22 00:13:36 +01003267static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3268 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303269
Tony Jonesee959b02008-02-22 00:13:36 +01003270struct device_attribute *mptscsih_host_attrs[] = {
3271 &dev_attr_version_fw,
3272 &dev_attr_version_bios,
3273 &dev_attr_version_mpi,
3274 &dev_attr_version_product,
3275 &dev_attr_version_nvdata_persistent,
3276 &dev_attr_version_nvdata_default,
3277 &dev_attr_board_name,
3278 &dev_attr_board_assembly,
3279 &dev_attr_board_tracer,
3280 &dev_attr_io_delay,
3281 &dev_attr_device_delay,
3282 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303283 NULL,
3284};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303285
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303286EXPORT_SYMBOL(mptscsih_host_attrs);
3287
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003288EXPORT_SYMBOL(mptscsih_remove);
3289EXPORT_SYMBOL(mptscsih_shutdown);
3290#ifdef CONFIG_PM
3291EXPORT_SYMBOL(mptscsih_suspend);
3292EXPORT_SYMBOL(mptscsih_resume);
3293#endif
3294EXPORT_SYMBOL(mptscsih_proc_info);
3295EXPORT_SYMBOL(mptscsih_info);
3296EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003297EXPORT_SYMBOL(mptscsih_slave_destroy);
3298EXPORT_SYMBOL(mptscsih_slave_configure);
3299EXPORT_SYMBOL(mptscsih_abort);
3300EXPORT_SYMBOL(mptscsih_dev_reset);
3301EXPORT_SYMBOL(mptscsih_bus_reset);
3302EXPORT_SYMBOL(mptscsih_host_reset);
3303EXPORT_SYMBOL(mptscsih_bios_param);
3304EXPORT_SYMBOL(mptscsih_io_done);
3305EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3306EXPORT_SYMBOL(mptscsih_scandv_complete);
3307EXPORT_SYMBOL(mptscsih_event_process);
3308EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003309EXPORT_SYMBOL(mptscsih_change_queue_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003311/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/