blob: 35173252e948954888b2112c195ae43a6b2701e8 [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 */
Eric Mooree8206382007-09-29 10:16:53 -060083static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
84static 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 -070095static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
96static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Eric Moore793955f2007-01-29 09:42:20 -070098static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400100int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
101int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Kashyap, Desai37c60f32009-05-29 16:44:06 +0530103static int mptscsih_get_completion_code(MPT_ADAPTER *ioc,
104 MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400105int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700107static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400109void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700110void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400112int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
113int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#endif
115
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900116#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
120/*
121 * mptscsih_getFreeChainBuffer - Function to get a free chain
122 * from the MPT_SCSI_HOST FreeChainQ.
123 * @ioc: Pointer to MPT_ADAPTER structure
124 * @req_idx: Index of the SCSI IO request frame. (output)
125 *
126 * return SUCCESS or FAILED
127 */
128static inline int
129mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
130{
131 MPT_FRAME_HDR *chainBuf;
132 unsigned long flags;
133 int rc;
134 int chain_idx;
135
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530136 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600137 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 spin_lock_irqsave(&ioc->FreeQlock, flags);
139 if (!list_empty(&ioc->FreeChainQ)) {
140 int offset;
141
142 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
143 u.frame.linkage.list);
144 list_del(&chainBuf->u.frame.linkage.list);
145 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
146 chain_idx = offset / ioc->req_sz;
147 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600148 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
149 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
150 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 } else {
152 rc = FAILED;
153 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600154 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
155 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
157 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
158
159 *retIndex = chain_idx;
160 return rc;
161} /* mptscsih_getFreeChainBuffer() */
162
163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
164/*
165 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
166 * SCSIIORequest_t Message Frame.
167 * @ioc: Pointer to MPT_ADAPTER structure
168 * @SCpnt: Pointer to scsi_cmnd structure
169 * @pReq: Pointer to SCSIIORequest_t structure
170 *
171 * Returns ...
172 */
173static int
174mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
175 SCSIIORequest_t *pReq, int req_idx)
176{
177 char *psge;
178 char *chainSge;
179 struct scatterlist *sg;
180 int frm_sz;
181 int sges_left, sg_done;
182 int chain_idx = MPT_HOST_NO_CHAIN;
183 int sgeOffset;
184 int numSgeSlots, numSgeThisFrame;
185 u32 sgflags, sgdir, thisxfer = 0;
186 int chain_dma_off = 0;
187 int newIndex;
188 int ii;
189 dma_addr_t v2;
190 u32 RequestNB;
191
192 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
193 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
194 sgdir = MPT_TRANSFER_HOST_TO_IOC;
195 } else {
196 sgdir = MPT_TRANSFER_IOC_TO_HOST;
197 }
198
199 psge = (char *) &pReq->SGL;
200 frm_sz = ioc->req_sz;
201
202 /* Map the data portion, if any.
203 * sges_left = 0 if no data transfer.
204 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900205 sges_left = scsi_dma_map(SCpnt);
206 if (sges_left < 0)
207 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 /* Handle the SG case.
210 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900211 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 sg_done = 0;
213 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
214 chainSge = NULL;
215
216 /* Prior to entering this loop - the following must be set
217 * current MF: sgeOffset (bytes)
218 * chainSge (Null if original MF is not a chain buffer)
219 * sg_done (num SGE done for this MF)
220 */
221
222nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530223 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
225
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530226 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 /* Get first (num - 1) SG elements
229 * Skip any SG entries with a length of 0
230 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
231 */
232 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
233 thisxfer = sg_dma_len(sg);
234 if (thisxfer == 0) {
Jens Axboeed17b032007-07-16 15:30:33 +0200235 sg = sg_next(sg); /* Get next SG element from the OS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 sg_done++;
237 continue;
238 }
239
240 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530241 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Jens Axboeed17b032007-07-16 15:30:33 +0200243 sg = sg_next(sg); /* Get next SG element from the OS */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530244 psge += ioc->SGE_size;
245 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 sg_done++;
247 }
248
249 if (numSgeThisFrame == sges_left) {
250 /* Add last element, end of buffer and end of list flags.
251 */
252 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
253 MPT_SGE_FLAGS_END_OF_BUFFER |
254 MPT_SGE_FLAGS_END_OF_LIST;
255
256 /* Add last SGE and set termination flags.
257 * Note: Last SGE may have a length of 0 - which should be ok.
258 */
259 thisxfer = sg_dma_len(sg);
260
261 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530262 ioc->add_sge(psge, sgflags | thisxfer, v2);
263 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 sg_done++;
265
266 if (chainSge) {
267 /* The current buffer is a chain buffer,
268 * but there is not another one.
269 * Update the chain element
270 * Offset and Length fields.
271 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530272 ioc->add_chain((char *)chainSge, 0, sgeOffset,
273 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 } else {
275 /* The current buffer is the original MF
276 * and there is no Chain buffer.
277 */
278 pReq->ChainOffset = 0;
279 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530280 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
282 ioc->RequestNB[req_idx] = RequestNB;
283 }
284 } else {
285 /* At least one chain buffer is needed.
286 * Complete the first MF
287 * - last SGE element, set the LastElement bit
288 * - set ChainOffset (words) for orig MF
289 * (OR finish previous MF chain buffer)
290 * - update MFStructPtr ChainIndex
291 * - Populate chain element
292 * Also
293 * Loop until done.
294 */
295
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530296 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 ioc->name, sg_done));
298
299 /* Set LAST_ELEMENT flag for last non-chain element
300 * in the buffer. Since psge points at the NEXT
301 * SGE element, go back one SGE element, update the flags
302 * and reset the pointer. (Note: sgflags & thisxfer are already
303 * set properly).
304 */
305 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530306 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 sgflags = le32_to_cpu(*ptmp);
308 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
309 *ptmp = cpu_to_le32(sgflags);
310 }
311
312 if (chainSge) {
313 /* The current buffer is a chain buffer.
314 * chainSge points to the previous Chain Element.
315 * Update its chain element Offset and Length (must
316 * include chain element size) fields.
317 * Old chain element is now complete.
318 */
319 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530320 sgeOffset += ioc->SGE_size;
321 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
322 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 } else {
324 /* The original MF buffer requires a chain buffer -
325 * set the offset.
326 * Last element in this MF is a chain element.
327 */
328 pReq->ChainOffset = (u8) (sgeOffset >> 2);
329 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530330 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 -0700331 ioc->RequestNB[req_idx] = RequestNB;
332 }
333
334 sges_left -= sg_done;
335
336
337 /* NOTE: psge points to the beginning of the chain element
338 * in current buffer. Get a chain buffer.
339 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200340 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530341 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200342 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
343 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 /* Update the tracking arrays.
348 * If chainSge == NULL, update ReqToChain, else ChainToChain
349 */
350 if (chainSge) {
351 ioc->ChainToChain[chain_idx] = newIndex;
352 } else {
353 ioc->ReqToChain[req_idx] = newIndex;
354 }
355 chain_idx = newIndex;
356 chain_dma_off = ioc->req_sz * chain_idx;
357
358 /* Populate the chainSGE for the current buffer.
359 * - Set chain buffer pointer to psge and fill
360 * out the Address and Flags fields.
361 */
362 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600363 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
364 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 /* Start the SGE for the next buffer
367 */
368 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
369 sgeOffset = 0;
370 sg_done = 0;
371
Eric Moore29dd3602007-09-14 18:46:51 -0600372 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
373 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 /* Start the SGE for the next buffer
376 */
377
378 goto nextSGEset;
379 }
380
381 return SUCCESS;
382} /* mptscsih_AddSGE() */
383
Eric Moore786899b2006-07-11 17:22:22 -0600384static void
385mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
386 U32 SlotStatus)
387{
388 MPT_FRAME_HDR *mf;
389 SEPRequest_t *SEPMsg;
390
Eric Moorecc78d302007-06-15 17:27:21 -0600391 if (ioc->bus_type != SAS)
392 return;
393
394 /* Not supported for hidden raid components
395 */
396 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600397 return;
398
399 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530400 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700401 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600402 return;
403 }
404
405 SEPMsg = (SEPRequest_t *)mf;
406 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700407 SEPMsg->Bus = vtarget->channel;
408 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600409 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
410 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530411 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700412 "Sending SEP cmd=%x channel=%d id=%d\n",
413 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600414 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
415}
416
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530417#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700418/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530419 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700420 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700421 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530422 * @pScsiReply: Pointer to MPT reply frame
423 *
424 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700425 *
426 * Refer to lsi/mpi.h.
427 **/
428static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530429mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700430{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530431 char *desc = NULL;
432 char *desc1 = NULL;
433 u16 ioc_status;
434 u8 skey, asc, ascq;
435
436 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700437
438 switch (ioc_status) {
439
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530440 case MPI_IOCSTATUS_SUCCESS:
441 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700442 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530443 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
444 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700445 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530446 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
447 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700448 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530449 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
450 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700451 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530452 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
453 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700454 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530455 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
456 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700457 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530458 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
459 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700460 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530461 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
462 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700463 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530464 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
465 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700466 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530467 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
468 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700469 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530470 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
471 desc = "task management failed";
472 break;
473 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
474 desc = "IOC terminated";
475 break;
476 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
477 desc = "ext terminated";
478 break;
479 default:
480 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700481 break;
482 }
483
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530484 switch (pScsiReply->SCSIStatus)
485 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700486
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530487 case MPI_SCSI_STATUS_SUCCESS:
488 desc1 = "success";
489 break;
490 case MPI_SCSI_STATUS_CHECK_CONDITION:
491 desc1 = "check condition";
492 break;
493 case MPI_SCSI_STATUS_CONDITION_MET:
494 desc1 = "condition met";
495 break;
496 case MPI_SCSI_STATUS_BUSY:
497 desc1 = "busy";
498 break;
499 case MPI_SCSI_STATUS_INTERMEDIATE:
500 desc1 = "intermediate";
501 break;
502 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
503 desc1 = "intermediate condmet";
504 break;
505 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
506 desc1 = "reservation conflict";
507 break;
508 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
509 desc1 = "command terminated";
510 break;
511 case MPI_SCSI_STATUS_TASK_SET_FULL:
512 desc1 = "task set full";
513 break;
514 case MPI_SCSI_STATUS_ACA_ACTIVE:
515 desc1 = "aca active";
516 break;
517 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
518 desc1 = "fcpext device logged out";
519 break;
520 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
521 desc1 = "fcpext no link";
522 break;
523 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
524 desc1 = "fcpext unassigned";
525 break;
526 default:
527 desc1 = "";
528 break;
529 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700530
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530531 scsi_print_command(sc);
Eric Moore29dd3602007-09-14 18:46:51 -0600532 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
533 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
534 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
535 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
536 scsi_get_resid(sc));
537 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
538 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530539 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Eric Moore29dd3602007-09-14 18:46:51 -0600540 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530541 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600542 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530543 pScsiReply->SCSIState);
544
545 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
546 skey = sc->sense_buffer[2] & 0x0F;
547 asc = sc->sense_buffer[12];
548 ascq = sc->sense_buffer[13];
549
Eric Moore29dd3602007-09-14 18:46:51 -0600550 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
551 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530552 }
553
554 /*
555 * Look for + dump FCP ResponseInfo[]!
556 */
557 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
558 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600559 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
560 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700561}
562#endif
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
565/*
566 * mptscsih_io_done - Main SCSI IO callback routine registered to
567 * Fusion MPT (base) driver
568 * @ioc: Pointer to MPT_ADAPTER structure
569 * @mf: Pointer to original MPT request frame
570 * @r: Pointer to MPT reply frame (NULL if TurboReply)
571 *
572 * This routine is called from mpt.c::mpt_interrupt() at the completion
573 * of any SCSI IO request.
574 * This routine is registered with the Fusion MPT (base) driver at driver
575 * load/init time via the mpt_register() API call.
576 *
577 * Returns 1 indicating alloc'd request frame ptr should be freed.
578 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400579int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
581{
582 struct scsi_cmnd *sc;
583 MPT_SCSI_HOST *hd;
584 SCSIIORequest_t *pScsiReq;
585 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700586 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600587 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600588 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Eric Mooree7eae9f2007-09-29 10:15:59 -0600590 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700592 req_idx_MR = (mr != NULL) ?
593 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
594 if ((req_idx != req_idx_MR) ||
595 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
596 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
597 ioc->name);
598 printk (MYIOC_s_ERR_FMT
599 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
600 ioc->name, req_idx, req_idx_MR, mf, mr,
Eric Mooree8206382007-09-29 10:16:53 -0600601 mptscsih_get_scsi_lookup(ioc, req_idx_MR));
Moore, Eric2254c862006-01-17 17:06:29 -0700602 return 0;
603 }
604
Eric Mooree8206382007-09-29 10:16:53 -0600605 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (sc == NULL) {
607 MPIHeader_t *hdr = (MPIHeader_t *)mf;
608
609 /* Remark: writeSDP1 will use the ScsiDoneCtx
610 * If a SCSI I/O cmd, device disabled by OS and
611 * completion done. Cannot touch sc struct. Just free mem.
612 */
613 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
614 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
615 ioc->name);
616
617 mptscsih_freeChainBuffers(ioc, req_idx);
618 return 1;
619 }
620
Eric Moore3dc0b032006-07-11 17:32:33 -0600621 if ((unsigned char *)mf != sc->host_scribble) {
622 mptscsih_freeChainBuffers(ioc, req_idx);
623 return 1;
624 }
625
626 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 sc->result = DID_OK << 16; /* Set default reply as OK */
628 pScsiReq = (SCSIIORequest_t *) mf;
629 pScsiReply = (SCSIIOReply_t *) mr;
630
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200631 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530632 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200633 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
634 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
635 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530636 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200637 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
638 ioc->name, mf, mr, sc, req_idx));
639 }
640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (pScsiReply == NULL) {
642 /* special context reply handling */
643 ;
644 } else {
645 u32 xfer_cnt;
646 u16 status;
647 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700648 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
651 scsi_state = pScsiReply->SCSIState;
652 scsi_status = pScsiReply->SCSIStatus;
653 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900654 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700655 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600657 /*
658 * if we get a data underrun indication, yet no data was
659 * transferred and the SCSI status indicates that the
660 * command was never started, change the data underrun
661 * to success
662 */
663 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
664 (scsi_status == MPI_SCSI_STATUS_BUSY ||
665 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
666 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
667 status = MPI_IOCSTATUS_SUCCESS;
668 }
669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400671 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 /*
674 * Look for + dump FCP ResponseInfo[]!
675 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600676 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
677 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600678 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
679 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700680 sc->device->host->host_no, sc->device->channel,
681 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 le32_to_cpu(pScsiReply->ResponseInfo));
683 }
684
685 switch(status) {
686 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
687 /* CHECKME!
688 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
689 * But not: DID_BUS_BUSY lest one risk
690 * killing interrupt handler:-(
691 */
692 sc->result = SAM_STAT_BUSY;
693 break;
694
695 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
696 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
697 sc->result = DID_BAD_TARGET << 16;
698 break;
699
700 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
701 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600702 if (ioc->bus_type != FC)
703 sc->result = DID_NO_CONNECT << 16;
704 /* else fibre, just stall until rescan event */
705 else
706 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
709 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600710
Eric Moorea69de502007-09-14 18:48:19 -0600711 vdevice = sc->device->hostdata;
712 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600713 break;
Eric Moorea69de502007-09-14 18:48:19 -0600714 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600715 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
716 mptscsih_issue_sep_command(ioc, vtarget,
717 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
718 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 break;
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600723 if ( ioc->bus_type == SAS ) {
724 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
725 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700726 if ((log_info & SAS_LOGINFO_MASK)
727 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600728 sc->result = (DID_BUS_BUSY << 16);
729 break;
730 }
731 }
Eric Moore86dd4242007-01-04 20:44:01 -0700732 } else if (ioc->bus_type == FC) {
733 /*
734 * The FC IOC may kill a request for variety of
735 * reasons, some of which may be recovered by a
736 * retry, some which are unlikely to be
737 * recovered. Return DID_ERROR instead of
738 * DID_RESET to permit retry of the command,
739 * just not an infinite number of them
740 */
741 sc->result = DID_ERROR << 16;
742 break;
Eric Moorebf451522006-07-11 17:25:35 -0600743 }
744
745 /*
746 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
747 */
748
749 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
751 /* Linux handles an unsolicited DID_RESET better
752 * than an unsolicited DID_ABORT.
753 */
754 sc->result = DID_RESET << 16;
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 break;
757
758 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900759 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600760 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
761 sc->result=DID_SOFT_ERROR << 16;
762 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600764 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700765 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600766 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
770 /*
771 * Do upfront check for valid SenseData and give it
772 * precedence!
773 */
774 sc->result = (DID_OK << 16) | scsi_status;
775 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
776 /* Have already saved the status and sense data
777 */
778 ;
779 } else {
780 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600781 if (scsi_status == SAM_STAT_BUSY)
782 sc->result = SAM_STAT_BUSY;
783 else
784 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
786 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
787 /* What to do?
788 */
789 sc->result = DID_SOFT_ERROR << 16;
790 }
791 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
792 /* Not real sure here either... */
793 sc->result = DID_RESET << 16;
794 }
795 }
796
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530797
Eric Moore29dd3602007-09-14 18:46:51 -0600798 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
799 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
800 ioc->name, sc->underflow));
801 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
802 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 /* Report Queue Full
805 */
806 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
807 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 break;
810
Moore, Eric7e551472006-01-16 18:53:21 -0700811 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900812 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
814 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600815 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 if (scsi_state == 0) {
817 ;
818 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
819 /*
820 * If running against circa 200003dd 909 MPT f/w,
821 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
822 * (QUEUE_FULL) returned from device! --> get 0x0000?128
823 * and with SenseBytes set to 0.
824 */
825 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
826 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
827
828 }
829 else if (scsi_state &
830 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
831 ) {
832 /*
833 * What to do?
834 */
835 sc->result = DID_SOFT_ERROR << 16;
836 }
837 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
838 /* Not real sure here either... */
839 sc->result = DID_RESET << 16;
840 }
841 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
842 /* Device Inq. data indicates that it supports
843 * QTags, but rejects QTag messages.
844 * This command completed OK.
845 *
846 * Not real sure here either so do nothing... */
847 }
848
849 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
850 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
851
852 /* Add handling of:
853 * Reservation Conflict, Busy,
854 * Command Terminated, CHECK
855 */
856 break;
857
858 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
859 sc->result = DID_SOFT_ERROR << 16;
860 break;
861
862 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
863 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
864 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
865 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
866 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
867 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
868 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
870 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
871 default:
872 /*
873 * What to do?
874 */
875 sc->result = DID_SOFT_ERROR << 16;
876 break;
877
878 } /* switch(status) */
879
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530880#ifdef CONFIG_FUSION_LOGGING
881 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
882 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700883#endif
884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 } /* end of address reply case */
886
887 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900888 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 sc->scsi_done(sc); /* Issue the command callback */
891
892 /* Free Chain buffers */
893 mptscsih_freeChainBuffers(ioc, req_idx);
894 return 1;
895}
896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897/*
898 * mptscsih_flush_running_cmds - For each command found, search
899 * Scsi_Host instance taskQ and reply to OS.
900 * Called only if recovering from a FW reload.
901 * @hd: Pointer to a SCSI HOST structure
902 *
903 * Returns: None.
904 *
905 * Must be called while new I/Os are being queued.
906 */
907static void
908mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
909{
910 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600911 struct scsi_cmnd *sc;
912 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 int ii;
Eric Mooree8206382007-09-29 10:16:53 -0600914 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Eric Mooree8206382007-09-29 10:16:53 -0600916 for (ii= 0; ii < ioc->req_depth; ii++) {
917 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
918 if (!sc)
919 continue;
920 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
921 if (!mf)
922 continue;
923 channel = mf->Bus;
924 id = mf->TargetID;
925 mptscsih_freeChainBuffers(ioc, ii);
926 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
927 if ((unsigned char *)mf != sc->host_scribble)
928 continue;
929 scsi_dma_unmap(sc);
930 sc->result = DID_RESET << 16;
931 sc->host_scribble = NULL;
Eric Moorec51d0be2007-09-29 10:17:21 -0600932 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
Eric Mooree8206382007-09-29 10:16:53 -0600933 "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
934 " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
935 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937}
938
939/*
940 * mptscsih_search_running_cmds - Delete any commands associated
941 * with the specified target and lun. Function called only
942 * when a lun is disable by mid-layer.
943 * Do NOT access the referenced scsi_cmnd structure or
944 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600945 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700946 * @hd: Pointer to a SCSI HOST structure
947 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 *
949 * Returns: None.
950 *
951 * Called from slave_destroy.
952 */
953static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700954mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 SCSIIORequest_t *mf = NULL;
957 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600958 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700959 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -0600960 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600961 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Eric Mooree8206382007-09-29 10:16:53 -0600963 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
964 for (ii = 0; ii < ioc->req_depth; ii++) {
965 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Eric Mooree80b0022007-09-14 18:49:03 -0600967 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600968 if (mf == NULL)
969 continue;
Eric Moorecc78d302007-06-15 17:27:21 -0600970 /* If the device is a hidden raid component, then its
971 * expected that the mf->function will be RAID_SCSI_IO
972 */
973 if (vdevice->vtarget->tflags &
974 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
975 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
976 continue;
977
Eric Moore793955f2007-01-29 09:42:20 -0700978 int_to_scsilun(vdevice->lun, &lun);
979 if ((mf->Bus != vdevice->vtarget->channel) ||
980 (mf->TargetID != vdevice->vtarget->id) ||
981 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 continue;
983
Eric Moore3dc0b032006-07-11 17:32:33 -0600984 if ((unsigned char *)mf != sc->host_scribble)
985 continue;
Eric Mooree8206382007-09-29 10:16:53 -0600986 ioc->ScsiLookup[ii] = NULL;
987 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
988 mptscsih_freeChainBuffers(ioc, ii);
989 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900990 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600991 sc->host_scribble = NULL;
992 sc->result = DID_NO_CONNECT << 16;
Eric Moorec51d0be2007-09-29 10:17:21 -0600993 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
Eric Mooree80b0022007-09-14 18:49:03 -0600994 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530995 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600996 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -0600997 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
999 }
Eric Mooree8206382007-09-29 10:16:53 -06001000 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 return;
1002}
1003
1004/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1007/*
1008 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1009 * from a SCSI target device.
1010 * @sc: Pointer to scsi_cmnd structure
1011 * @pScsiReply: Pointer to SCSIIOReply_t
1012 * @pScsiReq: Pointer to original SCSI request
1013 *
1014 * This routine periodically reports QUEUE_FULL status returned from a
1015 * SCSI target device. It reports this to the console via kernel
1016 * printk() API call, not more than once every 10 seconds.
1017 */
1018static void
1019mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1020{
1021 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001023 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001025 if (sc->device == NULL)
1026 return;
1027 if (sc->device->host == NULL)
1028 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001029 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001030 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001031 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001032 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001033 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1034 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001035 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037}
1038
1039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1040/*
1041 * mptscsih_remove - Removed scsi devices
1042 * @pdev: Pointer to pci_dev structure
1043 *
1044 *
1045 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001046void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047mptscsih_remove(struct pci_dev *pdev)
1048{
1049 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1050 struct Scsi_Host *host = ioc->sh;
1051 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001052 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001054 if(!host) {
1055 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
1059 scsi_remove_host(host);
1060
Eric Mooree7eae9f2007-09-29 10:15:59 -06001061 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001062 return;
1063
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001064 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001066 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Eric Mooree8206382007-09-29 10:16:53 -06001068 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001069 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001070 kfree(ioc->ScsiLookup);
1071 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073
Eric Mooree80b0022007-09-14 18:49:03 -06001074 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001075 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001076 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001077
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001078 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001079
1080 /* NULL the Scsi_Host pointer
1081 */
Eric Mooree80b0022007-09-14 18:49:03 -06001082 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001083
1084 scsi_host_put(host);
1085
1086 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088}
1089
1090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1091/*
1092 * mptscsih_shutdown - reboot notifier
1093 *
1094 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001095void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001096mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098}
1099
1100#ifdef CONFIG_PM
1101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1102/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001103 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 *
1105 *
1106 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001107int
Pavel Machek8d189f72005-04-16 15:25:28 -07001108mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301110 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1111
1112 scsi_block_requests(ioc->sh);
1113 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001114 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001115 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116}
1117
1118/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1119/*
1120 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1121 *
1122 *
1123 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001124int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125mptscsih_resume(struct pci_dev *pdev)
1126{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301127 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1128 int rc;
1129
1130 rc = mpt_resume(pdev);
1131 scsi_unblock_requests(ioc->sh);
1132 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133}
1134
1135#endif
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1138/**
1139 * mptscsih_info - Return information about MPT adapter
1140 * @SChost: Pointer to Scsi_Host structure
1141 *
1142 * (linux scsi_host_template.info routine)
1143 *
1144 * Returns pointer to buffer where information was written.
1145 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001146const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147mptscsih_info(struct Scsi_Host *SChost)
1148{
1149 MPT_SCSI_HOST *h;
1150 int size = 0;
1151
Eric Mooree7eae9f2007-09-29 10:15:59 -06001152 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001155 if (h->info_kbuf == NULL)
1156 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1157 return h->info_kbuf;
1158 h->info_kbuf[0] = '\0';
1159
1160 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1161 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001164 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
1166
1167struct info_str {
1168 char *buffer;
1169 int length;
1170 int offset;
1171 int pos;
1172};
1173
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001174static void
1175mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
1177 if (info->pos + len > info->length)
1178 len = info->length - info->pos;
1179
1180 if (info->pos + len < info->offset) {
1181 info->pos += len;
1182 return;
1183 }
1184
1185 if (info->pos < info->offset) {
1186 data += (info->offset - info->pos);
1187 len -= (info->offset - info->pos);
1188 }
1189
1190 if (len > 0) {
1191 memcpy(info->buffer + info->pos, data, len);
1192 info->pos += len;
1193 }
1194}
1195
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001196static int
1197mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
1199 va_list args;
1200 char buf[81];
1201 int len;
1202
1203 va_start(args, fmt);
1204 len = vsprintf(buf, fmt, args);
1205 va_end(args);
1206
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001207 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 return len;
1209}
1210
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001211static int
1212mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 struct info_str info;
1215
1216 info.buffer = pbuf;
1217 info.length = len;
1218 info.offset = offset;
1219 info.pos = 0;
1220
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001221 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1222 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1223 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1224 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1227}
1228
1229/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1230/**
1231 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001232 * @host: scsi host struct
1233 * @buffer: if write, user data; if read, buffer for user
1234 * @start: returns the buffer address
1235 * @offset: if write, 0; if read, the current offset into the buffer from
1236 * the previous read.
1237 * @length: if write, return length;
1238 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 *
1240 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001242int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1244 int length, int func)
1245{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001246 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 MPT_ADAPTER *ioc = hd->ioc;
1248 int size = 0;
1249
1250 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001251 /*
1252 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 */
1254 } else {
1255 if (start)
1256 *start = buffer;
1257
1258 size = mptscsih_host_info(ioc, buffer, offset, length);
1259 }
1260
1261 return size;
1262}
1263
1264/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1265#define ADD_INDEX_LOG(req_ent) do { } while(0)
1266
1267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1268/**
1269 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1270 * @SCpnt: Pointer to scsi_cmnd structure
1271 * @done: Pointer SCSI mid-layer IO completion function
1272 *
1273 * (linux scsi_host_template.queuecommand routine)
1274 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1275 * from a linux scsi_cmnd request and send it to the IOC.
1276 *
1277 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1278 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001279int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1281{
1282 MPT_SCSI_HOST *hd;
1283 MPT_FRAME_HDR *mf;
1284 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001285 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 int lun;
1287 u32 datalen;
1288 u32 scsictl;
1289 u32 scsidir;
1290 u32 cmd_len;
1291 int my_idx;
1292 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301293 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Eric Mooree7eae9f2007-09-29 10:15:59 -06001295 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301296 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 lun = SCpnt->device->lun;
1298 SCpnt->scsi_done = done;
1299
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301300 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1301 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303 if (hd->resetPending) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301304 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1305 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 return SCSI_MLQUEUE_HOST_BUSY;
1307 }
1308
1309 /*
1310 * Put together a MPT SCSI request...
1311 */
Eric Mooree80b0022007-09-14 18:49:03 -06001312 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301313 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1314 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 return SCSI_MLQUEUE_HOST_BUSY;
1316 }
1317
1318 pScsiReq = (SCSIIORequest_t *) mf;
1319
1320 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1321
1322 ADD_INDEX_LOG(my_idx);
1323
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001324 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 * Seems we may receive a buffer (datalen>0) even when there
1326 * will be no data transfer! GRRRRR...
1327 */
1328 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001329 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1331 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001332 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1334 } else {
1335 datalen = 0;
1336 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1337 }
1338
1339 /* Default to untagged. Once a target structure has been allocated,
1340 * use the Inquiry data to determine if device supports tagged.
1341 */
Eric Moorea69de502007-09-14 18:48:19 -06001342 if (vdevice
1343 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 && (SCpnt->device->tagged_supported)) {
1345 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1346 } else {
1347 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1348 }
1349
1350 /* Use the above information to set up the message frame
1351 */
Eric Moorea69de502007-09-14 18:48:19 -06001352 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1353 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001355 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001356 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1357 else
1358 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 pScsiReq->CDBLength = SCpnt->cmd_len;
1360 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1361 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301362 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001363 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 pScsiReq->Control = cpu_to_le32(scsictl);
1365
1366 /*
1367 * Write SCSI CDB into the message
1368 */
1369 cmd_len = SCpnt->cmd_len;
1370 for (ii=0; ii < cmd_len; ii++)
1371 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1372
1373 for (ii=cmd_len; ii < 16; ii++)
1374 pScsiReq->CDB[ii] = 0;
1375
1376 /* DataLength */
1377 pScsiReq->DataLength = cpu_to_le32(datalen);
1378
1379 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001380 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1382
1383 /* Now add the SG list
1384 * Always have a SGE even if null length.
1385 */
1386 if (datalen == 0) {
1387 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301388 ioc->add_sge((char *)&pScsiReq->SGL,
1389 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 (dma_addr_t) -1);
1391 } else {
1392 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001393 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 goto fail;
1395 }
1396
Eric Moore3dc0b032006-07-11 17:32:33 -06001397 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001398 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Eric Mooree80b0022007-09-14 18:49:03 -06001400 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301401 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1402 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001403 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 return 0;
1405
1406 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001407 mptscsih_freeChainBuffers(ioc, my_idx);
1408 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return SCSI_MLQUEUE_HOST_BUSY;
1410}
1411
1412/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1413/*
1414 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1415 * with a SCSI IO request
1416 * @hd: Pointer to the MPT_SCSI_HOST instance
1417 * @req_idx: Index of the SCSI IO request frame.
1418 *
1419 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1420 * No return.
1421 */
1422static void
1423mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1424{
1425 MPT_FRAME_HDR *chain;
1426 unsigned long flags;
1427 int chain_idx;
1428 int next;
1429
1430 /* Get the first chain index and reset
1431 * tracker state.
1432 */
1433 chain_idx = ioc->ReqToChain[req_idx];
1434 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1435
1436 while (chain_idx != MPT_HOST_NO_CHAIN) {
1437
1438 /* Save the next chain buffer index */
1439 next = ioc->ChainToChain[chain_idx];
1440
1441 /* Free this chain buffer and reset
1442 * tracker
1443 */
1444 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1445
1446 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1447 + (chain_idx * ioc->req_sz));
1448
1449 spin_lock_irqsave(&ioc->FreeQlock, flags);
1450 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1451 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1452
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301453 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 ioc->name, chain_idx));
1455
1456 /* handle next */
1457 chain_idx = next;
1458 }
1459 return;
1460}
1461
1462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1463/*
1464 * Reset Handling
1465 */
1466
1467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001468/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001470 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001472 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001473 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 * @lun: Logical Unit for reset (if appropriate)
1475 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001476 * @timeout: timeout for task management control
1477 *
1478 * Fall through to mpt_HardResetHandler if: not operational, too many
1479 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 *
1481 * Remark: Currently invoked from a non-interrupt thread (_bh).
1482 *
Randy Dunlap7105a382008-02-29 22:03:27 -08001483 * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 * will be active.
1485 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001486 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001487 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001488int
Eric Moore793955f2007-01-29 09:42:20 -07001489mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490{
1491 MPT_ADAPTER *ioc;
1492 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 u32 ioc_raw_state;
1494 unsigned long flags;
1495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 ioc = hd->ioc;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301497 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 // SJR - CHECKME - Can we avoid this here?
1500 // (mpt_HardResetHandler has this check...)
1501 spin_lock_irqsave(&ioc->diagLock, flags);
1502 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1503 spin_unlock_irqrestore(&ioc->diagLock, flags);
1504 return FAILED;
1505 }
1506 spin_unlock_irqrestore(&ioc->diagLock, flags);
1507
1508 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001509 * If we time out and not bus reset, then we return a FAILED status
1510 * to the caller.
1511 * The call to mptscsih_tm_pending_wait() will set the pending flag
1512 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 * successful. Otherwise, reload the FW.
1514 */
1515 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1516 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Eric Moore29dd3602007-09-14 18:46:51 -06001517 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301519 ioc->name, hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 return FAILED;
1521 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06001522 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
Eric Moorecd2c6192007-01-29 09:47:47 -07001523 "reset: Timed out waiting for last TM (%d) "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301524 "to complete! \n", ioc->name,
Eric Moorecd2c6192007-01-29 09:47:47 -07001525 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 return FAILED;
1527 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001528 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301530 ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001531 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 }
1533 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06001534 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 hd->tmPending |= (1 << type);
Eric Mooree80b0022007-09-14 18:49:03 -06001536 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 }
1538
Eric Mooree80b0022007-09-14 18:49:03 -06001539 ioc_raw_state = mpt_GetIocState(ioc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1542 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001543 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1544 ioc->name, type, ioc_raw_state);
Eric Moore29dd3602007-09-14 18:46:51 -06001545 printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001546 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06001547 printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
1548 "FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001549 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 }
1551
Eric Moorecd2c6192007-01-29 09:47:47 -07001552 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1553 printk(MYIOC_s_WARN_FMT
1554 "TM Handler for type=%x: ioc_state: "
1555 "DOORBELL_ACTIVE (0x%x)!\n",
1556 ioc->name, type, ioc_raw_state);
1557 return FAILED;
1558 }
1559
1560 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001562 if (hd->hard_resets < -1)
1563 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Eric Moorecd2c6192007-01-29 09:47:47 -07001565 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1566 ctx2abort, timeout);
1567 if (rc)
1568 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301569 ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001570 else
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301571 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1572 ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001573
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301574 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1575 "TMHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
1577 return rc;
1578}
1579
1580
1581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001582/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1584 * @hd: Pointer to MPT_SCSI_HOST structure
1585 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001586 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001587 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 * @lun: Logical Unit for reset (if appropriate)
1589 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001590 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 *
1592 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1593 * or a non-interrupt thread. In the former, must not call schedule().
1594 *
1595 * Not all fields are meaningfull for all task types.
1596 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001597 * Returns 0 for SUCCESS, or FAILED.
1598 *
1599 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600static int
Eric Moore793955f2007-01-29 09:42:20 -07001601mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602{
1603 MPT_FRAME_HDR *mf;
1604 SCSITaskMgmt_t *pScsiTm;
1605 int ii;
1606 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001607 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
1609 /* Return Fail to calling function if no message frames available.
1610 */
Eric Mooree80b0022007-09-14 18:49:03 -06001611 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
1612 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1613 ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001614 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 }
Eric Mooree80b0022007-09-14 18:49:03 -06001616 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
1617 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 /* Format the Request
1620 */
1621 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001622 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 pScsiTm->Bus = channel;
1624 pScsiTm->ChainOffset = 0;
1625 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1626
1627 pScsiTm->Reserved = 0;
1628 pScsiTm->TaskType = type;
1629 pScsiTm->Reserved1 = 0;
1630 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1631 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1632
Eric Moore793955f2007-01-29 09:42:20 -07001633 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
1635 for (ii=0; ii < 7; ii++)
1636 pScsiTm->Reserved2[ii] = 0;
1637
1638 pScsiTm->TaskMsgContext = ctx2abort;
1639
Eric Mooree80b0022007-09-14 18:49:03 -06001640 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1641 "type=%d\n", ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301643 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
Eric Mooree80b0022007-09-14 18:49:03 -06001645 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1646 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1647 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301648 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001649 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301650 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1651 if (retval) {
Eric Mooree80b0022007-09-14 18:49:03 -06001652 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
1653 " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
1654 ioc, mf, retval));
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301655 goto fail_out;
1656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 }
1658
1659 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Mooree80b0022007-09-14 18:49:03 -06001660 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
1661 " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
1662 ioc, mf));
1663 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
1664 ioc->name));
1665 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1666 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
1667 ioc->name, retval));
Eric Moorecd2c6192007-01-29 09:47:47 -07001668 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 }
1670
Eric Moorecd2c6192007-01-29 09:47:47 -07001671 /*
1672 * Handle success case, see if theres a non-zero ioc_status.
1673 */
1674 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1675 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1676 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1677 retval = 0;
1678 else
1679 retval = FAILED;
1680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001682
1683 fail_out:
1684
1685 /*
Joe Perchesfc1323b2008-02-03 17:21:01 +02001686 * Free task management mf, and corresponding tm flags
Eric Moorecd2c6192007-01-29 09:47:47 -07001687 */
Eric Mooree80b0022007-09-14 18:49:03 -06001688 mpt_free_msg_frame(ioc, mf);
Eric Moorecd2c6192007-01-29 09:47:47 -07001689 hd->tmPending = 0;
1690 hd->tmState = TM_STATE_NONE;
1691 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692}
1693
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001694static int
1695mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1696{
1697 switch (ioc->bus_type) {
1698 case FC:
1699 return 40;
1700 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001701 case SPI:
1702 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001703 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001704 }
1705}
1706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1708/**
1709 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1710 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1711 *
1712 * (linux scsi_host_template.eh_abort_handler routine)
1713 *
1714 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001715 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001716int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717mptscsih_abort(struct scsi_cmnd * SCpnt)
1718{
1719 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 MPT_FRAME_HDR *mf;
1721 u32 ctx2abort;
1722 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001723 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001724 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001725 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001726 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 /* If we can't locate our host adapter structure, return FAILED status.
1729 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001730 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 SCpnt->result = DID_RESET << 16;
1732 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001733 printk(KERN_ERR MYNAM ": task abort: "
1734 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 return FAILED;
1736 }
1737
Eric Moore958d4a32007-06-15 17:24:14 -06001738 ioc = hd->ioc;
1739 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1740 ioc->name, SCpnt);
1741 scsi_print_command(SCpnt);
1742
1743 vdevice = SCpnt->device->hostdata;
1744 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001745 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1746 "task abort: device has been deleted (sc=%p)\n",
1747 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001748 SCpnt->result = DID_NO_CONNECT << 16;
1749 SCpnt->scsi_done(SCpnt);
1750 retval = 0;
1751 goto out;
1752 }
1753
Eric Moorecc78d302007-06-15 17:27:21 -06001754 /* Task aborts are not supported for hidden raid components.
1755 */
1756 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001757 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1758 "task abort: hidden raid component (sc=%p)\n",
1759 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001760 SCpnt->result = DID_RESET << 16;
1761 retval = FAILED;
1762 goto out;
1763 }
1764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 /* Find this command
1766 */
Eric Mooree8206382007-09-29 10:16:53 -06001767 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001768 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 * Do OS callback.
1770 */
1771 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001772 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001773 "Command not in the active list! (sc=%p)\n", ioc->name,
1774 SCpnt));
1775 retval = 0;
1776 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 }
1778
Eric Moore958d4a32007-06-15 17:24:14 -06001779 if (hd->resetPending) {
1780 retval = FAILED;
1781 goto out;
1782 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001783
1784 if (hd->timeouts < -1)
1785 hd->timeouts++;
1786
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301787 if (mpt_fwfault_debug)
1788 mpt_halt_firmware(ioc);
1789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1791 * (the IO to be ABORT'd)
1792 *
1793 * NOTE: Since we do not byteswap MsgContext, we do not
1794 * swap it here either. It is an opaque cookie to
1795 * the controller, so it does not matter. -DaveM
1796 */
Eric Mooree80b0022007-09-14 18:49:03 -06001797 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1799
1800 hd->abortSCpnt = SCpnt;
1801
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001802 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001803 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1804 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Eric Mooree8206382007-09-29 10:16:53 -06001806 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001807 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001808 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001809
Eric Moore958d4a32007-06-15 17:24:14 -06001810 out:
1811 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1812 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001814 if (retval == 0)
1815 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001816 else
1817 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818}
1819
1820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1821/**
1822 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1823 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1824 *
1825 * (linux scsi_host_template.eh_dev_reset_handler routine)
1826 *
1827 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001828 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001829int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1831{
1832 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001833 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001834 VirtDevice *vdevice;
1835 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 /* If we can't locate our host adapter structure, return FAILED status.
1838 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001839 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001840 printk(KERN_ERR MYNAM ": target reset: "
1841 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 return FAILED;
1843 }
1844
Eric Moore958d4a32007-06-15 17:24:14 -06001845 ioc = hd->ioc;
1846 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1847 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001848 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
Eric Moore958d4a32007-06-15 17:24:14 -06001850 if (hd->resetPending) {
1851 retval = FAILED;
1852 goto out;
1853 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001854
Eric Moore958d4a32007-06-15 17:24:14 -06001855 vdevice = SCpnt->device->hostdata;
1856 if (!vdevice || !vdevice->vtarget) {
1857 retval = 0;
1858 goto out;
1859 }
1860
Eric Moorecc78d302007-06-15 17:27:21 -06001861 /* Target reset to hidden raid component is not supported
1862 */
1863 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1864 retval = FAILED;
1865 goto out;
1866 }
1867
Eric Moore958d4a32007-06-15 17:24:14 -06001868 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1869 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1870 mptscsih_get_tm_timeout(ioc));
1871
1872 out:
1873 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1874 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001875
1876 if (retval == 0)
1877 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001878 else
1879 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880}
1881
Eric Moorecd2c6192007-01-29 09:47:47 -07001882
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1884/**
1885 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1886 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1887 *
1888 * (linux scsi_host_template.eh_bus_reset_handler routine)
1889 *
1890 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001891 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001892int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1894{
1895 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001896 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001897 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001898 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* If we can't locate our host adapter structure, return FAILED status.
1901 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001902 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001903 printk(KERN_ERR MYNAM ": bus reset: "
1904 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 return FAILED;
1906 }
1907
Eric Moore958d4a32007-06-15 17:24:14 -06001908 ioc = hd->ioc;
1909 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1910 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001911 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 if (hd->timeouts < -1)
1914 hd->timeouts++;
1915
Eric Moorea69de502007-09-14 18:48:19 -06001916 vdevice = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001917 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moorea69de502007-09-14 18:48:19 -06001918 vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
Eric Moore958d4a32007-06-15 17:24:14 -06001920 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1921 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001922
1923 if (retval == 0)
1924 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001925 else
1926 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927}
1928
1929/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1930/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001931 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1933 *
1934 * (linux scsi_host_template.eh_host_reset_handler routine)
1935 *
1936 * Returns SUCCESS or FAILED.
1937 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001938int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1940{
1941 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001942 int retval;
1943 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
1945 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001946 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001947 printk(KERN_ERR MYNAM ": host reset: "
1948 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return FAILED;
1950 }
1951
James Bottomleya6da74c2008-12-15 14:13:27 -06001952 /* make sure we have no outstanding commands at this stage */
1953 mptscsih_flush_running_cmds(hd);
1954
Eric Moore958d4a32007-06-15 17:24:14 -06001955 ioc = hd->ioc;
1956 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1957 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
1959 /* If our attempts to reset the host failed, then return a failed
1960 * status. The host will be taken off line by the SCSI mid-layer.
1961 */
Eric Mooree80b0022007-09-14 18:49:03 -06001962 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06001963 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 } else {
1965 /* Make sure TM pending is cleared and TM state is set to
1966 * NONE.
1967 */
Eric Moore958d4a32007-06-15 17:24:14 -06001968 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 hd->tmPending = 0;
1970 hd->tmState = TM_STATE_NONE;
1971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
Eric Moore958d4a32007-06-15 17:24:14 -06001973 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1974 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
Eric Moore958d4a32007-06-15 17:24:14 -06001976 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977}
1978
1979/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1980/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001981 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 * @hd: Pointer to MPT host structure.
1983 *
1984 * Returns {SUCCESS,FAILED}.
1985 */
1986static int
1987mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1988{
1989 unsigned long flags;
1990 int loop_count = 4 * 10; /* Wait 10 seconds */
1991 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06001992 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 do {
Eric Mooree80b0022007-09-14 18:49:03 -06001995 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 if (hd->tmState == TM_STATE_NONE) {
1997 hd->tmState = TM_STATE_IN_PROGRESS;
1998 hd->tmPending = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001999 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002000 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 break;
2002 }
Eric Mooree80b0022007-09-14 18:49:03 -06002003 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 msleep(250);
2005 } while (--loop_count);
2006
2007 return status;
2008}
2009
2010/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2011/**
2012 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2013 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002014 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 *
2016 * Returns {SUCCESS,FAILED}.
2017 */
2018static int
2019mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2020{
2021 unsigned long flags;
2022 int loop_count = 4 * timeout;
2023 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06002024 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 do {
Eric Mooree80b0022007-09-14 18:49:03 -06002027 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 if(hd->tmPending == 0) {
2029 status = SUCCESS;
Eric Mooree80b0022007-09-14 18:49:03 -06002030 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 break;
2032 }
Eric Mooree80b0022007-09-14 18:49:03 -06002033 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002034 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 } while (--loop_count);
2036
2037 return status;
2038}
2039
2040/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002041static void
2042mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2043{
2044 char *desc;
2045
2046 switch (response_code) {
2047 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2048 desc = "The task completed.";
2049 break;
2050 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2051 desc = "The IOC received an invalid frame status.";
2052 break;
2053 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2054 desc = "The task type is not supported.";
2055 break;
2056 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2057 desc = "The requested task failed.";
2058 break;
2059 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2060 desc = "The task completed successfully.";
2061 break;
2062 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2063 desc = "The LUN request is invalid.";
2064 break;
2065 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2066 desc = "The task is in the IOC queue and has not been sent to target.";
2067 break;
2068 default:
2069 desc = "unknown";
2070 break;
2071 }
2072 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2073 ioc->name, response_code, desc);
2074}
2075
2076/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077/**
2078 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2079 * @ioc: Pointer to MPT_ADAPTER structure
2080 * @mf: Pointer to SCSI task mgmt request frame
2081 * @mr: Pointer to SCSI task mgmt reply frame
2082 *
2083 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2084 * of any SCSI task management request.
2085 * This routine is registered with the MPT (base) driver at driver
2086 * load/init time via the mpt_register() API call.
2087 *
2088 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002089 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002090int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2092{
2093 SCSITaskMgmtReply_t *pScsiTmReply;
2094 SCSITaskMgmt_t *pScsiTmReq;
2095 MPT_SCSI_HOST *hd;
2096 unsigned long flags;
2097 u16 iocstatus;
2098 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002099 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302101 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002102 ioc->name, mf, mr));
2103 if (!ioc->sh) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302104 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002105 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 return 1;
2107 }
2108
2109 if (mr == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302110 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002111 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
2114
Eric Mooree7eae9f2007-09-29 10:15:59 -06002115 hd = shost_priv(ioc->sh);
Eric Moorecd2c6192007-01-29 09:47:47 -07002116 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2117 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2118 tmType = pScsiTmReq->TaskType;
2119 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2120 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2121
2122 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2123 pScsiTmReply->ResponseCode)
2124 mptscsih_taskmgmt_response_code(ioc,
2125 pScsiTmReply->ResponseCode);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302126 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Eric Moorecd2c6192007-01-29 09:47:47 -07002127
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302128#ifdef CONFIG_FUSION_LOGGING
2129 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2130 (ioc->debug_level & MPT_DEBUG_TM ))
2131 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2132 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002133 "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302134 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2135 le16_to_cpu(pScsiTmReply->IOCStatus),
2136 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2137 le32_to_cpu(pScsiTmReply->TerminationCount));
Eric Moorecd2c6192007-01-29 09:47:47 -07002138#endif
2139 if (!iocstatus) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302140 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
Eric Moorecd2c6192007-01-29 09:47:47 -07002141 hd->abortSCpnt = NULL;
2142 goto out;
2143 }
2144
2145 /* Error? (anything non-zero?) */
2146
2147 /* clear flags and continue.
2148 */
2149 switch (tmType) {
2150
2151 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2152 if (termination_count == 1)
2153 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2154 hd->abortSCpnt = NULL;
2155 break;
2156
2157 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2158
2159 /* If an internal command is present
2160 * or the TM failed - reload the FW.
2161 * FC FW may respond FAILED to an ABORT
2162 */
2163 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2164 hd->cmdPtr)
2165 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06002166 printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07002167 break;
2168
2169 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2170 default:
2171 break;
2172 }
2173
2174 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 spin_lock_irqsave(&ioc->FreeQlock, flags);
2176 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002178 hd->tm_iocstatus = iocstatus;
2179 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
2181 return 1;
2182}
2183
2184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2185/*
2186 * This is anyones guess quite frankly.
2187 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002188int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2190 sector_t capacity, int geom[])
2191{
2192 int heads;
2193 int sectors;
2194 sector_t cylinders;
2195 ulong dummy;
2196
2197 heads = 64;
2198 sectors = 32;
2199
2200 dummy = heads * sectors;
2201 cylinders = capacity;
2202 sector_div(cylinders,dummy);
2203
2204 /*
2205 * Handle extended translation size for logical drives
2206 * > 1Gb
2207 */
2208 if ((ulong)capacity >= 0x200000) {
2209 heads = 255;
2210 sectors = 63;
2211 dummy = heads * sectors;
2212 cylinders = capacity;
2213 sector_div(cylinders,dummy);
2214 }
2215
2216 /* return result */
2217 geom[0] = heads;
2218 geom[1] = sectors;
2219 geom[2] = cylinders;
2220
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 return 0;
2222}
2223
Moore, Ericf44e5462006-03-14 09:14:21 -07002224/* Search IOC page 3 to determine if this is hidden physical disk
2225 *
2226 */
2227int
Eric Moore793955f2007-01-29 09:42:20 -07002228mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002229{
Eric Mooreb506ade2007-01-29 09:45:37 -07002230 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002231 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002232 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002233
Eric Moore793955f2007-01-29 09:42:20 -07002234 if (!ioc->raid_data.pIocPg3)
2235 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002236 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002237 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2238 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2239 rc = 1;
2240 goto out;
2241 }
2242 }
2243
Eric Mooreb506ade2007-01-29 09:45:37 -07002244 /*
2245 * Check inactive list for matching phys disks
2246 */
2247 if (list_empty(&ioc->raid_data.inactive_list))
2248 goto out;
2249
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002250 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002251 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2252 list) {
2253 if ((component_info->d.PhysDiskID == id) &&
2254 (component_info->d.PhysDiskBus == channel))
2255 rc = 1;
2256 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002257 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002258
Eric Moore793955f2007-01-29 09:42:20 -07002259 out:
2260 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002261}
2262EXPORT_SYMBOL(mptscsih_is_phys_disk);
2263
Eric Moore793955f2007-01-29 09:42:20 -07002264u8
2265mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002266{
Eric Mooreb506ade2007-01-29 09:45:37 -07002267 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002268 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002269 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002270
Eric Moore793955f2007-01-29 09:42:20 -07002271 if (!ioc->raid_data.pIocPg3)
2272 goto out;
2273 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2274 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2275 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2276 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2277 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002278 }
2279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
Eric Mooreb506ade2007-01-29 09:45:37 -07002281 /*
2282 * Check inactive list for matching phys disks
2283 */
2284 if (list_empty(&ioc->raid_data.inactive_list))
2285 goto out;
2286
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002287 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002288 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2289 list) {
2290 if ((component_info->d.PhysDiskID == id) &&
2291 (component_info->d.PhysDiskBus == channel))
2292 rc = component_info->d.PhysDiskNum;
2293 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002294 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002295
Eric Moore793955f2007-01-29 09:42:20 -07002296 out:
2297 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002298}
Eric Moore793955f2007-01-29 09:42:20 -07002299EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002300
2301/*
2302 * OS entry point to allow for host driver to free allocated memory
2303 * Called if no device present or device being unloaded
2304 */
2305void
2306mptscsih_slave_destroy(struct scsi_device *sdev)
2307{
2308 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002309 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002310 VirtTarget *vtarget;
2311 VirtDevice *vdevice;
2312 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002314 starget = scsi_target(sdev);
2315 vtarget = starget->hostdata;
2316 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002318 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002319 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002320 mptscsih_synchronize_cache(hd, vdevice);
2321 kfree(vdevice);
2322 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323}
2324
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002325/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2326/*
2327 * mptscsih_change_queue_depth - This function will set a devices queue depth
2328 * @sdev: per scsi_device pointer
2329 * @qdepth: requested queue depth
2330 *
2331 * Adding support for new 'change_queue_depth' api.
2332*/
2333int
2334mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002336 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002337 VirtTarget *vtarget;
2338 struct scsi_target *starget;
2339 int max_depth;
2340 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002341 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002343 starget = scsi_target(sdev);
2344 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002345
Eric Mooree80b0022007-09-14 18:49:03 -06002346 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002347 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002349 else if (sdev->type == TYPE_DISK &&
2350 vtarget->minSyncFactor <= MPT_ULTRA160)
2351 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2352 else
2353 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 } else
2355 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2356
2357 if (qdepth > max_depth)
2358 qdepth = max_depth;
2359 if (qdepth == 1)
2360 tagged = 0;
2361 else
2362 tagged = MSG_SIMPLE_TAG;
2363
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002364 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2365 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366}
2367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368/*
2369 * OS entry point to adjust the queue_depths on a per-device basis.
2370 * Called once per device the bus scan. Use it to force the queue_depth
2371 * member to 1 if a device does not support Q tags.
2372 * Return non-zero if fails.
2373 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002374int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002375mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002377 struct Scsi_Host *sh = sdev->host;
2378 VirtTarget *vtarget;
2379 VirtDevice *vdevice;
2380 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002381 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002382 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002384 starget = scsi_target(sdev);
2385 vtarget = starget->hostdata;
2386 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Eric Mooree80b0022007-09-14 18:49:03 -06002388 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002389 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002390 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2391 if (ioc->bus_type == SPI)
2392 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002393 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002394 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002395 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
Eric Moore793955f2007-01-29 09:42:20 -07002397 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002398 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
Eric Mooree80b0022007-09-14 18:49:03 -06002400 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002402 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
Eric Mooree80b0022007-09-14 18:49:03 -06002404 if (ioc->bus_type == SPI)
2405 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002406 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002407 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002408 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
Eric Mooree80b0022007-09-14 18:49:03 -06002410 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002412 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002413 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
2415 return 0;
2416}
2417
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2419/*
2420 * Private routines...
2421 */
2422
2423/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2424/* Utility function to copy sense data from the scsi_cmnd buffer
2425 * to the FC and SCSI target structures.
2426 *
2427 */
2428static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002429mptscsih_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 -07002430{
Eric Moorea69de502007-09-14 18:48:19 -06002431 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 SCSIIORequest_t *pReq;
2433 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002434 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
2436 /* Get target structure
2437 */
2438 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002439 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441 if (sense_count) {
2442 u8 *sense_data;
2443 int req_index;
2444
2445 /* Copy the sense received into the scsi command block. */
2446 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002447 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2449
2450 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2451 */
Eric Mooree80b0022007-09-14 18:49:03 -06002452 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002453 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002456 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2458 ioc->events[idx].eventContext = ioc->eventContext;
2459
Dave Jones3d9780b2007-05-21 20:59:47 -04002460 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2461 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2462 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Dave Jones3d9780b2007-05-21 20:59:47 -04002464 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
2466 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002467 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002468 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002469 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002470 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2471 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002472 MPT_TARGET_FLAGS_LED_ON;
2473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 }
2475 }
2476 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002477 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2478 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 }
2480}
2481
Eric Mooree8206382007-09-29 10:16:53 -06002482/**
2483 * mptscsih_get_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002484 * @ioc: Pointer to MPT_ADAPTER structure
2485 * @i: index into the array
2486 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002487 * retrieves scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002488 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002489 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002490 **/
2491static struct scsi_cmnd *
2492mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493{
Eric Mooree8206382007-09-29 10:16:53 -06002494 unsigned long flags;
2495 struct scsi_cmnd *scmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
Eric Mooree8206382007-09-29 10:16:53 -06002497 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2498 scmd = ioc->ScsiLookup[i];
2499 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
Eric Mooree8206382007-09-29 10:16:53 -06002501 return scmd;
2502}
2503
2504/**
2505 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002506 * @ioc: Pointer to MPT_ADAPTER structure
2507 * @i: index into the array
2508 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002509 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002510 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002511 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002512 **/
2513static struct scsi_cmnd *
2514mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2515{
2516 unsigned long flags;
2517 struct scsi_cmnd *scmd;
2518
2519 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2520 scmd = ioc->ScsiLookup[i];
2521 ioc->ScsiLookup[i] = NULL;
2522 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2523
2524 return scmd;
2525}
2526
2527/**
2528 * mptscsih_set_scsi_lookup
2529 *
2530 * writes a scmd entry into the ScsiLookup[] array list
2531 *
2532 * @ioc: Pointer to MPT_ADAPTER structure
2533 * @i: index into the array
2534 * @scmd: scsi_cmnd pointer
2535 *
2536 **/
2537static void
2538mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2539{
2540 unsigned long flags;
2541
2542 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2543 ioc->ScsiLookup[i] = scmd;
2544 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2545}
2546
2547/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002548 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002549 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002550 * @sc: scsi_cmnd pointer
2551 */
Eric Mooree8206382007-09-29 10:16:53 -06002552static int
2553SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2554{
2555 unsigned long flags;
2556 int i, index=-1;
2557
2558 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2559 for (i = 0; i < ioc->req_depth; i++) {
2560 if (ioc->ScsiLookup[i] == sc) {
2561 index = i;
2562 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 }
2564 }
2565
Eric Mooree8206382007-09-29 10:16:53 -06002566 out:
2567 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2568 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569}
2570
2571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002572int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2574{
2575 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
Eric Mooree7eae9f2007-09-29 10:15:59 -06002577 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302580 hd = shost_priv(ioc->sh);
2581 switch (reset_phase) {
2582 case MPT_IOC_SETUP_RESET:
2583 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2584 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 hd->resetPending = 1;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302586 break;
2587 case MPT_IOC_PRE_RESET:
2588 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2589 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 hd->resetPending = 0;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302591 mptscsih_flush_running_cmds(hd);
2592 break;
2593 case MPT_IOC_POST_RESET:
2594 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2595 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
2596 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) {
2597 ioc->internal_cmds.status |=
2598 MPT_MGMT_STATUS_DID_IOCRESET;
2599 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302601 break;
2602 default:
2603 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 return 1; /* currently means nothing really */
2606}
2607
2608/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002609int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2611{
2612 MPT_SCSI_HOST *hd;
2613 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2614
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302615 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2616 "MPT event (=%02Xh) routed to SCSI host driver!\n",
2617 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002619 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06002620 ((hd = shost_priv(ioc->sh)) == NULL))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002621 return 1;
2622
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 switch (event) {
2624 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2625 /* FIXME! */
2626 break;
2627 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2628 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002629 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002630 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 break;
2632 case MPI_EVENT_LOGOUT: /* 09 */
2633 /* FIXME! */
2634 break;
2635
Michael Reed05e8ec12006-01-13 14:31:54 -06002636 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002637 break;
2638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 /*
2640 * CHECKME! Don't think we need to do
2641 * anything for these, but...
2642 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2644 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2645 /*
2646 * CHECKME! Falling thru...
2647 */
2648 break;
2649
2650 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002651 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 case MPI_EVENT_NONE: /* 00 */
2654 case MPI_EVENT_LOG_DATA: /* 01 */
2655 case MPI_EVENT_STATE_CHANGE: /* 02 */
2656 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2657 default:
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302658 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2659 ": Ignoring event (=%02Xh)\n",
2660 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 break;
2662 }
2663
2664 return 1; /* currently means nothing really */
2665}
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2668/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 * Bus Scan and Domain Validation functionality ...
2670 */
2671
2672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2673/*
2674 * mptscsih_scandv_complete - Scan and DV callback routine registered
2675 * to Fustion MPT (base) driver.
2676 *
2677 * @ioc: Pointer to MPT_ADAPTER structure
2678 * @mf: Pointer to original MPT request frame
2679 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2680 *
2681 * This routine is called from mpt.c::mpt_interrupt() at the completion
2682 * of any SCSI IO request.
2683 * This routine is registered with the Fusion MPT (base) driver at driver
2684 * load/init time via the mpt_register() API call.
2685 *
2686 * Returns 1 indicating alloc'd request frame ptr should be freed.
2687 *
2688 * Remark: Sets a completion code and (possibly) saves sense data
2689 * in the IOC member localReply structure.
2690 * Used ONLY for DV and other internal commands.
2691 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002692int
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302693mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2694 MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 SCSIIORequest_t *pReq;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302697 SCSIIOReply_t *pReply;
2698 u8 cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 u16 req_idx;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302700 u8 *sense_data;
2701 int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302703 ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2704 ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD;
2705 if (!reply)
2706 goto out;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002707
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302708 pReply = (SCSIIOReply_t *) reply;
2709 pReq = (SCSIIORequest_t *) req;
2710 ioc->internal_cmds.completion_code =
2711 mptscsih_get_completion_code(ioc, req, reply);
2712 ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
2713 memcpy(ioc->internal_cmds.reply, reply,
2714 min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength));
2715 cmd = reply->u.hdr.Function;
2716 if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
2717 (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) &&
2718 (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
2719 req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx);
2720 sense_data = ((u8 *)ioc->sense_buf_pool +
2721 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2722 sz = min_t(int, pReq->SenseBufferLength,
2723 MPT_SENSE_BUFFER_ALLOC);
2724 memcpy(ioc->internal_cmds.sense, sense_data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302726 out:
2727 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING))
2728 return 0;
2729 ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
2730 complete(&ioc->internal_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 return 1;
2732}
2733
2734/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2735/* mptscsih_timer_expired - Call back for timer process.
2736 * Used only for dv functionality.
2737 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2738 *
2739 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002740void
2741mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742{
2743 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002744 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Eric Mooree80b0022007-09-14 18:49:03 -06002746 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
2748 if (hd->cmdPtr) {
2749 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2750
2751 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2752 /* Desire to issue a task management request here.
2753 * TM requests MUST be single threaded.
2754 * If old eh code and no TM current, issue request.
2755 * If new eh code, do nothing. Wait for OS cmd timeout
2756 * for bus reset.
2757 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 } else {
2759 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002760 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2761 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 }
2763 }
2764 } else {
2765 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002766 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 }
2768
2769 /* No more processing.
2770 * TM call will generate an interrupt for SCSI TM Management.
2771 * The FW will reply to all outstanding commands, callback will finish cleanup.
2772 * Hard reset clean-up will free all resources.
2773 */
Eric Mooree80b0022007-09-14 18:49:03 -06002774 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
2776 return;
2777}
2778
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302779/**
2780 * mptscsih_get_completion_code -
2781 * @ioc: Pointer to MPT_ADAPTER structure
2782 * @reply:
2783 * @cmd:
2784 *
2785 **/
2786static int
2787mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2788 MPT_FRAME_HDR *reply)
2789{
2790 SCSIIOReply_t *pReply;
2791 MpiRaidActionReply_t *pr;
2792 u8 scsi_status;
2793 u16 status;
2794 int completion_code;
2795
2796 pReply = (SCSIIOReply_t *)reply;
2797 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2798 scsi_status = pReply->SCSIStatus;
2799
2800 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2801 "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh,"
2802 "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState,
2803 scsi_status, le32_to_cpu(pReply->IOCLogInfo)));
2804
2805 switch (status) {
2806
2807 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2808 completion_code = MPT_SCANDV_SELECTION_TIMEOUT;
2809 break;
2810
2811 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2812 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2813 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2814 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2815 completion_code = MPT_SCANDV_DID_RESET;
2816 break;
2817
2818 case MPI_IOCSTATUS_BUSY:
2819 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
2820 completion_code = MPT_SCANDV_BUSY;
2821 break;
2822
2823 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2824 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2825 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2826 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2827 completion_code = MPT_SCANDV_GOOD;
2828 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2829 pr = (MpiRaidActionReply_t *)reply;
2830 if (le16_to_cpu(pr->ActionStatus) ==
2831 MPI_RAID_ACTION_ASTATUS_SUCCESS)
2832 completion_code = MPT_SCANDV_GOOD;
2833 else
2834 completion_code = MPT_SCANDV_SOME_ERROR;
2835 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)
2836 completion_code = MPT_SCANDV_SENSE;
2837 else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2838 if (req->u.scsireq.CDB[0] == INQUIRY)
2839 completion_code = MPT_SCANDV_ISSUE_SENSE;
2840 else
2841 completion_code = MPT_SCANDV_DID_RESET;
2842 } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2843 completion_code = MPT_SCANDV_DID_RESET;
2844 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2845 completion_code = MPT_SCANDV_DID_RESET;
2846 else if (scsi_status == MPI_SCSI_STATUS_BUSY)
2847 completion_code = MPT_SCANDV_BUSY;
2848 else
2849 completion_code = MPT_SCANDV_GOOD;
2850 break;
2851
2852 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2853 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2854 completion_code = MPT_SCANDV_DID_RESET;
2855 else
2856 completion_code = MPT_SCANDV_SOME_ERROR;
2857 break;
2858 default:
2859 completion_code = MPT_SCANDV_SOME_ERROR;
2860 break;
2861
2862 } /* switch(status) */
2863
2864 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2865 " completionCode set to %08xh\n", ioc->name, completion_code));
2866 return completion_code;
2867}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2870/**
2871 * mptscsih_do_cmd - Do internal command.
2872 * @hd: MPT_SCSI_HOST pointer
2873 * @io: INTERNAL_CMD pointer.
2874 *
2875 * Issue the specified internally generated command and do command
2876 * specific cleanup. For bus scan / DV only.
2877 * NOTES: If command is Inquiry and status is good,
2878 * initialize a target structure, save the data
2879 *
2880 * Remark: Single threaded access only.
2881 *
2882 * Return:
2883 * < 0 if an illegal command or no resources
2884 *
2885 * 0 if good
2886 *
2887 * > 0 if command complete but some type of completion error.
2888 */
2889static int
2890mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2891{
2892 MPT_FRAME_HDR *mf;
2893 SCSIIORequest_t *pScsiReq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 int my_idx, ii, dir;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302895 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 char cmdLen;
2897 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 +05302898 u8 cmd = io->cmd;
2899 MPT_ADAPTER *ioc = hd->ioc;
2900 int ret = 0;
2901 unsigned long timeleft;
2902 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302904 mutex_lock(&ioc->internal_cmds.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
2906 /* Set command specific information
2907 */
2908 switch (cmd) {
2909 case INQUIRY:
2910 cmdLen = 6;
2911 dir = MPI_SCSIIO_CONTROL_READ;
2912 CDB[0] = cmd;
2913 CDB[4] = io->size;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302914 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 break;
2916
2917 case TEST_UNIT_READY:
2918 cmdLen = 6;
2919 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302920 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 break;
2922
2923 case START_STOP:
2924 cmdLen = 6;
2925 dir = MPI_SCSIIO_CONTROL_READ;
2926 CDB[0] = cmd;
2927 CDB[4] = 1; /*Spin up the disk */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302928 timeout = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 break;
2930
2931 case REQUEST_SENSE:
2932 cmdLen = 6;
2933 CDB[0] = cmd;
2934 CDB[4] = io->size;
2935 dir = MPI_SCSIIO_CONTROL_READ;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302936 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 break;
2938
2939 case READ_BUFFER:
2940 cmdLen = 10;
2941 dir = MPI_SCSIIO_CONTROL_READ;
2942 CDB[0] = cmd;
2943 if (io->flags & MPT_ICFLAG_ECHO) {
2944 CDB[1] = 0x0A;
2945 } else {
2946 CDB[1] = 0x02;
2947 }
2948
2949 if (io->flags & MPT_ICFLAG_BUF_CAP) {
2950 CDB[1] |= 0x01;
2951 }
2952 CDB[6] = (io->size >> 16) & 0xFF;
2953 CDB[7] = (io->size >> 8) & 0xFF;
2954 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302955 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 break;
2957
2958 case WRITE_BUFFER:
2959 cmdLen = 10;
2960 dir = MPI_SCSIIO_CONTROL_WRITE;
2961 CDB[0] = cmd;
2962 if (io->flags & MPT_ICFLAG_ECHO) {
2963 CDB[1] = 0x0A;
2964 } else {
2965 CDB[1] = 0x02;
2966 }
2967 CDB[6] = (io->size >> 16) & 0xFF;
2968 CDB[7] = (io->size >> 8) & 0xFF;
2969 CDB[8] = io->size & 0xFF;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302970 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 break;
2972
2973 case RESERVE:
2974 cmdLen = 6;
2975 dir = MPI_SCSIIO_CONTROL_READ;
2976 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302977 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 break;
2979
2980 case RELEASE:
2981 cmdLen = 6;
2982 dir = MPI_SCSIIO_CONTROL_READ;
2983 CDB[0] = cmd;
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302984 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 break;
2986
2987 case SYNCHRONIZE_CACHE:
2988 cmdLen = 10;
2989 dir = MPI_SCSIIO_CONTROL_READ;
2990 CDB[0] = cmd;
2991// CDB[1] = 0x02; /* set immediate bit */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302992 timeout = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 break;
2994
2995 default:
2996 /* Error Case */
Kashyap, Desai37c60f32009-05-29 16:44:06 +05302997 ret = -EFAULT;
2998 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 }
3000
3001 /* Get and Populate a free Frame
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303002 * MsgContext set in mpt_get_msg_frame call
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 */
Eric Mooree80b0022007-09-14 18:49:03 -06003004 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303005 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n",
3006 ioc->name, __func__));
3007 ret = MPT_SCANDV_BUSY;
3008 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 }
3010
3011 pScsiReq = (SCSIIORequest_t *) mf;
3012
3013 /* Get the request index */
3014 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3015 ADD_INDEX_LOG(my_idx); /* for debug */
3016
3017 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3018 pScsiReq->TargetID = io->physDiskNum;
3019 pScsiReq->Bus = 0;
3020 pScsiReq->ChainOffset = 0;
3021 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3022 } else {
3023 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003024 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 pScsiReq->ChainOffset = 0;
3026 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3027 }
3028
3029 pScsiReq->CDBLength = cmdLen;
3030 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3031
3032 pScsiReq->Reserved = 0;
3033
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303034 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 /* MsgContext set in mpt_get_msg_fram call */
3036
Eric Moore793955f2007-01-29 09:42:20 -07003037 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3040 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3041 else
3042 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3043
3044 if (cmd == REQUEST_SENSE) {
3045 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303046 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3047 "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 }
3049
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303050 for (ii = 0; ii < 16; ii++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pScsiReq->CDB[ii] = CDB[ii];
3052
3053 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003054 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3056
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303057 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3058 "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n",
3059 ioc->name, __func__, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303061 if (dir == MPI_SCSIIO_CONTROL_READ)
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303062 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303063 MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma);
3064 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303065 ioc->add_sge((char *) &pScsiReq->SGL,
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303066 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303068 INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
Eric Mooree80b0022007-09-14 18:49:03 -06003069 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303070 timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done,
3071 timeout*HZ);
3072 if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
3073 ret = MPT_SCANDV_DID_RESET;
3074 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3075 "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__,
3076 cmd));
3077 if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) {
3078 mpt_free_msg_frame(ioc, mf);
3079 goto out;
3080 }
3081 if (!timeleft) {
3082 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
3083 ioc->name, __func__);
3084 mpt_HardResetHandler(ioc, CAN_SLEEP);
3085 mpt_free_msg_frame(ioc, mf);
3086 }
3087 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 }
3089
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303090 ret = ioc->internal_cmds.completion_code;
3091 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n",
3092 ioc->name, __func__, ret));
3093
3094 out:
3095 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
3096 mutex_unlock(&ioc->internal_cmds.mutex);
3097 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098}
3099
3100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3101/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003102 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3103 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003104 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003105 *
3106 * Uses the ISR, but with special processing.
3107 * MUST be single-threaded.
3108 *
3109 */
3110static void
3111mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3112{
3113 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
Eric Moorecc78d302007-06-15 17:27:21 -06003115 /* Ignore hidden raid components, this is handled when the command
3116 * is sent to the volume
3117 */
3118 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3119 return;
3120
3121 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3122 !vdevice->configured_lun)
3123 return;
3124
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 /* Following parameters will not change
3126 * in this routine.
3127 */
3128 iocmd.cmd = SYNCHRONIZE_CACHE;
3129 iocmd.flags = 0;
3130 iocmd.physDiskNum = -1;
3131 iocmd.data = NULL;
3132 iocmd.data_dma = -1;
3133 iocmd.size = 0;
3134 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003135 iocmd.channel = vdevice->vtarget->channel;
3136 iocmd.id = vdevice->vtarget->id;
3137 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Eric Moorecc78d302007-06-15 17:27:21 -06003139 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140}
3141
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303142static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003143mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3144 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303145{
Tony Jonesee959b02008-02-22 00:13:36 +01003146 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003147 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303148 MPT_ADAPTER *ioc = hd->ioc;
3149
3150 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3151 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3152 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3153 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3154 ioc->facts.FWVersion.Word & 0x000000FF);
3155}
Tony Jonesee959b02008-02-22 00:13:36 +01003156static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303157
3158static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003159mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3160 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303161{
Tony Jonesee959b02008-02-22 00:13:36 +01003162 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003163 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303164 MPT_ADAPTER *ioc = hd->ioc;
3165
3166 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3167 (ioc->biosVersion & 0xFF000000) >> 24,
3168 (ioc->biosVersion & 0x00FF0000) >> 16,
3169 (ioc->biosVersion & 0x0000FF00) >> 8,
3170 ioc->biosVersion & 0x000000FF);
3171}
Tony Jonesee959b02008-02-22 00:13:36 +01003172static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303173
3174static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003175mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3176 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303177{
Tony Jonesee959b02008-02-22 00:13:36 +01003178 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003179 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303180 MPT_ADAPTER *ioc = hd->ioc;
3181
3182 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3183}
Tony Jonesee959b02008-02-22 00:13:36 +01003184static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303185
3186static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003187mptscsih_version_product_show(struct device *dev,
3188 struct device_attribute *attr,
3189char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303190{
Tony Jonesee959b02008-02-22 00:13:36 +01003191 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003192 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303193 MPT_ADAPTER *ioc = hd->ioc;
3194
3195 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3196}
Tony Jonesee959b02008-02-22 00:13:36 +01003197static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303198 mptscsih_version_product_show, NULL);
3199
3200static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003201mptscsih_version_nvdata_persistent_show(struct device *dev,
3202 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, "%02xh\n",
3210 ioc->nvdata_version_persistent);
3211}
Tony Jonesee959b02008-02-22 00:13:36 +01003212static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303213 mptscsih_version_nvdata_persistent_show, NULL);
3214
3215static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003216mptscsih_version_nvdata_default_show(struct device *dev,
3217 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303218{
Tony Jonesee959b02008-02-22 00:13:36 +01003219 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003220 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303221 MPT_ADAPTER *ioc = hd->ioc;
3222
3223 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3224}
Tony Jonesee959b02008-02-22 00:13:36 +01003225static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303226 mptscsih_version_nvdata_default_show, NULL);
3227
3228static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003229mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3230 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303231{
Tony Jonesee959b02008-02-22 00:13:36 +01003232 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003233 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303234 MPT_ADAPTER *ioc = hd->ioc;
3235
3236 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3237}
Tony Jonesee959b02008-02-22 00:13:36 +01003238static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303239
3240static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003241mptscsih_board_assembly_show(struct device *dev,
3242 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +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, Sathyaedb90682007-07-17 14:39:14 +05303246 MPT_ADAPTER *ioc = hd->ioc;
3247
3248 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3249}
Tony Jonesee959b02008-02-22 00:13:36 +01003250static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303251 mptscsih_board_assembly_show, NULL);
3252
3253static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003254mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3255 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303256{
Tony Jonesee959b02008-02-22 00:13:36 +01003257 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003258 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303259 MPT_ADAPTER *ioc = hd->ioc;
3260
3261 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3262}
Tony Jonesee959b02008-02-22 00:13:36 +01003263static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303264 mptscsih_board_tracer_show, NULL);
3265
3266static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003267mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3268 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303269{
Tony Jonesee959b02008-02-22 00:13:36 +01003270 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003271 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303272 MPT_ADAPTER *ioc = hd->ioc;
3273
3274 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3275}
Tony Jonesee959b02008-02-22 00:13:36 +01003276static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303277 mptscsih_io_delay_show, NULL);
3278
3279static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003280mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3281 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303282{
Tony Jonesee959b02008-02-22 00:13:36 +01003283 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003284 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303285 MPT_ADAPTER *ioc = hd->ioc;
3286
3287 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3288}
Tony Jonesee959b02008-02-22 00:13:36 +01003289static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303290 mptscsih_device_delay_show, NULL);
3291
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303292static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003293mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3294 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303295{
Tony Jonesee959b02008-02-22 00:13:36 +01003296 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003297 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303298 MPT_ADAPTER *ioc = hd->ioc;
3299
3300 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3301}
3302static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003303mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3304 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303305{
Tony Jonesee959b02008-02-22 00:13:36 +01003306 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003307 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303308 MPT_ADAPTER *ioc = hd->ioc;
3309 int val = 0;
3310
3311 if (sscanf(buf, "%x", &val) != 1)
3312 return -EINVAL;
3313
3314 ioc->debug_level = val;
3315 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3316 ioc->name, ioc->debug_level);
3317 return strlen(buf);
3318}
Tony Jonesee959b02008-02-22 00:13:36 +01003319static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3320 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303321
Tony Jonesee959b02008-02-22 00:13:36 +01003322struct device_attribute *mptscsih_host_attrs[] = {
3323 &dev_attr_version_fw,
3324 &dev_attr_version_bios,
3325 &dev_attr_version_mpi,
3326 &dev_attr_version_product,
3327 &dev_attr_version_nvdata_persistent,
3328 &dev_attr_version_nvdata_default,
3329 &dev_attr_board_name,
3330 &dev_attr_board_assembly,
3331 &dev_attr_board_tracer,
3332 &dev_attr_io_delay,
3333 &dev_attr_device_delay,
3334 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303335 NULL,
3336};
Kashyap, Desai37c60f32009-05-29 16:44:06 +05303337
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303338EXPORT_SYMBOL(mptscsih_host_attrs);
3339
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003340EXPORT_SYMBOL(mptscsih_remove);
3341EXPORT_SYMBOL(mptscsih_shutdown);
3342#ifdef CONFIG_PM
3343EXPORT_SYMBOL(mptscsih_suspend);
3344EXPORT_SYMBOL(mptscsih_resume);
3345#endif
3346EXPORT_SYMBOL(mptscsih_proc_info);
3347EXPORT_SYMBOL(mptscsih_info);
3348EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003349EXPORT_SYMBOL(mptscsih_slave_destroy);
3350EXPORT_SYMBOL(mptscsih_slave_configure);
3351EXPORT_SYMBOL(mptscsih_abort);
3352EXPORT_SYMBOL(mptscsih_dev_reset);
3353EXPORT_SYMBOL(mptscsih_bus_reset);
3354EXPORT_SYMBOL(mptscsih_host_reset);
3355EXPORT_SYMBOL(mptscsih_bios_param);
3356EXPORT_SYMBOL(mptscsih_io_done);
3357EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3358EXPORT_SYMBOL(mptscsih_scandv_complete);
3359EXPORT_SYMBOL(mptscsih_event_process);
3360EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003361EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003362EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003363EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003365/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/