blob: 8c08c73f194c83774dd77511880d43cd23a38f19 [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
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400103int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700105static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400107void mptscsih_remove(struct pci_dev *);
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700108void mptscsih_shutdown(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#ifdef CONFIG_PM
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400110int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
111int mptscsih_resume(struct pci_dev *pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#endif
113
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900114#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
118/*
119 * mptscsih_getFreeChainBuffer - Function to get a free chain
120 * from the MPT_SCSI_HOST FreeChainQ.
121 * @ioc: Pointer to MPT_ADAPTER structure
122 * @req_idx: Index of the SCSI IO request frame. (output)
123 *
124 * return SUCCESS or FAILED
125 */
126static inline int
127mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
128{
129 MPT_FRAME_HDR *chainBuf;
130 unsigned long flags;
131 int rc;
132 int chain_idx;
133
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530134 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600135 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 spin_lock_irqsave(&ioc->FreeQlock, flags);
137 if (!list_empty(&ioc->FreeChainQ)) {
138 int offset;
139
140 chainBuf = list_entry(ioc->FreeChainQ.next, MPT_FRAME_HDR,
141 u.frame.linkage.list);
142 list_del(&chainBuf->u.frame.linkage.list);
143 offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
144 chain_idx = offset / ioc->req_sz;
145 rc = SUCCESS;
Eric Moore29dd3602007-09-14 18:46:51 -0600146 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
147 "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
148 ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 } else {
150 rc = FAILED;
151 chain_idx = MPT_HOST_NO_CHAIN;
Eric Moore29dd3602007-09-14 18:46:51 -0600152 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
153 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
155 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
156
157 *retIndex = chain_idx;
158 return rc;
159} /* mptscsih_getFreeChainBuffer() */
160
161/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
162/*
163 * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
164 * SCSIIORequest_t Message Frame.
165 * @ioc: Pointer to MPT_ADAPTER structure
166 * @SCpnt: Pointer to scsi_cmnd structure
167 * @pReq: Pointer to SCSIIORequest_t structure
168 *
169 * Returns ...
170 */
171static int
172mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
173 SCSIIORequest_t *pReq, int req_idx)
174{
175 char *psge;
176 char *chainSge;
177 struct scatterlist *sg;
178 int frm_sz;
179 int sges_left, sg_done;
180 int chain_idx = MPT_HOST_NO_CHAIN;
181 int sgeOffset;
182 int numSgeSlots, numSgeThisFrame;
183 u32 sgflags, sgdir, thisxfer = 0;
184 int chain_dma_off = 0;
185 int newIndex;
186 int ii;
187 dma_addr_t v2;
188 u32 RequestNB;
189
190 sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
191 if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
192 sgdir = MPT_TRANSFER_HOST_TO_IOC;
193 } else {
194 sgdir = MPT_TRANSFER_IOC_TO_HOST;
195 }
196
197 psge = (char *) &pReq->SGL;
198 frm_sz = ioc->req_sz;
199
200 /* Map the data portion, if any.
201 * sges_left = 0 if no data transfer.
202 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900203 sges_left = scsi_dma_map(SCpnt);
204 if (sges_left < 0)
205 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 /* Handle the SG case.
208 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900209 sg = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 sg_done = 0;
211 sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
212 chainSge = NULL;
213
214 /* Prior to entering this loop - the following must be set
215 * current MF: sgeOffset (bytes)
216 * chainSge (Null if original MF is not a chain buffer)
217 * sg_done (num SGE done for this MF)
218 */
219
220nextSGEset:
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530221 numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
223
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530224 sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 /* Get first (num - 1) SG elements
227 * Skip any SG entries with a length of 0
228 * NOTE: at finish, sg and psge pointed to NEXT data/location positions
229 */
230 for (ii=0; ii < (numSgeThisFrame-1); ii++) {
231 thisxfer = sg_dma_len(sg);
232 if (thisxfer == 0) {
Jens Axboeed17b032007-07-16 15:30:33 +0200233 sg = sg_next(sg); /* Get next SG element from the OS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 sg_done++;
235 continue;
236 }
237
238 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530239 ioc->add_sge(psge, sgflags | thisxfer, v2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Jens Axboeed17b032007-07-16 15:30:33 +0200241 sg = sg_next(sg); /* Get next SG element from the OS */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530242 psge += ioc->SGE_size;
243 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 sg_done++;
245 }
246
247 if (numSgeThisFrame == sges_left) {
248 /* Add last element, end of buffer and end of list flags.
249 */
250 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
251 MPT_SGE_FLAGS_END_OF_BUFFER |
252 MPT_SGE_FLAGS_END_OF_LIST;
253
254 /* Add last SGE and set termination flags.
255 * Note: Last SGE may have a length of 0 - which should be ok.
256 */
257 thisxfer = sg_dma_len(sg);
258
259 v2 = sg_dma_address(sg);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530260 ioc->add_sge(psge, sgflags | thisxfer, v2);
261 sgeOffset += ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 sg_done++;
263
264 if (chainSge) {
265 /* The current buffer is a chain buffer,
266 * but there is not another one.
267 * Update the chain element
268 * Offset and Length fields.
269 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530270 ioc->add_chain((char *)chainSge, 0, sgeOffset,
271 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 } else {
273 /* The current buffer is the original MF
274 * and there is no Chain buffer.
275 */
276 pReq->ChainOffset = 0;
277 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530278 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
280 ioc->RequestNB[req_idx] = RequestNB;
281 }
282 } else {
283 /* At least one chain buffer is needed.
284 * Complete the first MF
285 * - last SGE element, set the LastElement bit
286 * - set ChainOffset (words) for orig MF
287 * (OR finish previous MF chain buffer)
288 * - update MFStructPtr ChainIndex
289 * - Populate chain element
290 * Also
291 * Loop until done.
292 */
293
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530294 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 ioc->name, sg_done));
296
297 /* Set LAST_ELEMENT flag for last non-chain element
298 * in the buffer. Since psge points at the NEXT
299 * SGE element, go back one SGE element, update the flags
300 * and reset the pointer. (Note: sgflags & thisxfer are already
301 * set properly).
302 */
303 if (sg_done) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530304 u32 *ptmp = (u32 *) (psge - ioc->SGE_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 sgflags = le32_to_cpu(*ptmp);
306 sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
307 *ptmp = cpu_to_le32(sgflags);
308 }
309
310 if (chainSge) {
311 /* The current buffer is a chain buffer.
312 * chainSge points to the previous Chain Element.
313 * Update its chain element Offset and Length (must
314 * include chain element size) fields.
315 * Old chain element is now complete.
316 */
317 u8 nextChain = (u8) (sgeOffset >> 2);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530318 sgeOffset += ioc->SGE_size;
319 ioc->add_chain((char *)chainSge, nextChain, sgeOffset,
320 ioc->ChainBufferDMA + chain_dma_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 } else {
322 /* The original MF buffer requires a chain buffer -
323 * set the offset.
324 * Last element in this MF is a chain element.
325 */
326 pReq->ChainOffset = (u8) (sgeOffset >> 2);
327 RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530328 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 -0700329 ioc->RequestNB[req_idx] = RequestNB;
330 }
331
332 sges_left -= sg_done;
333
334
335 /* NOTE: psge points to the beginning of the chain element
336 * in current buffer. Get a chain buffer.
337 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200338 if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530339 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200340 "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
341 ioc->name, pReq->CDB[0], SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return FAILED;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 /* Update the tracking arrays.
346 * If chainSge == NULL, update ReqToChain, else ChainToChain
347 */
348 if (chainSge) {
349 ioc->ChainToChain[chain_idx] = newIndex;
350 } else {
351 ioc->ReqToChain[req_idx] = newIndex;
352 }
353 chain_idx = newIndex;
354 chain_dma_off = ioc->req_sz * chain_idx;
355
356 /* Populate the chainSGE for the current buffer.
357 * - Set chain buffer pointer to psge and fill
358 * out the Address and Flags fields.
359 */
360 chainSge = (char *) psge;
Eric Moore29dd3602007-09-14 18:46:51 -0600361 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
362 ioc->name, psge, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 /* Start the SGE for the next buffer
365 */
366 psge = (char *) (ioc->ChainBuffer + chain_dma_off);
367 sgeOffset = 0;
368 sg_done = 0;
369
Eric Moore29dd3602007-09-14 18:46:51 -0600370 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
371 ioc->name, psge, chain_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 /* Start the SGE for the next buffer
374 */
375
376 goto nextSGEset;
377 }
378
379 return SUCCESS;
380} /* mptscsih_AddSGE() */
381
Eric Moore786899b2006-07-11 17:22:22 -0600382static void
383mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
384 U32 SlotStatus)
385{
386 MPT_FRAME_HDR *mf;
387 SEPRequest_t *SEPMsg;
388
Eric Moorecc78d302007-06-15 17:27:21 -0600389 if (ioc->bus_type != SAS)
390 return;
391
392 /* Not supported for hidden raid components
393 */
394 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
Eric Moore786899b2006-07-11 17:22:22 -0600395 return;
396
397 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530398 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700399 ioc->name,__func__));
Eric Moore786899b2006-07-11 17:22:22 -0600400 return;
401 }
402
403 SEPMsg = (SEPRequest_t *)mf;
404 SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
Eric Moore793955f2007-01-29 09:42:20 -0700405 SEPMsg->Bus = vtarget->channel;
406 SEPMsg->TargetID = vtarget->id;
Eric Moore786899b2006-07-11 17:22:22 -0600407 SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
408 SEPMsg->SlotStatus = SlotStatus;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530409 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -0700410 "Sending SEP cmd=%x channel=%d id=%d\n",
411 ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
Eric Moore786899b2006-07-11 17:22:22 -0600412 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
413}
414
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530415#ifdef CONFIG_FUSION_LOGGING
Eric Moorec6c727a2007-01-29 09:44:54 -0700416/**
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530417 * mptscsih_info_scsiio - debug print info on reply frame
Eric Moorec6c727a2007-01-29 09:44:54 -0700418 * @ioc: Pointer to MPT_ADAPTER structure
Eric Moorec6c727a2007-01-29 09:44:54 -0700419 * @sc: original scsi cmnd pointer
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530420 * @pScsiReply: Pointer to MPT reply frame
421 *
422 * MPT_DEBUG_REPLY needs to be enabled to obtain this info
Eric Moorec6c727a2007-01-29 09:44:54 -0700423 *
424 * Refer to lsi/mpi.h.
425 **/
426static void
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530427mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
Eric Moorec6c727a2007-01-29 09:44:54 -0700428{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530429 char *desc = NULL;
430 char *desc1 = NULL;
431 u16 ioc_status;
432 u8 skey, asc, ascq;
433
434 ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moorec6c727a2007-01-29 09:44:54 -0700435
436 switch (ioc_status) {
437
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530438 case MPI_IOCSTATUS_SUCCESS:
439 desc = "success";
Eric Moorec6c727a2007-01-29 09:44:54 -0700440 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530441 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
442 desc = "invalid bus";
Eric Moorec6c727a2007-01-29 09:44:54 -0700443 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530444 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
445 desc = "invalid target_id";
Eric Moorec6c727a2007-01-29 09:44:54 -0700446 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530447 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
448 desc = "device not there";
Eric Moorec6c727a2007-01-29 09:44:54 -0700449 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530450 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
451 desc = "data overrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700452 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530453 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
454 desc = "data underrun";
Eric Moorec6c727a2007-01-29 09:44:54 -0700455 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530456 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
457 desc = "I/O data error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700458 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530459 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
460 desc = "protocol error";
Eric Moorec6c727a2007-01-29 09:44:54 -0700461 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530462 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
463 desc = "task terminated";
Eric Moorec6c727a2007-01-29 09:44:54 -0700464 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530465 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
466 desc = "residual mismatch";
Eric Moorec6c727a2007-01-29 09:44:54 -0700467 break;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530468 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
469 desc = "task management failed";
470 break;
471 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
472 desc = "IOC terminated";
473 break;
474 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
475 desc = "ext terminated";
476 break;
477 default:
478 desc = "";
Eric Moorec6c727a2007-01-29 09:44:54 -0700479 break;
480 }
481
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530482 switch (pScsiReply->SCSIStatus)
483 {
Eric Moorec6c727a2007-01-29 09:44:54 -0700484
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530485 case MPI_SCSI_STATUS_SUCCESS:
486 desc1 = "success";
487 break;
488 case MPI_SCSI_STATUS_CHECK_CONDITION:
489 desc1 = "check condition";
490 break;
491 case MPI_SCSI_STATUS_CONDITION_MET:
492 desc1 = "condition met";
493 break;
494 case MPI_SCSI_STATUS_BUSY:
495 desc1 = "busy";
496 break;
497 case MPI_SCSI_STATUS_INTERMEDIATE:
498 desc1 = "intermediate";
499 break;
500 case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
501 desc1 = "intermediate condmet";
502 break;
503 case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
504 desc1 = "reservation conflict";
505 break;
506 case MPI_SCSI_STATUS_COMMAND_TERMINATED:
507 desc1 = "command terminated";
508 break;
509 case MPI_SCSI_STATUS_TASK_SET_FULL:
510 desc1 = "task set full";
511 break;
512 case MPI_SCSI_STATUS_ACA_ACTIVE:
513 desc1 = "aca active";
514 break;
515 case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
516 desc1 = "fcpext device logged out";
517 break;
518 case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
519 desc1 = "fcpext no link";
520 break;
521 case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
522 desc1 = "fcpext unassigned";
523 break;
524 default:
525 desc1 = "";
526 break;
527 }
Eric Moorec6c727a2007-01-29 09:44:54 -0700528
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530529 scsi_print_command(sc);
Eric Moore29dd3602007-09-14 18:46:51 -0600530 printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
531 ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
532 printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
533 "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
534 scsi_get_resid(sc));
535 printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
536 "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530537 le32_to_cpu(pScsiReply->TransferCount), sc->result);
Eric Moore29dd3602007-09-14 18:46:51 -0600538 printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530539 "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600540 ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530541 pScsiReply->SCSIState);
542
543 if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
544 skey = sc->sense_buffer[2] & 0x0F;
545 asc = sc->sense_buffer[12];
546 ascq = sc->sense_buffer[13];
547
Eric Moore29dd3602007-09-14 18:46:51 -0600548 printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
549 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530550 }
551
552 /*
553 * Look for + dump FCP ResponseInfo[]!
554 */
555 if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
556 pScsiReply->ResponseInfo)
Eric Moore29dd3602007-09-14 18:46:51 -0600557 printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
558 ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
Eric Moorec6c727a2007-01-29 09:44:54 -0700559}
560#endif
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
563/*
564 * mptscsih_io_done - Main SCSI IO callback routine registered to
565 * Fusion MPT (base) driver
566 * @ioc: Pointer to MPT_ADAPTER structure
567 * @mf: Pointer to original MPT request frame
568 * @r: Pointer to MPT reply frame (NULL if TurboReply)
569 *
570 * This routine is called from mpt.c::mpt_interrupt() at the completion
571 * of any SCSI IO request.
572 * This routine is registered with the Fusion MPT (base) driver at driver
573 * load/init time via the mpt_register() API call.
574 *
575 * Returns 1 indicating alloc'd request frame ptr should be freed.
576 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400577int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
579{
580 struct scsi_cmnd *sc;
581 MPT_SCSI_HOST *hd;
582 SCSIIORequest_t *pScsiReq;
583 SCSIIOReply_t *pScsiReply;
Moore, Eric2254c862006-01-17 17:06:29 -0700584 u16 req_idx, req_idx_MR;
Eric Moorea69de502007-09-14 18:48:19 -0600585 VirtDevice *vdevice;
Eric Moore786899b2006-07-11 17:22:22 -0600586 VirtTarget *vtarget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Eric Mooree7eae9f2007-09-29 10:15:59 -0600588 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Moore, Eric2254c862006-01-17 17:06:29 -0700590 req_idx_MR = (mr != NULL) ?
591 le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
592 if ((req_idx != req_idx_MR) ||
593 (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
594 printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
595 ioc->name);
596 printk (MYIOC_s_ERR_FMT
597 "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
598 ioc->name, req_idx, req_idx_MR, mf, mr,
Eric Mooree8206382007-09-29 10:16:53 -0600599 mptscsih_get_scsi_lookup(ioc, req_idx_MR));
Moore, Eric2254c862006-01-17 17:06:29 -0700600 return 0;
601 }
602
Eric Mooree8206382007-09-29 10:16:53 -0600603 sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (sc == NULL) {
605 MPIHeader_t *hdr = (MPIHeader_t *)mf;
606
607 /* Remark: writeSDP1 will use the ScsiDoneCtx
608 * If a SCSI I/O cmd, device disabled by OS and
609 * completion done. Cannot touch sc struct. Just free mem.
610 */
611 if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
612 printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n",
613 ioc->name);
614
615 mptscsih_freeChainBuffers(ioc, req_idx);
616 return 1;
617 }
618
Eric Moore3dc0b032006-07-11 17:32:33 -0600619 if ((unsigned char *)mf != sc->host_scribble) {
620 mptscsih_freeChainBuffers(ioc, req_idx);
621 return 1;
622 }
623
624 sc->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 sc->result = DID_OK << 16; /* Set default reply as OK */
626 pScsiReq = (SCSIIORequest_t *) mf;
627 pScsiReply = (SCSIIOReply_t *) mr;
628
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200629 if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530630 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200631 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
632 ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
633 }else{
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530634 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200635 "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
636 ioc->name, mf, mr, sc, req_idx));
637 }
638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (pScsiReply == NULL) {
640 /* special context reply handling */
641 ;
642 } else {
643 u32 xfer_cnt;
644 u16 status;
645 u8 scsi_state, scsi_status;
Eric Moorec6c727a2007-01-29 09:44:54 -0700646 u32 log_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
649 scsi_state = pScsiReply->SCSIState;
650 scsi_status = pScsiReply->SCSIStatus;
651 xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900652 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Eric Moorec6c727a2007-01-29 09:44:54 -0700653 log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600655 /*
656 * if we get a data underrun indication, yet no data was
657 * transferred and the SCSI status indicates that the
658 * command was never started, change the data underrun
659 * to success
660 */
661 if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
662 (scsi_status == MPI_SCSI_STATUS_BUSY ||
663 scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
664 scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
665 status = MPI_IOCSTATUS_SUCCESS;
666 }
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400669 mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 /*
672 * Look for + dump FCP ResponseInfo[]!
673 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600674 if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
675 pScsiReply->ResponseInfo) {
Eric Moore29dd3602007-09-14 18:46:51 -0600676 printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
677 "FCP_ResponseInfo=%08xh\n", ioc->name,
Eric Moorec6c727a2007-01-29 09:44:54 -0700678 sc->device->host->host_no, sc->device->channel,
679 sc->device->id, sc->device->lun,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 le32_to_cpu(pScsiReply->ResponseInfo));
681 }
682
683 switch(status) {
684 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
685 /* CHECKME!
686 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
687 * But not: DID_BUS_BUSY lest one risk
688 * killing interrupt handler:-(
689 */
690 sc->result = SAM_STAT_BUSY;
691 break;
692
693 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
694 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
695 sc->result = DID_BAD_TARGET << 16;
696 break;
697
698 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
699 /* Spoof to SCSI Selection Timeout! */
Moore, Eric65207fe2006-04-21 16:14:35 -0600700 if (ioc->bus_type != FC)
701 sc->result = DID_NO_CONNECT << 16;
702 /* else fibre, just stall until rescan event */
703 else
704 sc->result = DID_REQUEUE << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
707 hd->sel_timeout[pScsiReq->TargetID]++;
Eric Moore786899b2006-07-11 17:22:22 -0600708
Eric Moorea69de502007-09-14 18:48:19 -0600709 vdevice = sc->device->hostdata;
710 if (!vdevice)
Eric Moore786899b2006-07-11 17:22:22 -0600711 break;
Eric Moorea69de502007-09-14 18:48:19 -0600712 vtarget = vdevice->vtarget;
Eric Moore786899b2006-07-11 17:22:22 -0600713 if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
714 mptscsih_issue_sep_command(ioc, vtarget,
715 MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
716 vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 break;
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorebf451522006-07-11 17:25:35 -0600721 if ( ioc->bus_type == SAS ) {
722 u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
723 if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
Eric Moorec6c727a2007-01-29 09:44:54 -0700724 if ((log_info & SAS_LOGINFO_MASK)
725 == SAS_LOGINFO_NEXUS_LOSS) {
Eric Moorebf451522006-07-11 17:25:35 -0600726 sc->result = (DID_BUS_BUSY << 16);
727 break;
728 }
729 }
Eric Moore86dd4242007-01-04 20:44:01 -0700730 } else if (ioc->bus_type == FC) {
731 /*
732 * The FC IOC may kill a request for variety of
733 * reasons, some of which may be recovered by a
734 * retry, some which are unlikely to be
735 * recovered. Return DID_ERROR instead of
736 * DID_RESET to permit retry of the command,
737 * just not an infinite number of them
738 */
739 sc->result = DID_ERROR << 16;
740 break;
Eric Moorebf451522006-07-11 17:25:35 -0600741 }
742
743 /*
744 * Allow non-SAS & non-NEXUS_LOSS to drop into below code
745 */
746
747 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
749 /* Linux handles an unsolicited DID_RESET better
750 * than an unsolicited DID_ABORT.
751 */
752 sc->result = DID_RESET << 16;
753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 break;
755
756 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900757 scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600758 if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
759 sc->result=DID_SOFT_ERROR << 16;
760 else /* Sufficient data transfer occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 sc->result = (DID_OK << 16) | scsi_status;
Eric Moore29dd3602007-09-14 18:46:51 -0600762 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moorec6c727a2007-01-29 09:44:54 -0700763 "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600764 ioc->name, sc->result, sc->device->channel, sc->device->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 break;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
768 /*
769 * Do upfront check for valid SenseData and give it
770 * precedence!
771 */
772 sc->result = (DID_OK << 16) | scsi_status;
773 if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
774 /* Have already saved the status and sense data
775 */
776 ;
777 } else {
778 if (xfer_cnt < sc->underflow) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600779 if (scsi_status == SAM_STAT_BUSY)
780 sc->result = SAM_STAT_BUSY;
781 else
782 sc->result = DID_SOFT_ERROR << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784 if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
785 /* What to do?
786 */
787 sc->result = DID_SOFT_ERROR << 16;
788 }
789 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
790 /* Not real sure here either... */
791 sc->result = DID_RESET << 16;
792 }
793 }
794
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530795
Eric Moore29dd3602007-09-14 18:46:51 -0600796 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
797 " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
798 ioc->name, sc->underflow));
799 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
800 " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530801
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 /* Report Queue Full
803 */
804 if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
805 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -0400806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 break;
808
Moore, Eric7e551472006-01-16 18:53:21 -0700809 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900810 scsi_set_resid(sc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
812 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
Eric Mooread8c31b2007-03-19 10:31:51 -0600813 sc->result = (DID_OK << 16) | scsi_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (scsi_state == 0) {
815 ;
816 } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
817 /*
818 * If running against circa 200003dd 909 MPT f/w,
819 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
820 * (QUEUE_FULL) returned from device! --> get 0x0000?128
821 * and with SenseBytes set to 0.
822 */
823 if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
824 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
825
826 }
827 else if (scsi_state &
828 (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
829 ) {
830 /*
831 * What to do?
832 */
833 sc->result = DID_SOFT_ERROR << 16;
834 }
835 else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
836 /* Not real sure here either... */
837 sc->result = DID_RESET << 16;
838 }
839 else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
840 /* Device Inq. data indicates that it supports
841 * QTags, but rejects QTag messages.
842 * This command completed OK.
843 *
844 * Not real sure here either so do nothing... */
845 }
846
847 if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
848 mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
849
850 /* Add handling of:
851 * Reservation Conflict, Busy,
852 * Command Terminated, CHECK
853 */
854 break;
855
856 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
857 sc->result = DID_SOFT_ERROR << 16;
858 break;
859
860 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
861 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
862 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
863 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
864 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
865 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
866 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
868 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
869 default:
870 /*
871 * What to do?
872 */
873 sc->result = DID_SOFT_ERROR << 16;
874 break;
875
876 } /* switch(status) */
877
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530878#ifdef CONFIG_FUSION_LOGGING
879 if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
880 mptscsih_info_scsiio(ioc, sc, pScsiReply);
Eric Moorec6c727a2007-01-29 09:44:54 -0700881#endif
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 } /* end of address reply case */
884
885 /* Unmap the DMA buffers, if any. */
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900886 scsi_dma_unmap(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 sc->scsi_done(sc); /* Issue the command callback */
889
890 /* Free Chain buffers */
891 mptscsih_freeChainBuffers(ioc, req_idx);
892 return 1;
893}
894
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895/*
896 * mptscsih_flush_running_cmds - For each command found, search
897 * Scsi_Host instance taskQ and reply to OS.
898 * Called only if recovering from a FW reload.
899 * @hd: Pointer to a SCSI HOST structure
900 *
901 * Returns: None.
902 *
903 * Must be called while new I/Os are being queued.
904 */
905static void
906mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
907{
908 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600909 struct scsi_cmnd *sc;
910 SCSIIORequest_t *mf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 int ii;
Eric Mooree8206382007-09-29 10:16:53 -0600912 int channel, id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Eric Mooree8206382007-09-29 10:16:53 -0600914 for (ii= 0; ii < ioc->req_depth; ii++) {
915 sc = mptscsih_getclear_scsi_lookup(ioc, ii);
916 if (!sc)
917 continue;
918 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
919 if (!mf)
920 continue;
921 channel = mf->Bus;
922 id = mf->TargetID;
923 mptscsih_freeChainBuffers(ioc, ii);
924 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
925 if ((unsigned char *)mf != sc->host_scribble)
926 continue;
927 scsi_dma_unmap(sc);
928 sc->result = DID_RESET << 16;
929 sc->host_scribble = NULL;
Eric Moorec51d0be2007-09-29 10:17:21 -0600930 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
Eric Mooree8206382007-09-29 10:16:53 -0600931 "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
932 " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
933 sc->scsi_done(sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935}
936
937/*
938 * mptscsih_search_running_cmds - Delete any commands associated
939 * with the specified target and lun. Function called only
940 * when a lun is disable by mid-layer.
941 * Do NOT access the referenced scsi_cmnd structure or
942 * members. Will cause either a paging or NULL ptr error.
Michael Reed05e8ec12006-01-13 14:31:54 -0600943 * (BUT, BUT, BUT, the code does reference it! - mdr)
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700944 * @hd: Pointer to a SCSI HOST structure
945 * @vdevice: per device private data
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 *
947 * Returns: None.
948 *
949 * Called from slave_destroy.
950 */
951static void
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700952mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 SCSIIORequest_t *mf = NULL;
955 int ii;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600956 struct scsi_cmnd *sc;
Eric Moore793955f2007-01-29 09:42:20 -0700957 struct scsi_lun lun;
Eric Mooree80b0022007-09-14 18:49:03 -0600958 MPT_ADAPTER *ioc = hd->ioc;
Eric Mooree8206382007-09-29 10:16:53 -0600959 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Eric Mooree8206382007-09-29 10:16:53 -0600961 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
962 for (ii = 0; ii < ioc->req_depth; ii++) {
963 if ((sc = ioc->ScsiLookup[ii]) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Eric Mooree80b0022007-09-14 18:49:03 -0600965 mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
Eric Moore3dc0b032006-07-11 17:32:33 -0600966 if (mf == NULL)
967 continue;
Eric Moorecc78d302007-06-15 17:27:21 -0600968 /* If the device is a hidden raid component, then its
969 * expected that the mf->function will be RAID_SCSI_IO
970 */
971 if (vdevice->vtarget->tflags &
972 MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
973 MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
974 continue;
975
Eric Moore793955f2007-01-29 09:42:20 -0700976 int_to_scsilun(vdevice->lun, &lun);
977 if ((mf->Bus != vdevice->vtarget->channel) ||
978 (mf->TargetID != vdevice->vtarget->id) ||
979 memcmp(lun.scsi_lun, mf->LUN, 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 continue;
981
Eric Moore3dc0b032006-07-11 17:32:33 -0600982 if ((unsigned char *)mf != sc->host_scribble)
983 continue;
Eric Mooree8206382007-09-29 10:16:53 -0600984 ioc->ScsiLookup[ii] = NULL;
985 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
986 mptscsih_freeChainBuffers(ioc, ii);
987 mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
FUJITA Tomonori1928d732007-05-26 00:37:15 +0900988 scsi_dma_unmap(sc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600989 sc->host_scribble = NULL;
990 sc->result = DID_NO_CONNECT << 16;
Eric Moorec51d0be2007-09-29 10:17:21 -0600991 sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
Eric Mooree80b0022007-09-14 18:49:03 -0600992 "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +0530993 vdevice->vtarget->id, sc, mf, ii);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600994 sc->scsi_done(sc);
Eric Mooree8206382007-09-29 10:16:53 -0600995 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
997 }
Eric Mooree8206382007-09-29 10:16:53 -0600998 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 return;
1000}
1001
1002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1005/*
1006 * mptscsih_report_queue_full - Report QUEUE_FULL status returned
1007 * from a SCSI target device.
1008 * @sc: Pointer to scsi_cmnd structure
1009 * @pScsiReply: Pointer to SCSIIOReply_t
1010 * @pScsiReq: Pointer to original SCSI request
1011 *
1012 * This routine periodically reports QUEUE_FULL status returned from a
1013 * SCSI target device. It reports this to the console via kernel
1014 * printk() API call, not more than once every 10 seconds.
1015 */
1016static void
1017mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
1018{
1019 long time = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 MPT_SCSI_HOST *hd;
Eric Mooree80b0022007-09-14 18:49:03 -06001021 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001023 if (sc->device == NULL)
1024 return;
1025 if (sc->device->host == NULL)
1026 return;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001027 if ((hd = shost_priv(sc->device->host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001028 return;
Eric Mooree80b0022007-09-14 18:49:03 -06001029 ioc = hd->ioc;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001030 if (time - hd->last_queue_full > 10 * HZ) {
Eric Mooree80b0022007-09-14 18:49:03 -06001031 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
1032 ioc->name, 0, sc->device->id, sc->device->lun));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001033 hd->last_queue_full = time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035}
1036
1037/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1038/*
1039 * mptscsih_remove - Removed scsi devices
1040 * @pdev: Pointer to pci_dev structure
1041 *
1042 *
1043 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001044void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045mptscsih_remove(struct pci_dev *pdev)
1046{
1047 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1048 struct Scsi_Host *host = ioc->sh;
1049 MPT_SCSI_HOST *hd;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001050 int sz1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001052 if(!host) {
1053 mpt_detach(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
1057 scsi_remove_host(host);
1058
Eric Mooree7eae9f2007-09-29 10:15:59 -06001059 if((hd = shost_priv(host)) == NULL)
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001060 return;
1061
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001062 mptscsih_shutdown(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001064 sz1=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Eric Mooree8206382007-09-29 10:16:53 -06001066 if (ioc->ScsiLookup != NULL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001067 sz1 = ioc->req_depth * sizeof(void *);
Eric Mooree8206382007-09-29 10:16:53 -06001068 kfree(ioc->ScsiLookup);
1069 ioc->ScsiLookup = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071
Eric Mooree80b0022007-09-14 18:49:03 -06001072 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001073 "Free'd ScsiLookup (%d) memory\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001074 ioc->name, sz1));
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001075
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001076 kfree(hd->info_kbuf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001077
1078 /* NULL the Scsi_Host pointer
1079 */
Eric Mooree80b0022007-09-14 18:49:03 -06001080 ioc->sh = NULL;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001081
1082 scsi_host_put(host);
1083
1084 mpt_detach(pdev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086}
1087
1088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1089/*
1090 * mptscsih_shutdown - reboot notifier
1091 *
1092 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001093void
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001094mptscsih_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
1098#ifdef CONFIG_PM
1099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1100/*
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001101 * mptscsih_suspend - Fusion MPT scsi driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 *
1103 *
1104 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001105int
Pavel Machek8d189f72005-04-16 15:25:28 -07001106mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301108 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1109
1110 scsi_block_requests(ioc->sh);
1111 flush_scheduled_work();
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001112 mptscsih_shutdown(pdev);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001113 return mpt_suspend(pdev,state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114}
1115
1116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1117/*
1118 * mptscsih_resume - Fusion MPT scsi driver resume routine.
1119 *
1120 *
1121 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001122int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123mptscsih_resume(struct pci_dev *pdev)
1124{
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301125 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1126 int rc;
1127
1128 rc = mpt_resume(pdev);
1129 scsi_unblock_requests(ioc->sh);
1130 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131}
1132
1133#endif
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1136/**
1137 * mptscsih_info - Return information about MPT adapter
1138 * @SChost: Pointer to Scsi_Host structure
1139 *
1140 * (linux scsi_host_template.info routine)
1141 *
1142 * Returns pointer to buffer where information was written.
1143 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001144const char *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145mptscsih_info(struct Scsi_Host *SChost)
1146{
1147 MPT_SCSI_HOST *h;
1148 int size = 0;
1149
Eric Mooree7eae9f2007-09-29 10:15:59 -06001150 h = shost_priv(SChost);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 if (h) {
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001153 if (h->info_kbuf == NULL)
1154 if ((h->info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
1155 return h->info_kbuf;
1156 h->info_kbuf[0] = '\0';
1157
1158 mpt_print_ioc_summary(h->ioc, h->info_kbuf, &size, 0, 0);
1159 h->info_kbuf[size-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001162 return h->info_kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
1165struct info_str {
1166 char *buffer;
1167 int length;
1168 int offset;
1169 int pos;
1170};
1171
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001172static void
1173mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174{
1175 if (info->pos + len > info->length)
1176 len = info->length - info->pos;
1177
1178 if (info->pos + len < info->offset) {
1179 info->pos += len;
1180 return;
1181 }
1182
1183 if (info->pos < info->offset) {
1184 data += (info->offset - info->pos);
1185 len -= (info->offset - info->pos);
1186 }
1187
1188 if (len > 0) {
1189 memcpy(info->buffer + info->pos, data, len);
1190 info->pos += len;
1191 }
1192}
1193
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001194static int
1195mptscsih_copy_info(struct info_str *info, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
1197 va_list args;
1198 char buf[81];
1199 int len;
1200
1201 va_start(args, fmt);
1202 len = vsprintf(buf, fmt, args);
1203 va_end(args);
1204
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001205 mptscsih_copy_mem_info(info, buf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return len;
1207}
1208
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001209static int
1210mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
1212 struct info_str info;
1213
1214 info.buffer = pbuf;
1215 info.length = len;
1216 info.offset = offset;
1217 info.pos = 0;
1218
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001219 mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
1220 mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
1221 mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
1222 mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 return ((info.pos > info.offset) ? info.pos - info.offset : 0);
1225}
1226
1227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1228/**
1229 * mptscsih_proc_info - Return information about MPT adapter
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001230 * @host: scsi host struct
1231 * @buffer: if write, user data; if read, buffer for user
1232 * @start: returns the buffer address
1233 * @offset: if write, 0; if read, the current offset into the buffer from
1234 * the previous read.
1235 * @length: if write, return length;
1236 * @func: write = 1; read = 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 *
1238 * (linux scsi_host_template.info routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001240int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
1242 int length, int func)
1243{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001244 MPT_SCSI_HOST *hd = shost_priv(host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 MPT_ADAPTER *ioc = hd->ioc;
1246 int size = 0;
1247
1248 if (func) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001249 /*
1250 * write is not supported
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 */
1252 } else {
1253 if (start)
1254 *start = buffer;
1255
1256 size = mptscsih_host_info(ioc, buffer, offset, length);
1257 }
1258
1259 return size;
1260}
1261
1262/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1263#define ADD_INDEX_LOG(req_ent) do { } while(0)
1264
1265/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1266/**
1267 * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
1268 * @SCpnt: Pointer to scsi_cmnd structure
1269 * @done: Pointer SCSI mid-layer IO completion function
1270 *
1271 * (linux scsi_host_template.queuecommand routine)
1272 * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
1273 * from a linux scsi_cmnd request and send it to the IOC.
1274 *
1275 * Returns 0. (rtn value discarded by linux scsi mid-layer)
1276 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001277int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1279{
1280 MPT_SCSI_HOST *hd;
1281 MPT_FRAME_HDR *mf;
1282 SCSIIORequest_t *pScsiReq;
Eric Moorea69de502007-09-14 18:48:19 -06001283 VirtDevice *vdevice = SCpnt->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 int lun;
1285 u32 datalen;
1286 u32 scsictl;
1287 u32 scsidir;
1288 u32 cmd_len;
1289 int my_idx;
1290 int ii;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301291 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Eric Mooree7eae9f2007-09-29 10:15:59 -06001293 hd = shost_priv(SCpnt->device->host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301294 ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 lun = SCpnt->device->lun;
1296 SCpnt->scsi_done = done;
1297
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301298 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
1299 ioc->name, SCpnt, done));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 if (hd->resetPending) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301302 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
1303 ioc->name, SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 return SCSI_MLQUEUE_HOST_BUSY;
1305 }
1306
1307 /*
1308 * Put together a MPT SCSI request...
1309 */
Eric Mooree80b0022007-09-14 18:49:03 -06001310 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301311 dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
1312 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return SCSI_MLQUEUE_HOST_BUSY;
1314 }
1315
1316 pScsiReq = (SCSIIORequest_t *) mf;
1317
1318 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
1319
1320 ADD_INDEX_LOG(my_idx);
1321
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001322 /* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 * Seems we may receive a buffer (datalen>0) even when there
1324 * will be no data transfer! GRRRRR...
1325 */
1326 if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001327 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
1329 } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
FUJITA Tomonori1928d732007-05-26 00:37:15 +09001330 datalen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
1332 } else {
1333 datalen = 0;
1334 scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1335 }
1336
1337 /* Default to untagged. Once a target structure has been allocated,
1338 * use the Inquiry data to determine if device supports tagged.
1339 */
Eric Moorea69de502007-09-14 18:48:19 -06001340 if (vdevice
1341 && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 && (SCpnt->device->tagged_supported)) {
1343 scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
1344 } else {
1345 scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
1346 }
1347
1348 /* Use the above information to set up the message frame
1349 */
Eric Moorea69de502007-09-14 18:48:19 -06001350 pScsiReq->TargetID = (u8) vdevice->vtarget->id;
1351 pScsiReq->Bus = vdevice->vtarget->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 pScsiReq->ChainOffset = 0;
Eric Moorea69de502007-09-14 18:48:19 -06001353 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
James Bottomleyc92f2222006-03-01 09:02:49 -06001354 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
1355 else
1356 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 pScsiReq->CDBLength = SCpnt->cmd_len;
1358 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
1359 pScsiReq->Reserved = 0;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301360 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Eric Moore793955f2007-01-29 09:42:20 -07001361 int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 pScsiReq->Control = cpu_to_le32(scsictl);
1363
1364 /*
1365 * Write SCSI CDB into the message
1366 */
1367 cmd_len = SCpnt->cmd_len;
1368 for (ii=0; ii < cmd_len; ii++)
1369 pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
1370
1371 for (ii=cmd_len; ii < 16; ii++)
1372 pScsiReq->CDB[ii] = 0;
1373
1374 /* DataLength */
1375 pScsiReq->DataLength = cpu_to_le32(datalen);
1376
1377 /* SenseBuffer low address */
Eric Mooree80b0022007-09-14 18:49:03 -06001378 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
1380
1381 /* Now add the SG list
1382 * Always have a SGE even if null length.
1383 */
1384 if (datalen == 0) {
1385 /* Add a NULL SGE */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301386 ioc->add_sge((char *)&pScsiReq->SGL,
1387 MPT_SGE_FLAGS_SSIMPLE_READ | 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 (dma_addr_t) -1);
1389 } else {
1390 /* Add a 32 or 64 bit SGE */
Eric Mooree80b0022007-09-14 18:49:03 -06001391 if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 goto fail;
1393 }
1394
Eric Moore3dc0b032006-07-11 17:32:33 -06001395 SCpnt->host_scribble = (unsigned char *)mf;
Eric Mooree8206382007-09-29 10:16:53 -06001396 mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Eric Mooree80b0022007-09-14 18:49:03 -06001398 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301399 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
1400 ioc->name, SCpnt, mf, my_idx));
Eric Moore29dd3602007-09-14 18:46:51 -06001401 DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 return 0;
1403
1404 fail:
Eric Mooree80b0022007-09-14 18:49:03 -06001405 mptscsih_freeChainBuffers(ioc, my_idx);
1406 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 return SCSI_MLQUEUE_HOST_BUSY;
1408}
1409
1410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1411/*
1412 * mptscsih_freeChainBuffers - Function to free chain buffers associated
1413 * with a SCSI IO request
1414 * @hd: Pointer to the MPT_SCSI_HOST instance
1415 * @req_idx: Index of the SCSI IO request frame.
1416 *
1417 * Called if SG chain buffer allocation fails and mptscsih callbacks.
1418 * No return.
1419 */
1420static void
1421mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
1422{
1423 MPT_FRAME_HDR *chain;
1424 unsigned long flags;
1425 int chain_idx;
1426 int next;
1427
1428 /* Get the first chain index and reset
1429 * tracker state.
1430 */
1431 chain_idx = ioc->ReqToChain[req_idx];
1432 ioc->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
1433
1434 while (chain_idx != MPT_HOST_NO_CHAIN) {
1435
1436 /* Save the next chain buffer index */
1437 next = ioc->ChainToChain[chain_idx];
1438
1439 /* Free this chain buffer and reset
1440 * tracker
1441 */
1442 ioc->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
1443
1444 chain = (MPT_FRAME_HDR *) (ioc->ChainBuffer
1445 + (chain_idx * ioc->req_sz));
1446
1447 spin_lock_irqsave(&ioc->FreeQlock, flags);
1448 list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
1449 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1450
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301451 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 ioc->name, chain_idx));
1453
1454 /* handle next */
1455 chain_idx = next;
1456 }
1457 return;
1458}
1459
1460/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1461/*
1462 * Reset Handling
1463 */
1464
1465/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001466/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 * mptscsih_TMHandler - Generic handler for SCSI Task Management.
Randy Dunlap1544d672007-02-20 11:17:03 -08001468 * @hd: Pointer to MPT SCSI HOST structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001470 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001471 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 * @lun: Logical Unit for reset (if appropriate)
1473 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001474 * @timeout: timeout for task management control
1475 *
1476 * Fall through to mpt_HardResetHandler if: not operational, too many
1477 * failed TM requests or handshake failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 *
1479 * Remark: Currently invoked from a non-interrupt thread (_bh).
1480 *
Randy Dunlap7105a382008-02-29 22:03:27 -08001481 * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 * will be active.
1483 *
Randy Dunlap1544d672007-02-20 11:17:03 -08001484 * Returns 0 for SUCCESS, or %FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001485 **/
James Bottomley663e1aa2006-01-29 12:10:24 -06001486int
Eric Moore793955f2007-01-29 09:42:20 -07001487mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488{
1489 MPT_ADAPTER *ioc;
1490 int rc = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 u32 ioc_raw_state;
1492 unsigned long flags;
1493
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 ioc = hd->ioc;
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301495 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
1497 // SJR - CHECKME - Can we avoid this here?
1498 // (mpt_HardResetHandler has this check...)
1499 spin_lock_irqsave(&ioc->diagLock, flags);
1500 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
1501 spin_unlock_irqrestore(&ioc->diagLock, flags);
1502 return FAILED;
1503 }
1504 spin_unlock_irqrestore(&ioc->diagLock, flags);
1505
1506 /* Wait a fixed amount of time for the TM pending flag to be cleared.
Eric Moorecd2c6192007-01-29 09:47:47 -07001507 * If we time out and not bus reset, then we return a FAILED status
1508 * to the caller.
1509 * The call to mptscsih_tm_pending_wait() will set the pending flag
1510 * if we are
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 * successful. Otherwise, reload the FW.
1512 */
1513 if (mptscsih_tm_pending_wait(hd) == FAILED) {
1514 if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
Eric Moore29dd3602007-09-14 18:46:51 -06001515 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301517 ioc->name, hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 return FAILED;
1519 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06001520 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
Eric Moorecd2c6192007-01-29 09:47:47 -07001521 "reset: Timed out waiting for last TM (%d) "
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301522 "to complete! \n", ioc->name,
Eric Moorecd2c6192007-01-29 09:47:47 -07001523 hd->tmPending));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 return FAILED;
1525 } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001526 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 "Timed out waiting for last TM (%d) to complete! \n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301528 ioc->name, hd->tmPending));
Eric Moorecd2c6192007-01-29 09:47:47 -07001529 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
1531 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06001532 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 hd->tmPending |= (1 << type);
Eric Mooree80b0022007-09-14 18:49:03 -06001534 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 }
1536
Eric Mooree80b0022007-09-14 18:49:03 -06001537 ioc_raw_state = mpt_GetIocState(ioc, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
1540 printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07001541 "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
1542 ioc->name, type, ioc_raw_state);
Eric Moore29dd3602007-09-14 18:46:51 -06001543 printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001544 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06001545 printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
1546 "FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001547 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 }
1549
Eric Moorecd2c6192007-01-29 09:47:47 -07001550 if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
1551 printk(MYIOC_s_WARN_FMT
1552 "TM Handler for type=%x: ioc_state: "
1553 "DOORBELL_ACTIVE (0x%x)!\n",
1554 ioc->name, type, ioc_raw_state);
1555 return FAILED;
1556 }
1557
1558 /* Isse the Task Mgmt request.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 */
Eric Moorecd2c6192007-01-29 09:47:47 -07001560 if (hd->hard_resets < -1)
1561 hd->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Eric Moorecd2c6192007-01-29 09:47:47 -07001563 rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
1564 ctx2abort, timeout);
1565 if (rc)
1566 printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301567 ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07001568 else
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301569 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
1570 ioc->name));
Eric Moore3dc0b032006-07-11 17:32:33 -06001571
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301572 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1573 "TMHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 return rc;
1576}
1577
1578
1579/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Eric Moorecd2c6192007-01-29 09:47:47 -07001580/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 * mptscsih_IssueTaskMgmt - Generic send Task Management function.
1582 * @hd: Pointer to MPT_SCSI_HOST structure
1583 * @type: Task Management type
Randy Dunlap1544d672007-02-20 11:17:03 -08001584 * @channel: channel number for task management
Eric Moore793955f2007-01-29 09:42:20 -07001585 * @id: Logical Target ID for reset (if appropriate)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 * @lun: Logical Unit for reset (if appropriate)
1587 * @ctx2abort: Context for the task to be aborted (if appropriate)
Randy Dunlap1544d672007-02-20 11:17:03 -08001588 * @timeout: timeout for task management control
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 *
1590 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
1591 * or a non-interrupt thread. In the former, must not call schedule().
1592 *
1593 * Not all fields are meaningfull for all task types.
1594 *
Eric Moorecd2c6192007-01-29 09:47:47 -07001595 * Returns 0 for SUCCESS, or FAILED.
1596 *
1597 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598static int
Eric Moore793955f2007-01-29 09:42:20 -07001599mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600{
1601 MPT_FRAME_HDR *mf;
1602 SCSITaskMgmt_t *pScsiTm;
1603 int ii;
1604 int retval;
Eric Mooree80b0022007-09-14 18:49:03 -06001605 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 /* Return Fail to calling function if no message frames available.
1608 */
Eric Mooree80b0022007-09-14 18:49:03 -06001609 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
1610 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
1611 ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001612 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 }
Eric Mooree80b0022007-09-14 18:49:03 -06001614 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
1615 ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617 /* Format the Request
1618 */
1619 pScsiTm = (SCSITaskMgmt_t *) mf;
Eric Moore793955f2007-01-29 09:42:20 -07001620 pScsiTm->TargetID = id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 pScsiTm->Bus = channel;
1622 pScsiTm->ChainOffset = 0;
1623 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1624
1625 pScsiTm->Reserved = 0;
1626 pScsiTm->TaskType = type;
1627 pScsiTm->Reserved1 = 0;
1628 pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
1629 ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
1630
Eric Moore793955f2007-01-29 09:42:20 -07001631 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 for (ii=0; ii < 7; ii++)
1634 pScsiTm->Reserved2[ii] = 0;
1635
1636 pScsiTm->TaskMsgContext = ctx2abort;
1637
Eric Mooree80b0022007-09-14 18:49:03 -06001638 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
1639 "type=%d\n", ioc->name, ctx2abort, type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05301641 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Eric Mooree80b0022007-09-14 18:49:03 -06001643 if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
1644 (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
1645 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301646 else {
Eric Mooree80b0022007-09-14 18:49:03 -06001647 retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301648 sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
1649 if (retval) {
Eric Mooree80b0022007-09-14 18:49:03 -06001650 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
1651 " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
1652 ioc, mf, retval));
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301653 goto fail_out;
1654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 }
1656
1657 if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
Eric Mooree80b0022007-09-14 18:49:03 -06001658 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
1659 " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
1660 ioc, mf));
1661 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
1662 ioc->name));
1663 retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
1664 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
1665 ioc->name, retval));
Eric Moorecd2c6192007-01-29 09:47:47 -07001666 goto fail_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 }
1668
Eric Moorecd2c6192007-01-29 09:47:47 -07001669 /*
1670 * Handle success case, see if theres a non-zero ioc_status.
1671 */
1672 if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
1673 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
1674 hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
1675 retval = 0;
1676 else
1677 retval = FAILED;
1678
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 return retval;
Eric Moorecd2c6192007-01-29 09:47:47 -07001680
1681 fail_out:
1682
1683 /*
Joe Perchesfc1323b2008-02-03 17:21:01 +02001684 * Free task management mf, and corresponding tm flags
Eric Moorecd2c6192007-01-29 09:47:47 -07001685 */
Eric Mooree80b0022007-09-14 18:49:03 -06001686 mpt_free_msg_frame(ioc, mf);
Eric Moorecd2c6192007-01-29 09:47:47 -07001687 hd->tmPending = 0;
1688 hd->tmState = TM_STATE_NONE;
1689 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690}
1691
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001692static int
1693mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
1694{
1695 switch (ioc->bus_type) {
1696 case FC:
1697 return 40;
1698 case SAS:
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001699 case SPI:
1700 default:
Bernd Schubert22ab0192008-09-23 15:28:58 +02001701 return 10;
Christoph Hellwigd66c7a02006-01-17 13:43:14 +00001702 }
1703}
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1706/**
1707 * mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
1708 * @SCpnt: Pointer to scsi_cmnd structure, IO to be aborted
1709 *
1710 * (linux scsi_host_template.eh_abort_handler routine)
1711 *
1712 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001713 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001714int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715mptscsih_abort(struct scsi_cmnd * SCpnt)
1716{
1717 MPT_SCSI_HOST *hd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 MPT_FRAME_HDR *mf;
1719 u32 ctx2abort;
1720 int scpnt_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001721 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001722 VirtDevice *vdevice;
Eric Moore3dc0b032006-07-11 17:32:33 -06001723 ulong sn = SCpnt->serial_number;
Eric Moore958d4a32007-06-15 17:24:14 -06001724 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 /* If we can't locate our host adapter structure, return FAILED status.
1727 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001728 if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 SCpnt->result = DID_RESET << 16;
1730 SCpnt->scsi_done(SCpnt);
Eric Moore29dd3602007-09-14 18:46:51 -06001731 printk(KERN_ERR MYNAM ": task abort: "
1732 "can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 return FAILED;
1734 }
1735
Eric Moore958d4a32007-06-15 17:24:14 -06001736 ioc = hd->ioc;
1737 printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
1738 ioc->name, SCpnt);
1739 scsi_print_command(SCpnt);
1740
1741 vdevice = SCpnt->device->hostdata;
1742 if (!vdevice || !vdevice->vtarget) {
Eric Moore29dd3602007-09-14 18:46:51 -06001743 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1744 "task abort: device has been deleted (sc=%p)\n",
1745 ioc->name, SCpnt));
Eric Moore958d4a32007-06-15 17:24:14 -06001746 SCpnt->result = DID_NO_CONNECT << 16;
1747 SCpnt->scsi_done(SCpnt);
1748 retval = 0;
1749 goto out;
1750 }
1751
Eric Moorecc78d302007-06-15 17:27:21 -06001752 /* Task aborts are not supported for hidden raid components.
1753 */
1754 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Moore29dd3602007-09-14 18:46:51 -06001755 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1756 "task abort: hidden raid component (sc=%p)\n",
1757 ioc->name, SCpnt));
Eric Moorecc78d302007-06-15 17:27:21 -06001758 SCpnt->result = DID_RESET << 16;
1759 retval = FAILED;
1760 goto out;
1761 }
1762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 /* Find this command
1764 */
Eric Mooree8206382007-09-29 10:16:53 -06001765 if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001766 /* Cmd not found in ScsiLookup.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 * Do OS callback.
1768 */
1769 SCpnt->result = DID_RESET << 16;
Eric Moore29dd3602007-09-14 18:46:51 -06001770 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
Eric Moore958d4a32007-06-15 17:24:14 -06001771 "Command not in the active list! (sc=%p)\n", ioc->name,
1772 SCpnt));
1773 retval = 0;
1774 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 }
1776
Eric Moore958d4a32007-06-15 17:24:14 -06001777 if (hd->resetPending) {
1778 retval = FAILED;
1779 goto out;
1780 }
Moore, Eric65207fe2006-04-21 16:14:35 -06001781
1782 if (hd->timeouts < -1)
1783 hd->timeouts++;
1784
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05301785 if (mpt_fwfault_debug)
1786 mpt_halt_firmware(ioc);
1787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 /* Most important! Set TaskMsgContext to SCpnt's MsgContext!
1789 * (the IO to be ABORT'd)
1790 *
1791 * NOTE: Since we do not byteswap MsgContext, we do not
1792 * swap it here either. It is an opaque cookie to
1793 * the controller, so it does not matter. -DaveM
1794 */
Eric Mooree80b0022007-09-14 18:49:03 -06001795 mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
1797
1798 hd->abortSCpnt = SCpnt;
1799
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
Eric Moore958d4a32007-06-15 17:24:14 -06001801 vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
1802 ctx2abort, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Eric Mooree8206382007-09-29 10:16:53 -06001804 if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
Eric Moorecd2c6192007-01-29 09:47:47 -07001805 SCpnt->serial_number == sn)
Eric Moore3dc0b032006-07-11 17:32:33 -06001806 retval = FAILED;
Eric Moore3dc0b032006-07-11 17:32:33 -06001807
Eric Moore958d4a32007-06-15 17:24:14 -06001808 out:
1809 printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
1810 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001812 if (retval == 0)
1813 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001814 else
1815 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816}
1817
1818/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1819/**
1820 * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
1821 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1822 *
1823 * (linux scsi_host_template.eh_dev_reset_handler routine)
1824 *
1825 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001826 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001827int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
1829{
1830 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001831 int retval;
Eric Moore958d4a32007-06-15 17:24:14 -06001832 VirtDevice *vdevice;
1833 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
1835 /* If we can't locate our host adapter structure, return FAILED status.
1836 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001837 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001838 printk(KERN_ERR MYNAM ": target reset: "
1839 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 return FAILED;
1841 }
1842
Eric Moore958d4a32007-06-15 17:24:14 -06001843 ioc = hd->ioc;
1844 printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
1845 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001846 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
Eric Moore958d4a32007-06-15 17:24:14 -06001848 if (hd->resetPending) {
1849 retval = FAILED;
1850 goto out;
1851 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001852
Eric Moore958d4a32007-06-15 17:24:14 -06001853 vdevice = SCpnt->device->hostdata;
1854 if (!vdevice || !vdevice->vtarget) {
1855 retval = 0;
1856 goto out;
1857 }
1858
Eric Moorecc78d302007-06-15 17:27:21 -06001859 /* Target reset to hidden raid component is not supported
1860 */
1861 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1862 retval = FAILED;
1863 goto out;
1864 }
1865
Eric Moore958d4a32007-06-15 17:24:14 -06001866 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
1867 vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
1868 mptscsih_get_tm_timeout(ioc));
1869
1870 out:
1871 printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
1872 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001873
1874 if (retval == 0)
1875 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001876 else
1877 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878}
1879
Eric Moorecd2c6192007-01-29 09:47:47 -07001880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1882/**
1883 * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
1884 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1885 *
1886 * (linux scsi_host_template.eh_bus_reset_handler routine)
1887 *
1888 * Returns SUCCESS or FAILED.
Eric Moorecd2c6192007-01-29 09:47:47 -07001889 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001890int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
1892{
1893 MPT_SCSI_HOST *hd;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001894 int retval;
Eric Moorea69de502007-09-14 18:48:19 -06001895 VirtDevice *vdevice;
Eric Moore958d4a32007-06-15 17:24:14 -06001896 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898 /* If we can't locate our host adapter structure, return FAILED status.
1899 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001900 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001901 printk(KERN_ERR MYNAM ": bus reset: "
1902 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 return FAILED;
1904 }
1905
Eric Moore958d4a32007-06-15 17:24:14 -06001906 ioc = hd->ioc;
1907 printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
1908 ioc->name, SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001909 scsi_print_command(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
1911 if (hd->timeouts < -1)
1912 hd->timeouts++;
1913
Eric Moorea69de502007-09-14 18:48:19 -06001914 vdevice = SCpnt->device->hostdata;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001915 retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
Eric Moorea69de502007-09-14 18:48:19 -06001916 vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
Eric Moore958d4a32007-06-15 17:24:14 -06001918 printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
1919 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001920
1921 if (retval == 0)
1922 return SUCCESS;
Eric Moorecd2c6192007-01-29 09:47:47 -07001923 else
1924 return FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925}
1926
1927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1928/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001929 * mptscsih_host_reset - Perform a SCSI host adapter RESET (new_eh variant)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to
1931 *
1932 * (linux scsi_host_template.eh_host_reset_handler routine)
1933 *
1934 * Returns SUCCESS or FAILED.
1935 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04001936int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937mptscsih_host_reset(struct scsi_cmnd *SCpnt)
1938{
1939 MPT_SCSI_HOST * hd;
Eric Moore958d4a32007-06-15 17:24:14 -06001940 int retval;
1941 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943 /* If we can't locate the host to reset, then we failed. */
Eric Mooree7eae9f2007-09-29 10:15:59 -06001944 if ((hd = shost_priv(SCpnt->device->host)) == NULL){
Eric Moore29dd3602007-09-14 18:46:51 -06001945 printk(KERN_ERR MYNAM ": host reset: "
1946 "Can't locate host! (sc=%p)\n", SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return FAILED;
1948 }
1949
James Bottomleya6da74c2008-12-15 14:13:27 -06001950 /* make sure we have no outstanding commands at this stage */
1951 mptscsih_flush_running_cmds(hd);
1952
Eric Moore958d4a32007-06-15 17:24:14 -06001953 ioc = hd->ioc;
1954 printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
1955 ioc->name, SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
1957 /* If our attempts to reset the host failed, then return a failed
1958 * status. The host will be taken off line by the SCSI mid-layer.
1959 */
Eric Mooree80b0022007-09-14 18:49:03 -06001960 if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
Eric Moore958d4a32007-06-15 17:24:14 -06001961 retval = FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 } else {
1963 /* Make sure TM pending is cleared and TM state is set to
1964 * NONE.
1965 */
Eric Moore958d4a32007-06-15 17:24:14 -06001966 retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 hd->tmPending = 0;
1968 hd->tmState = TM_STATE_NONE;
1969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
Eric Moore958d4a32007-06-15 17:24:14 -06001971 printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
1972 ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
Eric Moore958d4a32007-06-15 17:24:14 -06001974 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975}
1976
1977/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1978/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001979 * mptscsih_tm_pending_wait - wait for pending task management request to complete
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 * @hd: Pointer to MPT host structure.
1981 *
1982 * Returns {SUCCESS,FAILED}.
1983 */
1984static int
1985mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
1986{
1987 unsigned long flags;
1988 int loop_count = 4 * 10; /* Wait 10 seconds */
1989 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06001990 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
1992 do {
Eric Mooree80b0022007-09-14 18:49:03 -06001993 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 if (hd->tmState == TM_STATE_NONE) {
1995 hd->tmState = TM_STATE_IN_PROGRESS;
1996 hd->tmPending = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001997 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001998 status = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 break;
2000 }
Eric Mooree80b0022007-09-14 18:49:03 -06002001 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 msleep(250);
2003 } while (--loop_count);
2004
2005 return status;
2006}
2007
2008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2009/**
2010 * mptscsih_tm_wait_for_completion - wait for completion of TM task
2011 * @hd: Pointer to MPT host structure.
Randy Dunlap1544d672007-02-20 11:17:03 -08002012 * @timeout: timeout value
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 *
2014 * Returns {SUCCESS,FAILED}.
2015 */
2016static int
2017mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
2018{
2019 unsigned long flags;
2020 int loop_count = 4 * timeout;
2021 int status = FAILED;
Eric Mooree80b0022007-09-14 18:49:03 -06002022 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 do {
Eric Mooree80b0022007-09-14 18:49:03 -06002025 spin_lock_irqsave(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 if(hd->tmPending == 0) {
2027 status = SUCCESS;
Eric Mooree80b0022007-09-14 18:49:03 -06002028 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 break;
2030 }
Eric Mooree80b0022007-09-14 18:49:03 -06002031 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Michael Reedd6be06c2006-05-24 15:07:57 -05002032 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 } while (--loop_count);
2034
2035 return status;
2036}
2037
2038/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric9f63bb72006-01-16 18:53:26 -07002039static void
2040mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
2041{
2042 char *desc;
2043
2044 switch (response_code) {
2045 case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
2046 desc = "The task completed.";
2047 break;
2048 case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
2049 desc = "The IOC received an invalid frame status.";
2050 break;
2051 case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2052 desc = "The task type is not supported.";
2053 break;
2054 case MPI_SCSITASKMGMT_RSP_TM_FAILED:
2055 desc = "The requested task failed.";
2056 break;
2057 case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2058 desc = "The task completed successfully.";
2059 break;
2060 case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2061 desc = "The LUN request is invalid.";
2062 break;
2063 case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2064 desc = "The task is in the IOC queue and has not been sent to target.";
2065 break;
2066 default:
2067 desc = "unknown";
2068 break;
2069 }
2070 printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
2071 ioc->name, response_code, desc);
2072}
2073
2074/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075/**
2076 * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
2077 * @ioc: Pointer to MPT_ADAPTER structure
2078 * @mf: Pointer to SCSI task mgmt request frame
2079 * @mr: Pointer to SCSI task mgmt reply frame
2080 *
2081 * This routine is called from mptbase.c::mpt_interrupt() at the completion
2082 * of any SCSI task management request.
2083 * This routine is registered with the MPT (base) driver at driver
2084 * load/init time via the mpt_register() API call.
2085 *
2086 * Returns 1 indicating alloc'd request frame ptr should be freed.
Eric Moorecd2c6192007-01-29 09:47:47 -07002087 **/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002088int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2090{
2091 SCSITaskMgmtReply_t *pScsiTmReply;
2092 SCSITaskMgmt_t *pScsiTmReq;
2093 MPT_SCSI_HOST *hd;
2094 unsigned long flags;
2095 u16 iocstatus;
2096 u8 tmType;
Eric Moorecd2c6192007-01-29 09:47:47 -07002097 u32 termination_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302099 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
Eric Moorecd2c6192007-01-29 09:47:47 -07002100 ioc->name, mf, mr));
2101 if (!ioc->sh) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302102 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002103 "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 return 1;
2105 }
2106
2107 if (mr == NULL) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302108 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
Eric Moorecd2c6192007-01-29 09:47:47 -07002109 "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 }
2112
Eric Mooree7eae9f2007-09-29 10:15:59 -06002113 hd = shost_priv(ioc->sh);
Eric Moorecd2c6192007-01-29 09:47:47 -07002114 pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
2115 pScsiTmReq = (SCSITaskMgmt_t*)mf;
2116 tmType = pScsiTmReq->TaskType;
2117 iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2118 termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
2119
2120 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
2121 pScsiTmReply->ResponseCode)
2122 mptscsih_taskmgmt_response_code(ioc,
2123 pScsiTmReply->ResponseCode);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302124 DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
Eric Moorecd2c6192007-01-29 09:47:47 -07002125
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302126#ifdef CONFIG_FUSION_LOGGING
2127 if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
2128 (ioc->debug_level & MPT_DEBUG_TM ))
2129 printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
2130 "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002131 "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302132 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
2133 le16_to_cpu(pScsiTmReply->IOCStatus),
2134 le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
2135 le32_to_cpu(pScsiTmReply->TerminationCount));
Eric Moorecd2c6192007-01-29 09:47:47 -07002136#endif
2137 if (!iocstatus) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302138 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
Eric Moorecd2c6192007-01-29 09:47:47 -07002139 hd->abortSCpnt = NULL;
2140 goto out;
2141 }
2142
2143 /* Error? (anything non-zero?) */
2144
2145 /* clear flags and continue.
2146 */
2147 switch (tmType) {
2148
2149 case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2150 if (termination_count == 1)
2151 iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
2152 hd->abortSCpnt = NULL;
2153 break;
2154
2155 case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
2156
2157 /* If an internal command is present
2158 * or the TM failed - reload the FW.
2159 * FC FW may respond FAILED to an ABORT
2160 */
2161 if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
2162 hd->cmdPtr)
2163 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
Eric Moore29dd3602007-09-14 18:46:51 -06002164 printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
Eric Moorecd2c6192007-01-29 09:47:47 -07002165 break;
2166
2167 case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2168 default:
2169 break;
2170 }
2171
2172 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 spin_lock_irqsave(&ioc->FreeQlock, flags);
2174 hd->tmPending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 hd->tmState = TM_STATE_NONE;
Eric Moorecd2c6192007-01-29 09:47:47 -07002176 hd->tm_iocstatus = iocstatus;
2177 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
2179 return 1;
2180}
2181
2182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2183/*
2184 * This is anyones guess quite frankly.
2185 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002186int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
2188 sector_t capacity, int geom[])
2189{
2190 int heads;
2191 int sectors;
2192 sector_t cylinders;
2193 ulong dummy;
2194
2195 heads = 64;
2196 sectors = 32;
2197
2198 dummy = heads * sectors;
2199 cylinders = capacity;
2200 sector_div(cylinders,dummy);
2201
2202 /*
2203 * Handle extended translation size for logical drives
2204 * > 1Gb
2205 */
2206 if ((ulong)capacity >= 0x200000) {
2207 heads = 255;
2208 sectors = 63;
2209 dummy = heads * sectors;
2210 cylinders = capacity;
2211 sector_div(cylinders,dummy);
2212 }
2213
2214 /* return result */
2215 geom[0] = heads;
2216 geom[1] = sectors;
2217 geom[2] = cylinders;
2218
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return 0;
2220}
2221
Moore, Ericf44e5462006-03-14 09:14:21 -07002222/* Search IOC page 3 to determine if this is hidden physical disk
2223 *
2224 */
2225int
Eric Moore793955f2007-01-29 09:42:20 -07002226mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
Moore, Ericf44e5462006-03-14 09:14:21 -07002227{
Eric Mooreb506ade2007-01-29 09:45:37 -07002228 struct inactive_raid_component_info *component_info;
Moore, Ericf44e5462006-03-14 09:14:21 -07002229 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002230 int rc = 0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002231
Eric Moore793955f2007-01-29 09:42:20 -07002232 if (!ioc->raid_data.pIocPg3)
2233 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002234 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
Eric Moore793955f2007-01-29 09:42:20 -07002235 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2236 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2237 rc = 1;
2238 goto out;
2239 }
2240 }
2241
Eric Mooreb506ade2007-01-29 09:45:37 -07002242 /*
2243 * Check inactive list for matching phys disks
2244 */
2245 if (list_empty(&ioc->raid_data.inactive_list))
2246 goto out;
2247
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002248 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002249 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2250 list) {
2251 if ((component_info->d.PhysDiskID == id) &&
2252 (component_info->d.PhysDiskBus == channel))
2253 rc = 1;
2254 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002255 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002256
Eric Moore793955f2007-01-29 09:42:20 -07002257 out:
2258 return rc;
Moore, Ericf44e5462006-03-14 09:14:21 -07002259}
2260EXPORT_SYMBOL(mptscsih_is_phys_disk);
2261
Eric Moore793955f2007-01-29 09:42:20 -07002262u8
2263mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -06002264{
Eric Mooreb506ade2007-01-29 09:45:37 -07002265 struct inactive_raid_component_info *component_info;
James Bottomleyc92f2222006-03-01 09:02:49 -06002266 int i;
Eric Moore793955f2007-01-29 09:42:20 -07002267 int rc = -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -06002268
Eric Moore793955f2007-01-29 09:42:20 -07002269 if (!ioc->raid_data.pIocPg3)
2270 goto out;
2271 for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
2272 if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
2273 (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
2274 rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
2275 goto out;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002276 }
2277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
Eric Mooreb506ade2007-01-29 09:45:37 -07002279 /*
2280 * Check inactive list for matching phys disks
2281 */
2282 if (list_empty(&ioc->raid_data.inactive_list))
2283 goto out;
2284
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002285 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002286 list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
2287 list) {
2288 if ((component_info->d.PhysDiskID == id) &&
2289 (component_info->d.PhysDiskBus == channel))
2290 rc = component_info->d.PhysDiskNum;
2291 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002292 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002293
Eric Moore793955f2007-01-29 09:42:20 -07002294 out:
2295 return rc;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002296}
Eric Moore793955f2007-01-29 09:42:20 -07002297EXPORT_SYMBOL(mptscsih_raid_id_to_num);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002298
2299/*
2300 * OS entry point to allow for host driver to free allocated memory
2301 * Called if no device present or device being unloaded
2302 */
2303void
2304mptscsih_slave_destroy(struct scsi_device *sdev)
2305{
2306 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002307 MPT_SCSI_HOST *hd = shost_priv(host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002308 VirtTarget *vtarget;
2309 VirtDevice *vdevice;
2310 struct scsi_target *starget;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002312 starget = scsi_target(sdev);
2313 vtarget = starget->hostdata;
2314 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002316 mptscsih_search_running_cmds(hd, vdevice);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002317 vtarget->num_luns--;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002318 mptscsih_synchronize_cache(hd, vdevice);
2319 kfree(vdevice);
2320 sdev->hostdata = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321}
2322
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002323/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2324/*
2325 * mptscsih_change_queue_depth - This function will set a devices queue depth
2326 * @sdev: per scsi_device pointer
2327 * @qdepth: requested queue depth
2328 *
2329 * Adding support for new 'change_queue_depth' api.
2330*/
2331int
2332mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333{
Eric Mooree7eae9f2007-09-29 10:15:59 -06002334 MPT_SCSI_HOST *hd = shost_priv(sdev->host);
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002335 VirtTarget *vtarget;
2336 struct scsi_target *starget;
2337 int max_depth;
2338 int tagged;
Eric Mooree80b0022007-09-14 18:49:03 -06002339 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002341 starget = scsi_target(sdev);
2342 vtarget = starget->hostdata;
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002343
Eric Mooree80b0022007-09-14 18:49:03 -06002344 if (ioc->bus_type == SPI) {
James Bottomleyc92f2222006-03-01 09:02:49 -06002345 if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 max_depth = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06002347 else if (sdev->type == TYPE_DISK &&
2348 vtarget->minSyncFactor <= MPT_ULTRA160)
2349 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2350 else
2351 max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 } else
2353 max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
2354
2355 if (qdepth > max_depth)
2356 qdepth = max_depth;
2357 if (qdepth == 1)
2358 tagged = 0;
2359 else
2360 tagged = MSG_SIMPLE_TAG;
2361
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06002362 scsi_adjust_queue_depth(sdev, tagged, qdepth);
2363 return sdev->queue_depth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364}
2365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366/*
2367 * OS entry point to adjust the queue_depths on a per-device basis.
2368 * Called once per device the bus scan. Use it to force the queue_depth
2369 * member to 1 if a device does not support Q tags.
2370 * Return non-zero if fails.
2371 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002372int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002373mptscsih_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002375 struct Scsi_Host *sh = sdev->host;
2376 VirtTarget *vtarget;
2377 VirtDevice *vdevice;
2378 struct scsi_target *starget;
Eric Mooree7eae9f2007-09-29 10:15:59 -06002379 MPT_SCSI_HOST *hd = shost_priv(sh);
Eric Mooree80b0022007-09-14 18:49:03 -06002380 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002382 starget = scsi_target(sdev);
2383 vtarget = starget->hostdata;
2384 vdevice = sdev->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
Eric Mooree80b0022007-09-14 18:49:03 -06002386 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore793955f2007-01-29 09:42:20 -07002387 "device @ %p, channel=%d, id=%d, lun=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002388 ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
2389 if (ioc->bus_type == SPI)
2390 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002391 "sdtr %d wdtr %d ppr %d inq length=%d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002392 ioc->name, sdev->sdtr, sdev->wdtr,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002393 sdev->ppr, sdev->inquiry_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
Eric Moore793955f2007-01-29 09:42:20 -07002395 vdevice->configured_lun = 1;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002396 mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Eric Mooree80b0022007-09-14 18:49:03 -06002398 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 "Queue depth=%d, tflags=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002400 ioc->name, sdev->queue_depth, vtarget->tflags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
Eric Mooree80b0022007-09-14 18:49:03 -06002402 if (ioc->bus_type == SPI)
2403 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002404 "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002405 ioc->name, vtarget->negoFlags, vtarget->maxOffset,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002406 vtarget->minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
Eric Mooree80b0022007-09-14 18:49:03 -06002408 dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 "tagged %d, simple %d, ordered %d\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002410 ioc->name,sdev->tagged_supported, sdev->simple_tags,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07002411 sdev->ordered_tags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 return 0;
2414}
2415
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2417/*
2418 * Private routines...
2419 */
2420
2421/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2422/* Utility function to copy sense data from the scsi_cmnd buffer
2423 * to the FC and SCSI target structures.
2424 *
2425 */
2426static void
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002427mptscsih_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 -07002428{
Eric Moorea69de502007-09-14 18:48:19 -06002429 VirtDevice *vdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 SCSIIORequest_t *pReq;
2431 u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
Eric Mooree80b0022007-09-14 18:49:03 -06002432 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 /* Get target structure
2435 */
2436 pReq = (SCSIIORequest_t *) mf;
Eric Moorea69de502007-09-14 18:48:19 -06002437 vdevice = sc->device->hostdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
2439 if (sense_count) {
2440 u8 *sense_data;
2441 int req_index;
2442
2443 /* Copy the sense received into the scsi command block. */
2444 req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree80b0022007-09-14 18:49:03 -06002445 sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
2447
2448 /* Log SMART data (asc = 0x5D, non-IM case only) if required.
2449 */
Eric Mooree80b0022007-09-14 18:49:03 -06002450 if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
Eric Moorea69de502007-09-14 18:48:19 -06002451 if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 int idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07002454 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
2456 ioc->events[idx].eventContext = ioc->eventContext;
2457
Dave Jones3d9780b2007-05-21 20:59:47 -04002458 ioc->events[idx].data[0] = (pReq->LUN[1] << 24) |
2459 (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) |
2460 (sc->device->channel << 8) | sc->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Dave Jones3d9780b2007-05-21 20:59:47 -04002462 ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464 ioc->eventContext++;
Eric Mooree80b0022007-09-14 18:49:03 -06002465 if (ioc->pcidev->vendor ==
Eric Moore786899b2006-07-11 17:22:22 -06002466 PCI_VENDOR_ID_IBM) {
Eric Mooree80b0022007-09-14 18:49:03 -06002467 mptscsih_issue_sep_command(ioc,
Eric Moorea69de502007-09-14 18:48:19 -06002468 vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
2469 vdevice->vtarget->tflags |=
Eric Moore786899b2006-07-11 17:22:22 -06002470 MPT_TARGET_FLAGS_LED_ON;
2471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 }
2473 }
2474 } else {
Eric Mooree80b0022007-09-14 18:49:03 -06002475 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
2476 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
2478}
2479
Eric Mooree8206382007-09-29 10:16:53 -06002480/**
2481 * mptscsih_get_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002482 * @ioc: Pointer to MPT_ADAPTER structure
2483 * @i: index into the array
2484 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002485 * retrieves scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002486 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002487 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002488 **/
2489static struct scsi_cmnd *
2490mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491{
Eric Mooree8206382007-09-29 10:16:53 -06002492 unsigned long flags;
2493 struct scsi_cmnd *scmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
Eric Mooree8206382007-09-29 10:16:53 -06002495 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2496 scmd = ioc->ScsiLookup[i];
2497 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Eric Mooree8206382007-09-29 10:16:53 -06002499 return scmd;
2500}
2501
2502/**
2503 * mptscsih_getclear_scsi_lookup
Eric Mooree8206382007-09-29 10:16:53 -06002504 * @ioc: Pointer to MPT_ADAPTER structure
2505 * @i: index into the array
2506 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002507 * retrieves and clears scmd entry from ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002508 *
Randy Dunlap7105a382008-02-29 22:03:27 -08002509 * Returns the scsi_cmd pointer
Eric Mooree8206382007-09-29 10:16:53 -06002510 **/
2511static struct scsi_cmnd *
2512mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
2513{
2514 unsigned long flags;
2515 struct scsi_cmnd *scmd;
2516
2517 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2518 scmd = ioc->ScsiLookup[i];
2519 ioc->ScsiLookup[i] = NULL;
2520 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2521
2522 return scmd;
2523}
2524
2525/**
2526 * mptscsih_set_scsi_lookup
2527 *
2528 * writes a scmd entry into the ScsiLookup[] array list
2529 *
2530 * @ioc: Pointer to MPT_ADAPTER structure
2531 * @i: index into the array
2532 * @scmd: scsi_cmnd pointer
2533 *
2534 **/
2535static void
2536mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
2537{
2538 unsigned long flags;
2539
2540 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2541 ioc->ScsiLookup[i] = scmd;
2542 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2543}
2544
2545/**
Randy Dunlap23f9b752007-10-15 17:29:33 -07002546 * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
Eric Mooree8206382007-09-29 10:16:53 -06002547 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap23f9b752007-10-15 17:29:33 -07002548 * @sc: scsi_cmnd pointer
2549 */
Eric Mooree8206382007-09-29 10:16:53 -06002550static int
2551SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
2552{
2553 unsigned long flags;
2554 int i, index=-1;
2555
2556 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
2557 for (i = 0; i < ioc->req_depth; i++) {
2558 if (ioc->ScsiLookup[i] == sc) {
2559 index = i;
2560 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 }
2562 }
2563
Eric Mooree8206382007-09-29 10:16:53 -06002564 out:
2565 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
2566 return index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567}
2568
2569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002570int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
2572{
2573 MPT_SCSI_HOST *hd;
2574 unsigned long flags;
2575
Eric Moore29dd3602007-09-14 18:46:51 -06002576 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2577 ": IOC %s_reset routed to SCSI host driver!\n",
2578 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
2579 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 /* If a FW reload request arrives after base installed but
2582 * before all scsi hosts have been attached, then an alt_ioc
2583 * may have a NULL sh pointer.
2584 */
Eric Mooree7eae9f2007-09-29 10:15:59 -06002585 if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 return 0;
2587 else
Eric Mooree7eae9f2007-09-29 10:15:59 -06002588 hd = shost_priv(ioc->sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
2590 if (reset_phase == MPT_IOC_SETUP_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302591 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
2593 /* Clean Up:
2594 * 1. Set Hard Reset Pending Flag
2595 * All new commands go to doneQ
2596 */
2597 hd->resetPending = 1;
2598
2599 } else if (reset_phase == MPT_IOC_PRE_RESET) {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302600 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
2602 /* 2. Flush running commands
2603 * Clean ScsiLookup (and associated memory)
2604 * AND clean mytaskQ
2605 */
2606
2607 /* 2b. Reply to OS all known outstanding I/O commands.
2608 */
2609 mptscsih_flush_running_cmds(hd);
2610
2611 /* 2c. If there was an internal command that
2612 * has not completed, configuration or io request,
2613 * free these resources.
2614 */
2615 if (hd->cmdPtr) {
2616 del_timer(&hd->timer);
2617 mpt_free_msg_frame(ioc, hd->cmdPtr);
2618 }
2619
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302620 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
2622 } else {
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302623 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 /* Once a FW reload begins, all new OS commands are
2626 * redirected to the doneQ w/ a reset status.
2627 * Init all control structures.
2628 */
2629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 /* 2. Chain Buffer initialization
2631 */
2632
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002633 /* 4. Renegotiate to all devices, if SPI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 /* 5. Enable new commands to be posted
2637 */
2638 spin_lock_irqsave(&ioc->FreeQlock, flags);
2639 hd->tmPending = 0;
2640 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2641 hd->resetPending = 0;
2642 hd->tmState = TM_STATE_NONE;
2643
2644 /* 6. If there was an internal command,
2645 * wake this process up.
2646 */
2647 if (hd->cmdPtr) {
2648 /*
2649 * Wake up the original calling thread
2650 */
2651 hd->pLocal = &hd->localReply;
2652 hd->pLocal->completion = MPT_SCANDV_DID_RESET;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002653 hd->scandv_wait_done = 1;
2654 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 hd->cmdPtr = NULL;
2656 }
2657
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302658 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
2660 }
2661
2662 return 1; /* currently means nothing really */
2663}
2664
2665/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002666int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
2668{
2669 MPT_SCSI_HOST *hd;
2670 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
2671
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302672 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 ioc->name, event));
2674
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002675 if (ioc->sh == NULL ||
Eric Mooree7eae9f2007-09-29 10:15:59 -06002676 ((hd = shost_priv(ioc->sh)) == NULL))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002677 return 1;
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 switch (event) {
2680 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
2681 /* FIXME! */
2682 break;
2683 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
2684 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07002685 if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002686 hd->soft_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 break;
2688 case MPI_EVENT_LOGOUT: /* 09 */
2689 /* FIXME! */
2690 break;
2691
Michael Reed05e8ec12006-01-13 14:31:54 -06002692 case MPI_EVENT_RESCAN: /* 06 */
Michael Reed05e8ec12006-01-13 14:31:54 -06002693 break;
2694
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 /*
2696 * CHECKME! Don't think we need to do
2697 * anything for these, but...
2698 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
2700 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
2701 /*
2702 * CHECKME! Falling thru...
2703 */
2704 break;
2705
2706 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002707 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 case MPI_EVENT_NONE: /* 00 */
2710 case MPI_EVENT_LOG_DATA: /* 01 */
2711 case MPI_EVENT_STATE_CHANGE: /* 02 */
2712 case MPI_EVENT_EVENT_CHANGE: /* 0A */
2713 default:
Eric Moore29dd3602007-09-14 18:46:51 -06002714 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
2715 ioc->name, event));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 break;
2717 }
2718
2719 return 1; /* currently means nothing really */
2720}
2721
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2723/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 * Bus Scan and Domain Validation functionality ...
2725 */
2726
2727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2728/*
2729 * mptscsih_scandv_complete - Scan and DV callback routine registered
2730 * to Fustion MPT (base) driver.
2731 *
2732 * @ioc: Pointer to MPT_ADAPTER structure
2733 * @mf: Pointer to original MPT request frame
2734 * @mr: Pointer to MPT reply frame (NULL if TurboReply)
2735 *
2736 * This routine is called from mpt.c::mpt_interrupt() at the completion
2737 * of any SCSI IO request.
2738 * This routine is registered with the Fusion MPT (base) driver at driver
2739 * load/init time via the mpt_register() API call.
2740 *
2741 * Returns 1 indicating alloc'd request frame ptr should be freed.
2742 *
2743 * Remark: Sets a completion code and (possibly) saves sense data
2744 * in the IOC member localReply structure.
2745 * Used ONLY for DV and other internal commands.
2746 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002747int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
2749{
2750 MPT_SCSI_HOST *hd;
2751 SCSIIORequest_t *pReq;
2752 int completionCode;
2753 u16 req_idx;
2754
Eric Mooree7eae9f2007-09-29 10:15:59 -06002755 hd = shost_priv(ioc->sh);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002756
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 if ((mf == NULL) ||
2758 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
2759 printk(MYIOC_s_ERR_FMT
2760 "ScanDvComplete, %s req frame ptr! (=%p)\n",
2761 ioc->name, mf?"BAD":"NULL", (void *) mf);
2762 goto wakeup;
2763 }
2764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 del_timer(&hd->timer);
2766 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
Eric Mooree8206382007-09-29 10:16:53 -06002767 mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 pReq = (SCSIIORequest_t *) mf;
2769
2770 if (mf != hd->cmdPtr) {
2771 printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002772 ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 }
2774 hd->cmdPtr = NULL;
2775
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05302776 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
Eric Mooree80b0022007-09-14 18:49:03 -06002777 ioc->name, mf, mr, req_idx));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
2779 hd->pLocal = &hd->localReply;
2780 hd->pLocal->scsiStatus = 0;
2781
2782 /* If target struct exists, clear sense valid flag.
2783 */
2784 if (mr == NULL) {
2785 completionCode = MPT_SCANDV_GOOD;
2786 } else {
2787 SCSIIOReply_t *pReply;
2788 u16 status;
2789 u8 scsi_status;
2790
2791 pReply = (SCSIIOReply_t *) mr;
2792
2793 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
2794 scsi_status = pReply->SCSIStatus;
2795
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797 switch(status) {
2798
2799 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
2800 completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
2801 break;
2802
2803 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
2804 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
2805 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
2806 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
2807 completionCode = MPT_SCANDV_DID_RESET;
2808 break;
2809
2810 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
2811 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
2812 case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
2813 if (pReply->Function == MPI_FUNCTION_CONFIG) {
2814 ConfigReply_t *pr = (ConfigReply_t *)mr;
2815 completionCode = MPT_SCANDV_GOOD;
2816 hd->pLocal->header.PageVersion = pr->Header.PageVersion;
2817 hd->pLocal->header.PageLength = pr->Header.PageLength;
2818 hd->pLocal->header.PageNumber = pr->Header.PageNumber;
2819 hd->pLocal->header.PageType = pr->Header.PageType;
2820
2821 } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
2822 /* If the RAID Volume request is successful,
2823 * return GOOD, else indicate that
2824 * some type of error occurred.
2825 */
2826 MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
Christoph Hellwig637fa992005-08-18 16:25:44 +02002827 if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 completionCode = MPT_SCANDV_GOOD;
2829 else
2830 completionCode = MPT_SCANDV_SOME_ERROR;
James Bottomleyc92f2222006-03-01 09:02:49 -06002831 memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
2833 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
2834 u8 *sense_data;
2835 int sz;
2836
2837 /* save sense data in global structure
2838 */
2839 completionCode = MPT_SCANDV_SENSE;
2840 hd->pLocal->scsiStatus = scsi_status;
Eric Mooree80b0022007-09-14 18:49:03 -06002841 sense_data = ((u8 *)ioc->sense_buf_pool +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 (req_idx * MPT_SENSE_BUFFER_ALLOC));
2843
2844 sz = min_t(int, pReq->SenseBufferLength,
2845 SCSI_STD_SENSE_BYTES);
2846 memcpy(hd->pLocal->sense, sense_data, sz);
2847
Eric Moore29dd3602007-09-14 18:46:51 -06002848 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
2849 ioc->name, sense_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
2851 if (pReq->CDB[0] == INQUIRY)
2852 completionCode = MPT_SCANDV_ISSUE_SENSE;
2853 else
2854 completionCode = MPT_SCANDV_DID_RESET;
2855 }
2856 else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
2857 completionCode = MPT_SCANDV_DID_RESET;
2858 else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2859 completionCode = MPT_SCANDV_DID_RESET;
2860 else {
2861 completionCode = MPT_SCANDV_GOOD;
2862 hd->pLocal->scsiStatus = scsi_status;
2863 }
2864 break;
2865
2866 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
2867 if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
2868 completionCode = MPT_SCANDV_DID_RESET;
2869 else
2870 completionCode = MPT_SCANDV_SOME_ERROR;
2871 break;
2872
2873 default:
2874 completionCode = MPT_SCANDV_SOME_ERROR;
2875 break;
2876
2877 } /* switch(status) */
2878
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 } /* end of address reply case */
2880
2881 hd->pLocal->completion = completionCode;
2882
2883 /* MF and RF are freed in mpt_interrupt
2884 */
2885wakeup:
2886 /* Free Chain buffers (will never chain) in scan or dv */
2887 //mptscsih_freeChainBuffers(ioc, req_idx);
2888
2889 /*
2890 * Wake up the original calling thread
2891 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002892 hd->scandv_wait_done = 1;
2893 wake_up(&hd->scandv_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 return 1;
2896}
2897
2898/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2899/* mptscsih_timer_expired - Call back for timer process.
2900 * Used only for dv functionality.
2901 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
2902 *
2903 */
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04002904void
2905mptscsih_timer_expired(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906{
2907 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
Eric Mooree80b0022007-09-14 18:49:03 -06002908 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
Eric Mooree80b0022007-09-14 18:49:03 -06002910 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
2912 if (hd->cmdPtr) {
2913 MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
2914
2915 if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
2916 /* Desire to issue a task management request here.
2917 * TM requests MUST be single threaded.
2918 * If old eh code and no TM current, issue request.
2919 * If new eh code, do nothing. Wait for OS cmd timeout
2920 * for bus reset.
2921 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 } else {
2923 /* Perform a FW reload */
Eric Mooree80b0022007-09-14 18:49:03 -06002924 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
2925 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 }
2927 }
2928 } else {
2929 /* This should NEVER happen */
Eric Mooree80b0022007-09-14 18:49:03 -06002930 printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 }
2932
2933 /* No more processing.
2934 * TM call will generate an interrupt for SCSI TM Management.
2935 * The FW will reply to all outstanding commands, callback will finish cleanup.
2936 * Hard reset clean-up will free all resources.
2937 */
Eric Mooree80b0022007-09-14 18:49:03 -06002938 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939
2940 return;
2941}
2942
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
2944/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2945/**
2946 * mptscsih_do_cmd - Do internal command.
2947 * @hd: MPT_SCSI_HOST pointer
2948 * @io: INTERNAL_CMD pointer.
2949 *
2950 * Issue the specified internally generated command and do command
2951 * specific cleanup. For bus scan / DV only.
2952 * NOTES: If command is Inquiry and status is good,
2953 * initialize a target structure, save the data
2954 *
2955 * Remark: Single threaded access only.
2956 *
2957 * Return:
2958 * < 0 if an illegal command or no resources
2959 *
2960 * 0 if good
2961 *
2962 * > 0 if command complete but some type of completion error.
2963 */
2964static int
2965mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
2966{
2967 MPT_FRAME_HDR *mf;
2968 SCSIIORequest_t *pScsiReq;
2969 SCSIIORequest_t ReqCopy;
2970 int my_idx, ii, dir;
2971 int rc, cmdTimeout;
2972 int in_isr;
2973 char cmdLen;
2974 char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
2975 char cmd = io->cmd;
Eric Mooree80b0022007-09-14 18:49:03 -06002976 MPT_ADAPTER *ioc = hd->ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
2978 in_isr = in_interrupt();
2979 if (in_isr) {
Eric Mooree80b0022007-09-14 18:49:03 -06002980 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
2981 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return -EPERM;
2983 }
2984
2985
2986 /* Set command specific information
2987 */
2988 switch (cmd) {
2989 case INQUIRY:
2990 cmdLen = 6;
2991 dir = MPI_SCSIIO_CONTROL_READ;
2992 CDB[0] = cmd;
2993 CDB[4] = io->size;
2994 cmdTimeout = 10;
2995 break;
2996
2997 case TEST_UNIT_READY:
2998 cmdLen = 6;
2999 dir = MPI_SCSIIO_CONTROL_READ;
3000 cmdTimeout = 10;
3001 break;
3002
3003 case START_STOP:
3004 cmdLen = 6;
3005 dir = MPI_SCSIIO_CONTROL_READ;
3006 CDB[0] = cmd;
3007 CDB[4] = 1; /*Spin up the disk */
3008 cmdTimeout = 15;
3009 break;
3010
3011 case REQUEST_SENSE:
3012 cmdLen = 6;
3013 CDB[0] = cmd;
3014 CDB[4] = io->size;
3015 dir = MPI_SCSIIO_CONTROL_READ;
3016 cmdTimeout = 10;
3017 break;
3018
3019 case READ_BUFFER:
3020 cmdLen = 10;
3021 dir = MPI_SCSIIO_CONTROL_READ;
3022 CDB[0] = cmd;
3023 if (io->flags & MPT_ICFLAG_ECHO) {
3024 CDB[1] = 0x0A;
3025 } else {
3026 CDB[1] = 0x02;
3027 }
3028
3029 if (io->flags & MPT_ICFLAG_BUF_CAP) {
3030 CDB[1] |= 0x01;
3031 }
3032 CDB[6] = (io->size >> 16) & 0xFF;
3033 CDB[7] = (io->size >> 8) & 0xFF;
3034 CDB[8] = io->size & 0xFF;
3035 cmdTimeout = 10;
3036 break;
3037
3038 case WRITE_BUFFER:
3039 cmdLen = 10;
3040 dir = MPI_SCSIIO_CONTROL_WRITE;
3041 CDB[0] = cmd;
3042 if (io->flags & MPT_ICFLAG_ECHO) {
3043 CDB[1] = 0x0A;
3044 } else {
3045 CDB[1] = 0x02;
3046 }
3047 CDB[6] = (io->size >> 16) & 0xFF;
3048 CDB[7] = (io->size >> 8) & 0xFF;
3049 CDB[8] = io->size & 0xFF;
3050 cmdTimeout = 10;
3051 break;
3052
3053 case RESERVE:
3054 cmdLen = 6;
3055 dir = MPI_SCSIIO_CONTROL_READ;
3056 CDB[0] = cmd;
3057 cmdTimeout = 10;
3058 break;
3059
3060 case RELEASE:
3061 cmdLen = 6;
3062 dir = MPI_SCSIIO_CONTROL_READ;
3063 CDB[0] = cmd;
3064 cmdTimeout = 10;
3065 break;
3066
3067 case SYNCHRONIZE_CACHE:
3068 cmdLen = 10;
3069 dir = MPI_SCSIIO_CONTROL_READ;
3070 CDB[0] = cmd;
3071// CDB[1] = 0x02; /* set immediate bit */
3072 cmdTimeout = 10;
3073 break;
3074
3075 default:
3076 /* Error Case */
3077 return -EFAULT;
3078 }
3079
3080 /* Get and Populate a free Frame
3081 */
Eric Mooree80b0022007-09-14 18:49:03 -06003082 if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
3083 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
3084 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 return -EBUSY;
3086 }
3087
3088 pScsiReq = (SCSIIORequest_t *) mf;
3089
3090 /* Get the request index */
3091 my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
3092 ADD_INDEX_LOG(my_idx); /* for debug */
3093
3094 if (io->flags & MPT_ICFLAG_PHYS_DISK) {
3095 pScsiReq->TargetID = io->physDiskNum;
3096 pScsiReq->Bus = 0;
3097 pScsiReq->ChainOffset = 0;
3098 pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3099 } else {
3100 pScsiReq->TargetID = io->id;
Eric Moore793955f2007-01-29 09:42:20 -07003101 pScsiReq->Bus = io->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 pScsiReq->ChainOffset = 0;
3103 pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
3104 }
3105
3106 pScsiReq->CDBLength = cmdLen;
3107 pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
3108
3109 pScsiReq->Reserved = 0;
3110
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303111 pScsiReq->MsgFlags = mpt_msg_flags(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 /* MsgContext set in mpt_get_msg_fram call */
3113
Eric Moore793955f2007-01-29 09:42:20 -07003114 int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
3116 if (io->flags & MPT_ICFLAG_TAGGED_CMD)
3117 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
3118 else
3119 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
3120
3121 if (cmd == REQUEST_SENSE) {
3122 pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
Eric Mooree80b0022007-09-14 18:49:03 -06003123 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
3124 ioc->name, cmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 }
3126
3127 for (ii=0; ii < 16; ii++)
3128 pScsiReq->CDB[ii] = CDB[ii];
3129
3130 pScsiReq->DataLength = cpu_to_le32(io->size);
Eric Mooree80b0022007-09-14 18:49:03 -06003131 pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 + (my_idx * MPT_SENSE_BUFFER_ALLOC));
3133
Eric Mooree80b0022007-09-14 18:49:03 -06003134 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
3135 ioc->name, cmd, io->channel, io->id, io->lun));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136
3137 if (dir == MPI_SCSIIO_CONTROL_READ) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303138 ioc->add_sge((char *) &pScsiReq->SGL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
3140 io->data_dma);
3141 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303142 ioc->add_sge((char *) &pScsiReq->SGL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
3144 io->data_dma);
3145 }
3146
3147 /* The ISR will free the request frame, but we need
3148 * the information to initialize the target. Duplicate.
3149 */
3150 memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
3151
3152 /* Issue this command after:
3153 * finish init
3154 * add timer
3155 * Wait until the reply has been received
3156 * ScsiScanDvCtx callback function will
3157 * set hd->pLocal;
3158 * set scandv_wait_done and call wake_up
3159 */
3160 hd->pLocal = NULL;
3161 hd->timer.expires = jiffies + HZ*cmdTimeout;
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003162 hd->scandv_wait_done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
3164 /* Save cmd pointer, for resource free if timeout or
3165 * FW reload occurs
3166 */
3167 hd->cmdPtr = mf;
3168
3169 add_timer(&hd->timer);
Eric Mooree80b0022007-09-14 18:49:03 -06003170 mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003171 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
3173 if (hd->pLocal) {
3174 rc = hd->pLocal->completion;
3175 hd->pLocal->skip = 0;
3176
3177 /* Always set fatal error codes in some cases.
3178 */
3179 if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
3180 rc = -ENXIO;
3181 else if (rc == MPT_SCANDV_SOME_ERROR)
3182 rc = -rc;
3183 } else {
3184 rc = -EFAULT;
3185 /* This should never happen. */
Eric Mooree80b0022007-09-14 18:49:03 -06003186 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
3187 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 }
3189
3190 return rc;
3191}
3192
3193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3194/**
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003195 * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
3196 * @hd: Pointer to a SCSI HOST structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003197 * @vdevice: virtual target device
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07003198 *
3199 * Uses the ISR, but with special processing.
3200 * MUST be single-threaded.
3201 *
3202 */
3203static void
3204mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
3205{
3206 INTERNAL_CMD iocmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Eric Moorecc78d302007-06-15 17:27:21 -06003208 /* Ignore hidden raid components, this is handled when the command
3209 * is sent to the volume
3210 */
3211 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
3212 return;
3213
3214 if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
3215 !vdevice->configured_lun)
3216 return;
3217
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 /* Following parameters will not change
3219 * in this routine.
3220 */
3221 iocmd.cmd = SYNCHRONIZE_CACHE;
3222 iocmd.flags = 0;
3223 iocmd.physDiskNum = -1;
3224 iocmd.data = NULL;
3225 iocmd.data_dma = -1;
3226 iocmd.size = 0;
3227 iocmd.rsvd = iocmd.rsvd2 = 0;
Eric Moore793955f2007-01-29 09:42:20 -07003228 iocmd.channel = vdevice->vtarget->channel;
3229 iocmd.id = vdevice->vtarget->id;
3230 iocmd.lun = vdevice->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
Eric Moorecc78d302007-06-15 17:27:21 -06003232 mptscsih_do_cmd(hd, &iocmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233}
3234
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303235static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003236mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr,
3237 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303238{
Tony Jonesee959b02008-02-22 00:13:36 +01003239 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003240 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303241 MPT_ADAPTER *ioc = hd->ioc;
3242
3243 return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
3244 (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
3245 (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
3246 (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
3247 ioc->facts.FWVersion.Word & 0x000000FF);
3248}
Tony Jonesee959b02008-02-22 00:13:36 +01003249static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303250
3251static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003252mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr,
3253 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303254{
Tony Jonesee959b02008-02-22 00:13:36 +01003255 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003256 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303257 MPT_ADAPTER *ioc = hd->ioc;
3258
3259 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
3260 (ioc->biosVersion & 0xFF000000) >> 24,
3261 (ioc->biosVersion & 0x00FF0000) >> 16,
3262 (ioc->biosVersion & 0x0000FF00) >> 8,
3263 ioc->biosVersion & 0x000000FF);
3264}
Tony Jonesee959b02008-02-22 00:13:36 +01003265static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303266
3267static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003268mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr,
3269 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303270{
Tony Jonesee959b02008-02-22 00:13:36 +01003271 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003272 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303273 MPT_ADAPTER *ioc = hd->ioc;
3274
3275 return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
3276}
Tony Jonesee959b02008-02-22 00:13:36 +01003277static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303278
3279static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003280mptscsih_version_product_show(struct device *dev,
3281 struct device_attribute *attr,
3282char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303283{
Tony Jonesee959b02008-02-22 00:13:36 +01003284 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003285 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303286 MPT_ADAPTER *ioc = hd->ioc;
3287
3288 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
3289}
Tony Jonesee959b02008-02-22 00:13:36 +01003290static DEVICE_ATTR(version_product, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303291 mptscsih_version_product_show, NULL);
3292
3293static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003294mptscsih_version_nvdata_persistent_show(struct device *dev,
3295 struct device_attribute *attr,
3296 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303297{
Tony Jonesee959b02008-02-22 00:13:36 +01003298 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003299 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303300 MPT_ADAPTER *ioc = hd->ioc;
3301
3302 return snprintf(buf, PAGE_SIZE, "%02xh\n",
3303 ioc->nvdata_version_persistent);
3304}
Tony Jonesee959b02008-02-22 00:13:36 +01003305static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303306 mptscsih_version_nvdata_persistent_show, NULL);
3307
3308static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003309mptscsih_version_nvdata_default_show(struct device *dev,
3310 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303311{
Tony Jonesee959b02008-02-22 00:13:36 +01003312 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003313 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303314 MPT_ADAPTER *ioc = hd->ioc;
3315
3316 return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
3317}
Tony Jonesee959b02008-02-22 00:13:36 +01003318static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303319 mptscsih_version_nvdata_default_show, NULL);
3320
3321static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003322mptscsih_board_name_show(struct device *dev, struct device_attribute *attr,
3323 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303324{
Tony Jonesee959b02008-02-22 00:13:36 +01003325 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003326 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303327 MPT_ADAPTER *ioc = hd->ioc;
3328
3329 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
3330}
Tony Jonesee959b02008-02-22 00:13:36 +01003331static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303332
3333static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003334mptscsih_board_assembly_show(struct device *dev,
3335 struct device_attribute *attr, char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303336{
Tony Jonesee959b02008-02-22 00:13:36 +01003337 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003338 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303339 MPT_ADAPTER *ioc = hd->ioc;
3340
3341 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
3342}
Tony Jonesee959b02008-02-22 00:13:36 +01003343static DEVICE_ATTR(board_assembly, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303344 mptscsih_board_assembly_show, NULL);
3345
3346static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003347mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr,
3348 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303349{
Tony Jonesee959b02008-02-22 00:13:36 +01003350 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003351 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303352 MPT_ADAPTER *ioc = hd->ioc;
3353
3354 return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
3355}
Tony Jonesee959b02008-02-22 00:13:36 +01003356static DEVICE_ATTR(board_tracer, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303357 mptscsih_board_tracer_show, NULL);
3358
3359static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003360mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr,
3361 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303362{
Tony Jonesee959b02008-02-22 00:13:36 +01003363 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003364 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303365 MPT_ADAPTER *ioc = hd->ioc;
3366
3367 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
3368}
Tony Jonesee959b02008-02-22 00:13:36 +01003369static DEVICE_ATTR(io_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303370 mptscsih_io_delay_show, NULL);
3371
3372static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003373mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr,
3374 char *buf)
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303375{
Tony Jonesee959b02008-02-22 00:13:36 +01003376 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003377 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303378 MPT_ADAPTER *ioc = hd->ioc;
3379
3380 return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
3381}
Tony Jonesee959b02008-02-22 00:13:36 +01003382static DEVICE_ATTR(device_delay, S_IRUGO,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303383 mptscsih_device_delay_show, NULL);
3384
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303385static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003386mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr,
3387 char *buf)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303388{
Tony Jonesee959b02008-02-22 00:13:36 +01003389 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003390 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303391 MPT_ADAPTER *ioc = hd->ioc;
3392
3393 return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
3394}
3395static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003396mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr,
3397 const char *buf, size_t count)
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303398{
Tony Jonesee959b02008-02-22 00:13:36 +01003399 struct Scsi_Host *host = class_to_shost(dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06003400 MPT_SCSI_HOST *hd = shost_priv(host);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303401 MPT_ADAPTER *ioc = hd->ioc;
3402 int val = 0;
3403
3404 if (sscanf(buf, "%x", &val) != 1)
3405 return -EINVAL;
3406
3407 ioc->debug_level = val;
3408 printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
3409 ioc->name, ioc->debug_level);
3410 return strlen(buf);
3411}
Tony Jonesee959b02008-02-22 00:13:36 +01003412static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
3413 mptscsih_debug_level_show, mptscsih_debug_level_store);
Prakash, Sathya6757d6b2007-07-25 11:14:01 +05303414
Tony Jonesee959b02008-02-22 00:13:36 +01003415struct device_attribute *mptscsih_host_attrs[] = {
3416 &dev_attr_version_fw,
3417 &dev_attr_version_bios,
3418 &dev_attr_version_mpi,
3419 &dev_attr_version_product,
3420 &dev_attr_version_nvdata_persistent,
3421 &dev_attr_version_nvdata_default,
3422 &dev_attr_board_name,
3423 &dev_attr_board_assembly,
3424 &dev_attr_board_tracer,
3425 &dev_attr_io_delay,
3426 &dev_attr_device_delay,
3427 &dev_attr_debug_level,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303428 NULL,
3429};
3430EXPORT_SYMBOL(mptscsih_host_attrs);
3431
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003432EXPORT_SYMBOL(mptscsih_remove);
3433EXPORT_SYMBOL(mptscsih_shutdown);
3434#ifdef CONFIG_PM
3435EXPORT_SYMBOL(mptscsih_suspend);
3436EXPORT_SYMBOL(mptscsih_resume);
3437#endif
3438EXPORT_SYMBOL(mptscsih_proc_info);
3439EXPORT_SYMBOL(mptscsih_info);
3440EXPORT_SYMBOL(mptscsih_qcmd);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003441EXPORT_SYMBOL(mptscsih_slave_destroy);
3442EXPORT_SYMBOL(mptscsih_slave_configure);
3443EXPORT_SYMBOL(mptscsih_abort);
3444EXPORT_SYMBOL(mptscsih_dev_reset);
3445EXPORT_SYMBOL(mptscsih_bus_reset);
3446EXPORT_SYMBOL(mptscsih_host_reset);
3447EXPORT_SYMBOL(mptscsih_bios_param);
3448EXPORT_SYMBOL(mptscsih_io_done);
3449EXPORT_SYMBOL(mptscsih_taskmgmt_complete);
3450EXPORT_SYMBOL(mptscsih_scandv_complete);
3451EXPORT_SYMBOL(mptscsih_event_process);
3452EXPORT_SYMBOL(mptscsih_ioc_reset);
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -06003453EXPORT_SYMBOL(mptscsih_change_queue_depth);
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003454EXPORT_SYMBOL(mptscsih_timer_expired);
James Bottomley663e1aa2006-01-29 12:10:24 -06003455EXPORT_SYMBOL(mptscsih_TMHandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
Moore, Eric Dean 0d0c7972005-04-22 18:02:09 -04003457/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/