1 |
1275 |
phoenix |
/*
|
2 |
|
|
* linux/drivers/message/fusion/mptscsih.c
|
3 |
|
|
* High performance SCSI / Fibre Channel SCSI Host device driver.
|
4 |
|
|
* For use with PCI chip/adapter(s):
|
5 |
|
|
* LSIFC9xx/LSI409xx Fibre Channel
|
6 |
|
|
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
|
7 |
|
|
*
|
8 |
|
|
* Credits:
|
9 |
|
|
* This driver would not exist if not for Alan Cox's development
|
10 |
|
|
* of the linux i2o driver.
|
11 |
|
|
*
|
12 |
|
|
* A special thanks to Pamela Delaney (LSI Logic) for tons of work
|
13 |
|
|
* and countless enhancements while adding support for the 1030
|
14 |
|
|
* chip family. Pam has been instrumental in the development of
|
15 |
|
|
* of the 2.xx.xx series fusion drivers, and her contributions are
|
16 |
|
|
* far too numerous to hope to list in one place.
|
17 |
|
|
*
|
18 |
|
|
* A huge debt of gratitude is owed to David S. Miller (DaveM)
|
19 |
|
|
* for fixing much of the stupid and broken stuff in the early
|
20 |
|
|
* driver while porting to sparc64 platform. THANK YOU!
|
21 |
|
|
*
|
22 |
|
|
* (see mptbase.c)
|
23 |
|
|
*
|
24 |
|
|
* Copyright (c) 1999-2002 LSI Logic Corporation
|
25 |
|
|
* Original author: Steven J. Ralston
|
26 |
|
|
* (mailto:sjralston1@netscape.net)
|
27 |
|
|
* (mailto:mpt_linux_developer@lsil.com)
|
28 |
|
|
*
|
29 |
|
|
* $Id: mptscsih.c,v 1.1.1.1 2004-04-15 02:27:20 phoenix Exp $
|
30 |
|
|
*/
|
31 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
32 |
|
|
/*
|
33 |
|
|
This program is free software; you can redistribute it and/or modify
|
34 |
|
|
it under the terms of the GNU General Public License as published by
|
35 |
|
|
the Free Software Foundation; version 2 of the License.
|
36 |
|
|
|
37 |
|
|
This program is distributed in the hope that it will be useful,
|
38 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
39 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
40 |
|
|
GNU General Public License for more details.
|
41 |
|
|
|
42 |
|
|
NO WARRANTY
|
43 |
|
|
THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
44 |
|
|
CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
45 |
|
|
LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
46 |
|
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
47 |
|
|
solely responsible for determining the appropriateness of using and
|
48 |
|
|
distributing the Program and assumes all risks associated with its
|
49 |
|
|
exercise of rights under this Agreement, including but not limited to
|
50 |
|
|
the risks and costs of program errors, damage to or loss of data,
|
51 |
|
|
programs or equipment, and unavailability or interruption of operations.
|
52 |
|
|
|
53 |
|
|
DISCLAIMER OF LIABILITY
|
54 |
|
|
NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
55 |
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
56 |
|
|
DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
57 |
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
58 |
|
|
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
59 |
|
|
USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
60 |
|
|
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
61 |
|
|
|
62 |
|
|
You should have received a copy of the GNU General Public License
|
63 |
|
|
along with this program; if not, write to the Free Software
|
64 |
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
65 |
|
|
*/
|
66 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
67 |
|
|
|
68 |
|
|
#include <linux/module.h>
|
69 |
|
|
#include <linux/version.h>
|
70 |
|
|
#include <linux/kernel.h>
|
71 |
|
|
#include <linux/init.h>
|
72 |
|
|
#include <linux/errno.h>
|
73 |
|
|
#include <linux/kdev_t.h>
|
74 |
|
|
#include <linux/blkdev.h>
|
75 |
|
|
#include <linux/blk.h> /* for io_request_lock (spinlock) decl */
|
76 |
|
|
#include <linux/delay.h> /* for mdelay */
|
77 |
|
|
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
|
78 |
|
|
#include <linux/reboot.h> /* notifier code */
|
79 |
|
|
#include "../../scsi/scsi.h"
|
80 |
|
|
#include "../../scsi/hosts.h"
|
81 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
|
82 |
|
|
#include "../../scsi/sd.h"
|
83 |
|
|
#endif
|
84 |
|
|
|
85 |
|
|
#include "mptbase.h"
|
86 |
|
|
#include "mptscsih.h"
|
87 |
|
|
#include "isense.h"
|
88 |
|
|
|
89 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
90 |
|
|
#define my_NAME "Fusion MPT SCSI Host driver"
|
91 |
|
|
#define my_VERSION MPT_LINUX_VERSION_COMMON
|
92 |
|
|
#define MYNAM "mptscsih"
|
93 |
|
|
|
94 |
|
|
MODULE_AUTHOR(MODULEAUTHOR);
|
95 |
|
|
MODULE_DESCRIPTION(my_NAME);
|
96 |
|
|
MODULE_LICENSE("GPL");
|
97 |
|
|
|
98 |
|
|
/* Set string for command line args from insmod */
|
99 |
|
|
#ifdef MODULE
|
100 |
|
|
char *mptscsih = 0;
|
101 |
|
|
MODULE_PARM(mptscsih, "s");
|
102 |
|
|
#endif
|
103 |
|
|
|
104 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
105 |
|
|
|
106 |
|
|
typedef struct _BIG_SENSE_BUF {
|
107 |
|
|
u8 data[MPT_SENSE_BUFFER_ALLOC];
|
108 |
|
|
} BIG_SENSE_BUF;
|
109 |
|
|
|
110 |
|
|
#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
|
111 |
|
|
#define MPT_SCANDV_DID_RESET (0x00000001)
|
112 |
|
|
#define MPT_SCANDV_SENSE (0x00000002)
|
113 |
|
|
#define MPT_SCANDV_SOME_ERROR (0x00000004)
|
114 |
|
|
#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
|
115 |
|
|
#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
|
116 |
|
|
|
117 |
|
|
#define MPT_SCANDV_MAX_RETRIES (10)
|
118 |
|
|
|
119 |
|
|
#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
|
120 |
|
|
#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
|
121 |
|
|
#define MPT_ICFLAG_PHYS_DISK 0x04 /* Any SCSI IO but do Phys Disk Format */
|
122 |
|
|
#define MPT_ICFLAG_TAGGED_CMD 0x08 /* Do tagged IO */
|
123 |
|
|
#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occured with this command */
|
124 |
|
|
#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
|
125 |
|
|
|
126 |
|
|
typedef struct _internal_cmd {
|
127 |
|
|
char *data; /* data pointer */
|
128 |
|
|
dma_addr_t data_dma; /* data dma address */
|
129 |
|
|
int size; /* transfer size */
|
130 |
|
|
u8 cmd; /* SCSI Op Code */
|
131 |
|
|
u8 bus; /* bus number */
|
132 |
|
|
u8 id; /* SCSI ID (virtual) */
|
133 |
|
|
u8 lun;
|
134 |
|
|
u8 flags; /* Bit Field - See above */
|
135 |
|
|
u8 physDiskNum; /* Phys disk number, -1 else */
|
136 |
|
|
u8 rsvd2;
|
137 |
|
|
u8 rsvd;
|
138 |
|
|
} INTERNAL_CMD;
|
139 |
|
|
|
140 |
|
|
typedef struct _negoparms {
|
141 |
|
|
u8 width;
|
142 |
|
|
u8 offset;
|
143 |
|
|
u8 factor;
|
144 |
|
|
u8 flags;
|
145 |
|
|
} NEGOPARMS;
|
146 |
|
|
|
147 |
|
|
typedef struct _dv_parameters {
|
148 |
|
|
NEGOPARMS max;
|
149 |
|
|
NEGOPARMS now;
|
150 |
|
|
u8 cmd;
|
151 |
|
|
u8 id;
|
152 |
|
|
u16 pad1;
|
153 |
|
|
} DVPARAMETERS;
|
154 |
|
|
|
155 |
|
|
|
156 |
|
|
/*
|
157 |
|
|
* Other private/forward protos...
|
158 |
|
|
*/
|
159 |
|
|
static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
160 |
|
|
static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
|
161 |
|
|
static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
162 |
|
|
|
163 |
|
|
static int mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
|
164 |
|
|
SCSIIORequest_t *pReq, int req_idx);
|
165 |
|
|
static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
|
166 |
|
|
static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
|
167 |
|
|
static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
|
168 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
169 |
|
|
static void search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
|
170 |
|
|
#else
|
171 |
|
|
static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
|
172 |
|
|
#endif
|
173 |
|
|
static u32 SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc);
|
174 |
|
|
static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
|
175 |
|
|
static void post_pendingQ_commands(MPT_SCSI_HOST *hd);
|
176 |
|
|
|
177 |
|
|
static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag);
|
178 |
|
|
static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag);
|
179 |
|
|
|
180 |
|
|
static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
|
181 |
|
|
static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
|
182 |
|
|
|
183 |
|
|
static void mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
|
184 |
|
|
void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
|
185 |
|
|
static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
|
186 |
|
|
static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
|
187 |
|
|
static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
|
188 |
|
|
static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
|
189 |
|
|
static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
|
190 |
|
|
static int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
191 |
|
|
static void mptscsih_timer_expired(unsigned long data);
|
192 |
|
|
static void mptscsih_taskmgmt_timeout(unsigned long data);
|
193 |
|
|
static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
|
194 |
|
|
static int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
|
195 |
|
|
|
196 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
197 |
|
|
static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
|
198 |
|
|
static void mptscsih_domainValidation(void *hd);
|
199 |
|
|
static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
|
200 |
|
|
static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
|
201 |
|
|
static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
|
202 |
|
|
static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
|
203 |
|
|
static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
|
204 |
|
|
#endif
|
205 |
|
|
static int mptscsih_setup(char *str);
|
206 |
|
|
static int mptscsih_halt(struct notifier_block *nb, ulong event, void *buf);
|
207 |
|
|
|
208 |
|
|
/*
|
209 |
|
|
* Reboot Notification
|
210 |
|
|
*/
|
211 |
|
|
static struct notifier_block mptscsih_notifier = {
|
212 |
|
|
mptscsih_halt, NULL, 0
|
213 |
|
|
};
|
214 |
|
|
|
215 |
|
|
/*
|
216 |
|
|
* Private data...
|
217 |
|
|
*/
|
218 |
|
|
|
219 |
|
|
static int mpt_scsi_hosts = 0;
|
220 |
|
|
static atomic_t queue_depth;
|
221 |
|
|
|
222 |
|
|
static int ScsiDoneCtx = -1;
|
223 |
|
|
static int ScsiTaskCtx = -1;
|
224 |
|
|
static int ScsiScanDvCtx = -1; /* Used only for bus scan and dv */
|
225 |
|
|
|
226 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
|
227 |
|
|
static struct proc_dir_entry proc_mpt_scsihost =
|
228 |
|
|
{
|
229 |
|
|
.low_ino = PROC_SCSI_MPT,
|
230 |
|
|
.namelen = 8,
|
231 |
|
|
.name = "mptscsih",
|
232 |
|
|
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
233 |
|
|
.nlink = 2,
|
234 |
|
|
};
|
235 |
|
|
#endif
|
236 |
|
|
|
237 |
|
|
#define SNS_LEN(scp) sizeof((scp)->sense_buffer)
|
238 |
|
|
|
239 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
240 |
|
|
/*
|
241 |
|
|
* Stuff to handle single-threading SCSI TaskMgmt
|
242 |
|
|
* (abort/reset) requests...
|
243 |
|
|
*/
|
244 |
|
|
static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
|
245 |
|
|
static int mytaskQ_bh_active = 0;
|
246 |
|
|
static struct mpt_work_struct mptscsih_ptaskfoo;
|
247 |
|
|
static atomic_t mpt_taskQdepth;
|
248 |
|
|
#endif
|
249 |
|
|
|
250 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
251 |
|
|
/*
|
252 |
|
|
* Domain Validation task structure
|
253 |
|
|
*/
|
254 |
|
|
static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
|
255 |
|
|
static int dvtaskQ_active = 0;
|
256 |
|
|
static int dvtaskQ_release = 0;
|
257 |
|
|
static struct mpt_work_struct mptscsih_dvTask;
|
258 |
|
|
#endif
|
259 |
|
|
|
260 |
|
|
/*
|
261 |
|
|
* Wait Queue setup
|
262 |
|
|
*/
|
263 |
|
|
static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq);
|
264 |
|
|
static int scandv_wait_done = 1;
|
265 |
|
|
|
266 |
|
|
/* Driver default setup
|
267 |
|
|
*/
|
268 |
|
|
static struct mptscsih_driver_setup
|
269 |
|
|
driver_setup = MPTSCSIH_DRIVER_SETUP;
|
270 |
|
|
|
271 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
272 |
|
|
static Scsi_Cmnd *foo_to[8];
|
273 |
|
|
#endif
|
274 |
|
|
|
275 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
276 |
|
|
/*
|
277 |
|
|
* Private inline routines...
|
278 |
|
|
*/
|
279 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
280 |
|
|
/* 19991030 -sralston
|
281 |
|
|
* Return absolute SCSI data direction:
|
282 |
|
|
* 1 = _DATA_OUT
|
283 |
|
|
* 0 = _DIR_NONE
|
284 |
|
|
* -1 = _DATA_IN
|
285 |
|
|
*
|
286 |
|
|
* Changed: 3-20-2002 pdelaney to use the default data
|
287 |
|
|
* direction and the defines set up in the
|
288 |
|
|
* 2.4 kernel series
|
289 |
|
|
* 1 = _DATA_OUT changed to SCSI_DATA_WRITE (1)
|
290 |
|
|
* 0 = _DIR_NONE changed to SCSI_DATA_NONE (3)
|
291 |
|
|
* -1 = _DATA_IN changed to SCSI_DATA_READ (2)
|
292 |
|
|
* If the direction is unknown, fall through to original code.
|
293 |
|
|
*
|
294 |
|
|
* Mid-layer bug fix(): sg interface generates the wrong data
|
295 |
|
|
* direction in some cases. Set the direction the hard way for
|
296 |
|
|
* the most common commands.
|
297 |
|
|
*/
|
298 |
|
|
static inline int
|
299 |
|
|
mptscsih_io_direction(Scsi_Cmnd *cmd)
|
300 |
|
|
{
|
301 |
|
|
switch (cmd->cmnd[0]) {
|
302 |
|
|
case WRITE_6:
|
303 |
|
|
case WRITE_10:
|
304 |
|
|
return SCSI_DATA_WRITE;
|
305 |
|
|
break;
|
306 |
|
|
case READ_6:
|
307 |
|
|
case READ_10:
|
308 |
|
|
return SCSI_DATA_READ;
|
309 |
|
|
break;
|
310 |
|
|
}
|
311 |
|
|
|
312 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
313 |
|
|
if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
|
314 |
|
|
return cmd->sc_data_direction;
|
315 |
|
|
#endif
|
316 |
|
|
switch (cmd->cmnd[0]) {
|
317 |
|
|
/* _DATA_OUT commands */
|
318 |
|
|
case WRITE_6: case WRITE_10: case WRITE_12:
|
319 |
|
|
case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER:
|
320 |
|
|
case WRITE_VERIFY: case WRITE_VERIFY_12:
|
321 |
|
|
case COMPARE: case COPY: case COPY_VERIFY:
|
322 |
|
|
case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
|
323 |
|
|
case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12:
|
324 |
|
|
case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT:
|
325 |
|
|
case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK:
|
326 |
|
|
case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG:
|
327 |
|
|
case REASSIGN_BLOCKS:
|
328 |
|
|
case PERSISTENT_RESERVE_OUT:
|
329 |
|
|
case 0xea:
|
330 |
|
|
case 0xa3:
|
331 |
|
|
return SCSI_DATA_WRITE;
|
332 |
|
|
|
333 |
|
|
/* No data transfer commands */
|
334 |
|
|
case SEEK_6: case SEEK_10:
|
335 |
|
|
case RESERVE: case RELEASE:
|
336 |
|
|
case TEST_UNIT_READY:
|
337 |
|
|
case START_STOP:
|
338 |
|
|
case ALLOW_MEDIUM_REMOVAL:
|
339 |
|
|
return SCSI_DATA_NONE;
|
340 |
|
|
|
341 |
|
|
/* Conditional data transfer commands */
|
342 |
|
|
case FORMAT_UNIT:
|
343 |
|
|
if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */
|
344 |
|
|
return SCSI_DATA_WRITE;
|
345 |
|
|
else
|
346 |
|
|
return SCSI_DATA_NONE;
|
347 |
|
|
|
348 |
|
|
case VERIFY:
|
349 |
|
|
if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */
|
350 |
|
|
return SCSI_DATA_WRITE;
|
351 |
|
|
else
|
352 |
|
|
return SCSI_DATA_NONE;
|
353 |
|
|
|
354 |
|
|
case RESERVE_10:
|
355 |
|
|
if (cmd->cmnd[1] & 0x03) /* RESERVE:{LongID|Extent} (data out phase)? */
|
356 |
|
|
return SCSI_DATA_WRITE;
|
357 |
|
|
else
|
358 |
|
|
return SCSI_DATA_NONE;
|
359 |
|
|
|
360 |
|
|
/* Must be data _IN! */
|
361 |
|
|
default:
|
362 |
|
|
return SCSI_DATA_READ;
|
363 |
|
|
}
|
364 |
|
|
} /* mptscsih_io_direction() */
|
365 |
|
|
|
366 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
367 |
|
|
/**
|
368 |
|
|
* mptscsih_add_sge - Place a simple SGE at address pAddr.
|
369 |
|
|
* @pAddr: virtual address for SGE
|
370 |
|
|
* @flagslength: SGE flags and data transfer length
|
371 |
|
|
* @dma_addr: Physical address
|
372 |
|
|
*
|
373 |
|
|
* This routine places a MPT request frame back on the MPT adapter's
|
374 |
|
|
* FreeQ.
|
375 |
|
|
*/
|
376 |
|
|
static inline void
|
377 |
|
|
mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
|
378 |
|
|
{
|
379 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
380 |
|
|
SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
|
381 |
|
|
u32 tmp = dma_addr & 0xFFFFFFFF;
|
382 |
|
|
|
383 |
|
|
pSge->FlagsLength = cpu_to_le32(flagslength);
|
384 |
|
|
pSge->Address.Low = cpu_to_le32(tmp);
|
385 |
|
|
tmp = (u32) ((u64)dma_addr >> 32);
|
386 |
|
|
pSge->Address.High = cpu_to_le32(tmp);
|
387 |
|
|
|
388 |
|
|
} else {
|
389 |
|
|
SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
|
390 |
|
|
pSge->FlagsLength = cpu_to_le32(flagslength);
|
391 |
|
|
pSge->Address = cpu_to_le32(dma_addr);
|
392 |
|
|
}
|
393 |
|
|
} /* mptscsih_add_sge() */
|
394 |
|
|
|
395 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
396 |
|
|
/**
|
397 |
|
|
* mptscsih_add_chain - Place a chain SGE at address pAddr.
|
398 |
|
|
* @pAddr: virtual address for SGE
|
399 |
|
|
* @next: nextChainOffset value (u32's)
|
400 |
|
|
* @length: length of next SGL segment
|
401 |
|
|
* @dma_addr: Physical address
|
402 |
|
|
*
|
403 |
|
|
* This routine places a MPT request frame back on the MPT adapter's
|
404 |
|
|
* FreeQ.
|
405 |
|
|
*/
|
406 |
|
|
static inline void
|
407 |
|
|
mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
|
408 |
|
|
{
|
409 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
410 |
|
|
SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
|
411 |
|
|
u32 tmp = dma_addr & 0xFFFFFFFF;
|
412 |
|
|
|
413 |
|
|
pChain->Length = cpu_to_le16(length);
|
414 |
|
|
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
|
415 |
|
|
|
416 |
|
|
pChain->NextChainOffset = next;
|
417 |
|
|
|
418 |
|
|
pChain->Address.Low = cpu_to_le32(tmp);
|
419 |
|
|
tmp = (u32) ((u64)dma_addr >> 32);
|
420 |
|
|
pChain->Address.High = cpu_to_le32(tmp);
|
421 |
|
|
} else {
|
422 |
|
|
SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
|
423 |
|
|
pChain->Length = cpu_to_le16(length);
|
424 |
|
|
pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
|
425 |
|
|
pChain->NextChainOffset = next;
|
426 |
|
|
pChain->Address = cpu_to_le32(dma_addr);
|
427 |
|
|
}
|
428 |
|
|
} /* mptscsih_add_chain() */
|
429 |
|
|
|
430 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
431 |
|
|
/*
|
432 |
|
|
* mptscsih_getFreeChainBuffes - Function to get a free chain
|
433 |
|
|
* from the MPT_SCSI_HOST FreeChainQ.
|
434 |
|
|
* @hd: Pointer to the MPT_SCSI_HOST instance
|
435 |
|
|
* @req_idx: Index of the SCSI IO request frame. (output)
|
436 |
|
|
*
|
437 |
|
|
* return SUCCESS or FAILED
|
438 |
|
|
*/
|
439 |
|
|
static inline int
|
440 |
|
|
mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
|
441 |
|
|
{
|
442 |
|
|
MPT_FRAME_HDR *chainBuf;
|
443 |
|
|
unsigned long flags;
|
444 |
|
|
int rc;
|
445 |
|
|
int chain_idx;
|
446 |
|
|
|
447 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
448 |
|
|
if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
|
449 |
|
|
|
450 |
|
|
int offset;
|
451 |
|
|
|
452 |
|
|
chainBuf = hd->FreeChainQ.head;
|
453 |
|
|
Q_DEL_ITEM(&chainBuf->u.frame.linkage);
|
454 |
|
|
offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
|
455 |
|
|
chain_idx = offset / hd->ioc->req_sz;
|
456 |
|
|
rc = SUCCESS;
|
457 |
|
|
}
|
458 |
|
|
else {
|
459 |
|
|
rc = FAILED;
|
460 |
|
|
chain_idx = MPT_HOST_NO_CHAIN;
|
461 |
|
|
}
|
462 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
463 |
|
|
|
464 |
|
|
|
465 |
|
|
*retIndex = chain_idx;
|
466 |
|
|
|
467 |
|
|
dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
|
468 |
|
|
hd->ioc->name, *retIndex, chainBuf));
|
469 |
|
|
|
470 |
|
|
return rc;
|
471 |
|
|
} /* mptscsih_getFreeChainBuffer() */
|
472 |
|
|
|
473 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
474 |
|
|
/*
|
475 |
|
|
* mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
|
476 |
|
|
* SCSIIORequest_t Message Frame.
|
477 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure
|
478 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure
|
479 |
|
|
* @pReq: Pointer to SCSIIORequest_t structure
|
480 |
|
|
*
|
481 |
|
|
* Returns ...
|
482 |
|
|
*/
|
483 |
|
|
static int
|
484 |
|
|
mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
|
485 |
|
|
SCSIIORequest_t *pReq, int req_idx)
|
486 |
|
|
{
|
487 |
|
|
char *psge;
|
488 |
|
|
char *chainSge;
|
489 |
|
|
struct scatterlist *sg;
|
490 |
|
|
int frm_sz;
|
491 |
|
|
int sges_left, sg_done;
|
492 |
|
|
int chain_idx = MPT_HOST_NO_CHAIN;
|
493 |
|
|
int sgeOffset;
|
494 |
|
|
int numSgeSlots, numSgeThisFrame;
|
495 |
|
|
u32 sgflags, sgdir, thisxfer = 0;
|
496 |
|
|
int chain_dma_off = 0;
|
497 |
|
|
int newIndex;
|
498 |
|
|
int ii;
|
499 |
|
|
dma_addr_t v2;
|
500 |
|
|
|
501 |
|
|
sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
|
502 |
|
|
if (sgdir == MPI_SCSIIO_CONTROL_WRITE) {
|
503 |
|
|
sgdir = MPT_TRANSFER_HOST_TO_IOC;
|
504 |
|
|
} else {
|
505 |
|
|
sgdir = MPT_TRANSFER_IOC_TO_HOST;
|
506 |
|
|
}
|
507 |
|
|
|
508 |
|
|
psge = (char *) &pReq->SGL;
|
509 |
|
|
frm_sz = hd->ioc->req_sz;
|
510 |
|
|
|
511 |
|
|
/* Map the data portion, if any.
|
512 |
|
|
* sges_left = 0 if no data transfer.
|
513 |
|
|
*/
|
514 |
|
|
if ( (sges_left = SCpnt->use_sg) ) {
|
515 |
|
|
if ( (sges_left = pci_map_sg(hd->ioc->pcidev,
|
516 |
|
|
(struct scatterlist *) SCpnt->request_buffer,
|
517 |
|
|
SCpnt->use_sg,
|
518 |
|
|
scsi_to_pci_dma_dir(SCpnt->sc_data_direction)))
|
519 |
|
|
== 0 )
|
520 |
|
|
return FAILED;
|
521 |
|
|
} else if (SCpnt->request_bufflen) {
|
522 |
|
|
dma_addr_t buf_dma_addr;
|
523 |
|
|
scPrivate *my_priv;
|
524 |
|
|
|
525 |
|
|
buf_dma_addr = pci_map_single(hd->ioc->pcidev,
|
526 |
|
|
SCpnt->request_buffer,
|
527 |
|
|
SCpnt->request_bufflen,
|
528 |
|
|
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
|
529 |
|
|
|
530 |
|
|
/* We hide it here for later unmap. */
|
531 |
|
|
my_priv = (scPrivate *) &SCpnt->SCp;
|
532 |
|
|
my_priv->p1 = (void *)(ulong) buf_dma_addr;
|
533 |
|
|
|
534 |
|
|
dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
|
535 |
|
|
hd->ioc->name, SCpnt, SCpnt->request_bufflen));
|
536 |
|
|
|
537 |
|
|
mptscsih_add_sge((char *) &pReq->SGL,
|
538 |
|
|
0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
|
539 |
|
|
buf_dma_addr);
|
540 |
|
|
|
541 |
|
|
return SUCCESS;
|
542 |
|
|
}
|
543 |
|
|
|
544 |
|
|
/* Handle the SG case.
|
545 |
|
|
*/
|
546 |
|
|
sg = (struct scatterlist *) SCpnt->request_buffer;
|
547 |
|
|
sg_done = 0;
|
548 |
|
|
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
|
549 |
|
|
chainSge = NULL;
|
550 |
|
|
|
551 |
|
|
/* Prior to entering this loop - the following must be set
|
552 |
|
|
* current MF: sgeOffset (bytes)
|
553 |
|
|
* chainSge (Null if original MF is not a chain buffer)
|
554 |
|
|
* sg_done (num SGE done for this MF)
|
555 |
|
|
*/
|
556 |
|
|
|
557 |
|
|
nextSGEset:
|
558 |
|
|
numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
|
559 |
|
|
numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
|
560 |
|
|
|
561 |
|
|
sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
|
562 |
|
|
|
563 |
|
|
/* Get first (num - 1) SG elements
|
564 |
|
|
* Skip any SG entries with a length of 0
|
565 |
|
|
* NOTE: at finish, sg and psge pointed to NEXT data/location positions
|
566 |
|
|
*/
|
567 |
|
|
for (ii=0; ii < (numSgeThisFrame-1); ii++) {
|
568 |
|
|
thisxfer = sg_dma_len(sg);
|
569 |
|
|
if (thisxfer == 0) {
|
570 |
|
|
sg ++; /* Get next SG element from the OS */
|
571 |
|
|
sg_done++;
|
572 |
|
|
continue;
|
573 |
|
|
}
|
574 |
|
|
|
575 |
|
|
v2 = sg_dma_address(sg);
|
576 |
|
|
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
|
577 |
|
|
|
578 |
|
|
sg++; /* Get next SG element from the OS */
|
579 |
|
|
psge += (sizeof(u32) + sizeof(dma_addr_t));
|
580 |
|
|
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
|
581 |
|
|
sg_done++;
|
582 |
|
|
}
|
583 |
|
|
|
584 |
|
|
if (numSgeThisFrame == sges_left) {
|
585 |
|
|
/* Add last element, end of buffer and end of list flags.
|
586 |
|
|
*/
|
587 |
|
|
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
|
588 |
|
|
MPT_SGE_FLAGS_END_OF_BUFFER |
|
589 |
|
|
MPT_SGE_FLAGS_END_OF_LIST;
|
590 |
|
|
|
591 |
|
|
/* Add last SGE and set termination flags.
|
592 |
|
|
* Note: Last SGE may have a length of 0 - which should be ok.
|
593 |
|
|
*/
|
594 |
|
|
thisxfer = sg_dma_len(sg);
|
595 |
|
|
|
596 |
|
|
v2 = sg_dma_address(sg);
|
597 |
|
|
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
|
598 |
|
|
/*
|
599 |
|
|
sg++;
|
600 |
|
|
psge += (sizeof(u32) + sizeof(dma_addr_t));
|
601 |
|
|
*/
|
602 |
|
|
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
|
603 |
|
|
sg_done++;
|
604 |
|
|
|
605 |
|
|
if (chainSge) {
|
606 |
|
|
/* The current buffer is a chain buffer,
|
607 |
|
|
* but there is not another one.
|
608 |
|
|
* Update the chain element
|
609 |
|
|
* Offset and Length fields.
|
610 |
|
|
*/
|
611 |
|
|
mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
|
612 |
|
|
} else {
|
613 |
|
|
/* The current buffer is the original MF
|
614 |
|
|
* and there is no Chain buffer.
|
615 |
|
|
*/
|
616 |
|
|
pReq->ChainOffset = 0;
|
617 |
|
|
}
|
618 |
|
|
} else {
|
619 |
|
|
/* At least one chain buffer is needed.
|
620 |
|
|
* Complete the first MF
|
621 |
|
|
* - last SGE element, set the LastElement bit
|
622 |
|
|
* - set ChainOffset (words) for orig MF
|
623 |
|
|
* (OR finish previous MF chain buffer)
|
624 |
|
|
* - update MFStructPtr ChainIndex
|
625 |
|
|
* - Populate chain element
|
626 |
|
|
* Also
|
627 |
|
|
* Loop until done.
|
628 |
|
|
*/
|
629 |
|
|
|
630 |
|
|
dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
|
631 |
|
|
hd->ioc->name, sg_done));
|
632 |
|
|
|
633 |
|
|
/* Set LAST_ELEMENT flag for last non-chain element
|
634 |
|
|
* in the buffer. Since psge points at the NEXT
|
635 |
|
|
* SGE element, go back one SGE element, update the flags
|
636 |
|
|
* and reset the pointer. (Note: sgflags & thisxfer are already
|
637 |
|
|
* set properly).
|
638 |
|
|
*/
|
639 |
|
|
if (sg_done) {
|
640 |
|
|
u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
|
641 |
|
|
sgflags = le32_to_cpu(*ptmp);
|
642 |
|
|
sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
|
643 |
|
|
*ptmp = cpu_to_le32(sgflags);
|
644 |
|
|
}
|
645 |
|
|
|
646 |
|
|
if (chainSge) {
|
647 |
|
|
/* The current buffer is a chain buffer.
|
648 |
|
|
* chainSge points to the previous Chain Element.
|
649 |
|
|
* Update its chain element Offset and Length (must
|
650 |
|
|
* include chain element size) fields.
|
651 |
|
|
* Old chain element is now complete.
|
652 |
|
|
*/
|
653 |
|
|
u8 nextChain = (u8) (sgeOffset >> 2);
|
654 |
|
|
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
|
655 |
|
|
mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
|
656 |
|
|
} else {
|
657 |
|
|
/* The original MF buffer requires a chain buffer -
|
658 |
|
|
* set the offset.
|
659 |
|
|
* Last element in this MF is a chain element.
|
660 |
|
|
*/
|
661 |
|
|
pReq->ChainOffset = (u8) (sgeOffset >> 2);
|
662 |
|
|
}
|
663 |
|
|
|
664 |
|
|
sges_left -= sg_done;
|
665 |
|
|
|
666 |
|
|
|
667 |
|
|
/* NOTE: psge points to the beginning of the chain element
|
668 |
|
|
* in current buffer. Get a chain buffer.
|
669 |
|
|
*/
|
670 |
|
|
if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
|
671 |
|
|
return FAILED;
|
672 |
|
|
|
673 |
|
|
/* Update the tracking arrays.
|
674 |
|
|
* If chainSge == NULL, update ReqToChain, else ChainToChain
|
675 |
|
|
*/
|
676 |
|
|
if (chainSge) {
|
677 |
|
|
hd->ChainToChain[chain_idx] = newIndex;
|
678 |
|
|
} else {
|
679 |
|
|
hd->ReqToChain[req_idx] = newIndex;
|
680 |
|
|
}
|
681 |
|
|
chain_idx = newIndex;
|
682 |
|
|
chain_dma_off = hd->ioc->req_sz * chain_idx;
|
683 |
|
|
|
684 |
|
|
/* Populate the chainSGE for the current buffer.
|
685 |
|
|
* - Set chain buffer pointer to psge and fill
|
686 |
|
|
* out the Address and Flags fields.
|
687 |
|
|
*/
|
688 |
|
|
chainSge = (char *) psge;
|
689 |
|
|
dsgprintk((KERN_INFO " Current buff @ %p (index 0x%x)",
|
690 |
|
|
psge, req_idx));
|
691 |
|
|
|
692 |
|
|
/* Start the SGE for the next buffer
|
693 |
|
|
*/
|
694 |
|
|
psge = (char *) (hd->ChainBuffer + chain_dma_off);
|
695 |
|
|
sgeOffset = 0;
|
696 |
|
|
sg_done = 0;
|
697 |
|
|
|
698 |
|
|
dsgprintk((KERN_INFO " Chain buff @ %p (index 0x%x)\n",
|
699 |
|
|
psge, chain_idx));
|
700 |
|
|
|
701 |
|
|
/* Start the SGE for the next buffer
|
702 |
|
|
*/
|
703 |
|
|
|
704 |
|
|
goto nextSGEset;
|
705 |
|
|
}
|
706 |
|
|
|
707 |
|
|
return SUCCESS;
|
708 |
|
|
} /* mptscsih_AddSGE() */
|
709 |
|
|
|
710 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
711 |
|
|
/*
|
712 |
|
|
* mptscsih_io_done - Main SCSI IO callback routine registered to
|
713 |
|
|
* Fusion MPT (base) driver
|
714 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
715 |
|
|
* @mf: Pointer to original MPT request frame
|
716 |
|
|
* @r: Pointer to MPT reply frame (NULL if TurboReply)
|
717 |
|
|
*
|
718 |
|
|
* This routine is called from mpt.c::mpt_interrupt() at the completion
|
719 |
|
|
* of any SCSI IO request.
|
720 |
|
|
* This routine is registered with the Fusion MPT (base) driver at driver
|
721 |
|
|
* load/init time via the mpt_register() API call.
|
722 |
|
|
*
|
723 |
|
|
* Returns 1 indicating alloc'd request frame ptr should be freed.
|
724 |
|
|
*/
|
725 |
|
|
static int
|
726 |
|
|
mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
727 |
|
|
{
|
728 |
|
|
Scsi_Cmnd *sc;
|
729 |
|
|
MPT_SCSI_HOST *hd;
|
730 |
|
|
SCSIIORequest_t *pScsiReq;
|
731 |
|
|
SCSIIOReply_t *pScsiReply;
|
732 |
|
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
|
733 |
|
|
unsigned long flags;
|
734 |
|
|
#endif
|
735 |
|
|
u16 req_idx;
|
736 |
|
|
|
737 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
738 |
|
|
|
739 |
|
|
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
740 |
|
|
sc = hd->ScsiLookup[req_idx];
|
741 |
|
|
if (sc == NULL) {
|
742 |
|
|
MPIHeader_t *hdr = (MPIHeader_t *)mf;
|
743 |
|
|
|
744 |
|
|
atomic_dec(&queue_depth);
|
745 |
|
|
|
746 |
|
|
/* Remark: writeSDP1 will use the ScsiDoneCtx
|
747 |
|
|
* If a SCSI I/O cmd, device disabled by OS and
|
748 |
|
|
* completion done. Cannot touch sc struct. Just free mem.
|
749 |
|
|
*/
|
750 |
|
|
if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
|
751 |
|
|
printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
|
752 |
|
|
|
753 |
|
|
mptscsih_freeChainBuffers(hd, req_idx);
|
754 |
|
|
return 1;
|
755 |
|
|
}
|
756 |
|
|
|
757 |
|
|
dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
|
758 |
|
|
ioc->name, mf, mr, sc, req_idx));
|
759 |
|
|
|
760 |
|
|
atomic_dec(&queue_depth);
|
761 |
|
|
|
762 |
|
|
sc->result = DID_OK << 16; /* Set default reply as OK */
|
763 |
|
|
pScsiReq = (SCSIIORequest_t *) mf;
|
764 |
|
|
pScsiReply = (SCSIIOReply_t *) mr;
|
765 |
|
|
|
766 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
767 |
|
|
if (ioc->timeout_cnt > 0) {
|
768 |
|
|
int ii, left = 0;
|
769 |
|
|
|
770 |
|
|
for (ii=0; ii < 8; ii++) {
|
771 |
|
|
if (sc == foo_to[ii]) {
|
772 |
|
|
printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n",
|
773 |
|
|
ioc->name, sc, jiffies);
|
774 |
|
|
foo_to[ii] = NULL;
|
775 |
|
|
}
|
776 |
|
|
if (foo_to[ii] != NULL)
|
777 |
|
|
left++;
|
778 |
|
|
}
|
779 |
|
|
|
780 |
|
|
if (left == 0) {
|
781 |
|
|
ioc->timeout_maxcnt = 0;
|
782 |
|
|
ioc->timeout_cnt = 0;
|
783 |
|
|
}
|
784 |
|
|
}
|
785 |
|
|
#endif
|
786 |
|
|
if (pScsiReply == NULL) {
|
787 |
|
|
/* special context reply handling */
|
788 |
|
|
|
789 |
|
|
/* If regular Inquiry cmd - save inquiry data
|
790 |
|
|
*/
|
791 |
|
|
if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
|
792 |
|
|
int dlen;
|
793 |
|
|
|
794 |
|
|
dlen = le32_to_cpu(pScsiReq->DataLength);
|
795 |
|
|
if (dlen >= SCSI_STD_INQUIRY_BYTES) {
|
796 |
|
|
mptscsih_initTarget(hd,
|
797 |
|
|
sc->channel,
|
798 |
|
|
sc->target,
|
799 |
|
|
pScsiReq->LUN[1],
|
800 |
|
|
sc->buffer,
|
801 |
|
|
dlen);
|
802 |
|
|
}
|
803 |
|
|
}
|
804 |
|
|
} else {
|
805 |
|
|
u32 xfer_cnt;
|
806 |
|
|
u16 status;
|
807 |
|
|
u8 scsi_state;
|
808 |
|
|
|
809 |
|
|
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
810 |
|
|
scsi_state = pScsiReply->SCSIState;
|
811 |
|
|
|
812 |
|
|
dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
|
813 |
|
|
ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
|
814 |
|
|
mf, mr, sc));
|
815 |
|
|
dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh"
|
816 |
|
|
", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
|
817 |
|
|
status, scsi_state, pScsiReply->SCSIStatus,
|
818 |
|
|
le32_to_cpu(pScsiReply->IOCLogInfo)));
|
819 |
|
|
|
820 |
|
|
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
|
821 |
|
|
copy_sense_data(sc, hd, mf, pScsiReply);
|
822 |
|
|
|
823 |
|
|
/*
|
824 |
|
|
* Look for + dump FCP ResponseInfo[]!
|
825 |
|
|
*/
|
826 |
|
|
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
|
827 |
|
|
dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n",
|
828 |
|
|
le32_to_cpu(pScsiReply->ResponseInfo)));
|
829 |
|
|
}
|
830 |
|
|
|
831 |
|
|
switch(status) {
|
832 |
|
|
case MPI_IOCSTATUS_BUSY: /* 0x0002 */
|
833 |
|
|
/* CHECKME!
|
834 |
|
|
* Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
|
835 |
|
|
* But not: DID_BUS_BUSY lest one risk
|
836 |
|
|
* killing interrupt handler:-(
|
837 |
|
|
*/
|
838 |
|
|
sc->result = STS_BUSY;
|
839 |
|
|
break;
|
840 |
|
|
|
841 |
|
|
case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
|
842 |
|
|
case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
|
843 |
|
|
sc->result = DID_BAD_TARGET << 16;
|
844 |
|
|
break;
|
845 |
|
|
|
846 |
|
|
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
|
847 |
|
|
/* Spoof to SCSI Selection Timeout! */
|
848 |
|
|
sc->result = DID_NO_CONNECT << 16;
|
849 |
|
|
|
850 |
|
|
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
|
851 |
|
|
hd->sel_timeout[pScsiReq->TargetID]++;
|
852 |
|
|
break;
|
853 |
|
|
|
854 |
|
|
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
|
855 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
856 |
|
|
search_taskQ_for_cmd(sc, hd);
|
857 |
|
|
#endif
|
858 |
|
|
/* Linux handles an unsolicited DID_RESET better
|
859 |
|
|
* than an unsolicited DID_ABORT.
|
860 |
|
|
*/
|
861 |
|
|
sc->result = DID_RESET << 16;
|
862 |
|
|
|
863 |
|
|
/* GEM Workaround. */
|
864 |
|
|
if (hd->is_spi)
|
865 |
|
|
mptscsih_no_negotiate(hd, sc->target);
|
866 |
|
|
break;
|
867 |
|
|
|
868 |
|
|
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
|
869 |
|
|
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
|
870 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
871 |
|
|
search_taskQ_for_cmd(sc, hd);
|
872 |
|
|
#endif
|
873 |
|
|
sc->result = DID_RESET << 16;
|
874 |
|
|
|
875 |
|
|
/* GEM Workaround. */
|
876 |
|
|
if (hd->is_spi)
|
877 |
|
|
mptscsih_no_negotiate(hd, sc->target);
|
878 |
|
|
break;
|
879 |
|
|
|
880 |
|
|
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
|
881 |
|
|
/*
|
882 |
|
|
* YIKES! I just discovered that SCSI IO which
|
883 |
|
|
* returns check condition, SenseKey=05 (ILLEGAL REQUEST)
|
884 |
|
|
* and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
|
885 |
|
|
* comes down this path!
|
886 |
|
|
* Do upfront check for valid SenseData and give it
|
887 |
|
|
* precedence!
|
888 |
|
|
*/
|
889 |
|
|
sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
|
890 |
|
|
if (scsi_state == 0) {
|
891 |
|
|
;
|
892 |
|
|
} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
|
893 |
|
|
/* Have already saved the status and sense data
|
894 |
|
|
*/
|
895 |
|
|
;
|
896 |
|
|
} else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
|
897 |
|
|
/* What to do?
|
898 |
|
|
*/
|
899 |
|
|
sc->result = DID_SOFT_ERROR << 16;
|
900 |
|
|
}
|
901 |
|
|
else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
|
902 |
|
|
/* Not real sure here either... */
|
903 |
|
|
sc->result = DID_RESET << 16;
|
904 |
|
|
}
|
905 |
|
|
|
906 |
|
|
/* Give report and update residual count.
|
907 |
|
|
*/
|
908 |
|
|
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
|
909 |
|
|
dprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
|
910 |
|
|
sc->underflow));
|
911 |
|
|
dprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt));
|
912 |
|
|
|
913 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
|
914 |
|
|
sc->resid = sc->request_bufflen - xfer_cnt;
|
915 |
|
|
dprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid));
|
916 |
|
|
#endif
|
917 |
|
|
if((xfer_cnt == 0 ) || (sc->underflow > xfer_cnt)) {
|
918 |
|
|
sc->result = DID_SOFT_ERROR << 16;
|
919 |
|
|
}
|
920 |
|
|
|
921 |
|
|
/* Report Queue Full
|
922 |
|
|
*/
|
923 |
|
|
if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
|
924 |
|
|
mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
|
925 |
|
|
|
926 |
|
|
/* If regular Inquiry cmd and some data was transferred,
|
927 |
|
|
* save inquiry data
|
928 |
|
|
*/
|
929 |
|
|
if ( pScsiReq->CDB[0] == INQUIRY
|
930 |
|
|
&& !(pScsiReq->CDB[1] & 0x3)
|
931 |
|
|
&& xfer_cnt >= SCSI_STD_INQUIRY_BYTES
|
932 |
|
|
) {
|
933 |
|
|
mptscsih_initTarget(hd,
|
934 |
|
|
sc->channel,
|
935 |
|
|
sc->target,
|
936 |
|
|
pScsiReq->LUN[1],
|
937 |
|
|
sc->buffer,
|
938 |
|
|
xfer_cnt);
|
939 |
|
|
}
|
940 |
|
|
break;
|
941 |
|
|
|
942 |
|
|
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
|
943 |
|
|
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
|
944 |
|
|
sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
|
945 |
|
|
if (scsi_state == 0) {
|
946 |
|
|
;
|
947 |
|
|
} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
|
948 |
|
|
/*
|
949 |
|
|
* If running against circa 200003dd 909 MPT f/w,
|
950 |
|
|
* may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
|
951 |
|
|
* (QUEUE_FULL) returned from device! --> get 0x0000?128
|
952 |
|
|
* and with SenseBytes set to 0.
|
953 |
|
|
*/
|
954 |
|
|
if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
|
955 |
|
|
mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
|
956 |
|
|
|
957 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
958 |
|
|
/* ADDED 20011120 -sralston
|
959 |
|
|
* Scsi mid-layer (old_eh) doesn't seem to like it
|
960 |
|
|
* when RAID returns SCSIStatus=02 (CHECK CONDITION),
|
961 |
|
|
* SenseKey=01 (RECOVERED ERROR), ASC/ASCQ=95/01.
|
962 |
|
|
* Seems to be * treating this as a IO error:-(
|
963 |
|
|
*
|
964 |
|
|
* So just lie about it altogether here.
|
965 |
|
|
*
|
966 |
|
|
* NOTE: It still gets reported to syslog via
|
967 |
|
|
* mpt_ScsiHost_ErrorReport from copy_sense_data
|
968 |
|
|
* call far above.
|
969 |
|
|
*/
|
970 |
|
|
if ( pScsiReply->SCSIStatus == STS_CHECK_CONDITION
|
971 |
|
|
&& SD_Sense_Key(sc->sense_buffer) == SK_RECOVERED_ERROR
|
972 |
|
|
) {
|
973 |
|
|
sc->result = 0;
|
974 |
|
|
}
|
975 |
|
|
#endif
|
976 |
|
|
|
977 |
|
|
}
|
978 |
|
|
else if (scsi_state &
|
979 |
|
|
(MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
|
980 |
|
|
) {
|
981 |
|
|
/*
|
982 |
|
|
* What to do?
|
983 |
|
|
*/
|
984 |
|
|
sc->result = DID_SOFT_ERROR << 16;
|
985 |
|
|
}
|
986 |
|
|
else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
|
987 |
|
|
/* Not real sure here either... */
|
988 |
|
|
sc->result = DID_RESET << 16;
|
989 |
|
|
}
|
990 |
|
|
else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
|
991 |
|
|
/* Device Inq. data indicates that it supports
|
992 |
|
|
* QTags, but rejects QTag messages.
|
993 |
|
|
* This command completed OK.
|
994 |
|
|
*
|
995 |
|
|
* Not real sure here either so do nothing... */
|
996 |
|
|
}
|
997 |
|
|
|
998 |
|
|
if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
|
999 |
|
|
mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
|
1000 |
|
|
|
1001 |
|
|
/* Add handling of:
|
1002 |
|
|
* Reservation Conflict, Busy,
|
1003 |
|
|
* Command Terminated, CHECK
|
1004 |
|
|
*/
|
1005 |
|
|
|
1006 |
|
|
/* If regular Inquiry cmd - save inquiry data
|
1007 |
|
|
*/
|
1008 |
|
|
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
|
1009 |
|
|
if ( sc->result == (DID_OK << 16)
|
1010 |
|
|
&& pScsiReq->CDB[0] == INQUIRY
|
1011 |
|
|
&& !(pScsiReq->CDB[1] & 0x3)
|
1012 |
|
|
&& xfer_cnt >= SCSI_STD_INQUIRY_BYTES
|
1013 |
|
|
) {
|
1014 |
|
|
mptscsih_initTarget(hd,
|
1015 |
|
|
sc->channel,
|
1016 |
|
|
sc->target,
|
1017 |
|
|
pScsiReq->LUN[1],
|
1018 |
|
|
sc->buffer,
|
1019 |
|
|
xfer_cnt);
|
1020 |
|
|
}
|
1021 |
|
|
break;
|
1022 |
|
|
|
1023 |
|
|
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
|
1024 |
|
|
if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
|
1025 |
|
|
/* Not real sure here either... */
|
1026 |
|
|
sc->result = DID_RESET << 16;
|
1027 |
|
|
} else
|
1028 |
|
|
sc->result = DID_SOFT_ERROR << 16;
|
1029 |
|
|
break;
|
1030 |
|
|
|
1031 |
|
|
case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
|
1032 |
|
|
case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
|
1033 |
|
|
case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
|
1034 |
|
|
case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
|
1035 |
|
|
case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
|
1036 |
|
|
case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
|
1037 |
|
|
case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
|
1038 |
|
|
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
|
1039 |
|
|
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
|
1040 |
|
|
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
|
1041 |
|
|
case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
|
1042 |
|
|
default:
|
1043 |
|
|
/*
|
1044 |
|
|
* What to do?
|
1045 |
|
|
*/
|
1046 |
|
|
sc->result = DID_SOFT_ERROR << 16;
|
1047 |
|
|
break;
|
1048 |
|
|
|
1049 |
|
|
} /* switch(status) */
|
1050 |
|
|
|
1051 |
|
|
dprintk((KERN_NOTICE " sc->result set to %08xh\n", sc->result));
|
1052 |
|
|
} /* end of address reply case */
|
1053 |
|
|
|
1054 |
|
|
/* Unmap the DMA buffers, if any. */
|
1055 |
|
|
if (sc->use_sg) {
|
1056 |
|
|
pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
|
1057 |
|
|
sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction));
|
1058 |
|
|
} else if (sc->request_bufflen) {
|
1059 |
|
|
scPrivate *my_priv;
|
1060 |
|
|
|
1061 |
|
|
my_priv = (scPrivate *) &sc->SCp;
|
1062 |
|
|
pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
|
1063 |
|
|
sc->request_bufflen,
|
1064 |
|
|
scsi_to_pci_dma_dir(sc->sc_data_direction));
|
1065 |
|
|
}
|
1066 |
|
|
|
1067 |
|
|
hd->ScsiLookup[req_idx] = NULL;
|
1068 |
|
|
|
1069 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
1070 |
|
|
sc->host_scribble = NULL;
|
1071 |
|
|
#endif
|
1072 |
|
|
|
1073 |
|
|
MPT_HOST_LOCK(flags);
|
1074 |
|
|
sc->scsi_done(sc); /* Issue the command callback */
|
1075 |
|
|
MPT_HOST_UNLOCK(flags);
|
1076 |
|
|
|
1077 |
|
|
/* Free Chain buffers */
|
1078 |
|
|
mptscsih_freeChainBuffers(hd, req_idx);
|
1079 |
|
|
return 1;
|
1080 |
|
|
}
|
1081 |
|
|
|
1082 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH /* { */
|
1083 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1084 |
|
|
/*
|
1085 |
|
|
* search_taskQ - Search SCSI task mgmt request queue for specific
|
1086 |
|
|
* request type.
|
1087 |
|
|
* @remove: (Boolean) Should request be removed if found?
|
1088 |
|
|
* @sc: Pointer to Scsi_Cmnd structure
|
1089 |
|
|
* @task_type: Task type to search for
|
1090 |
|
|
*
|
1091 |
|
|
* Returns pointer to MPT request frame if found, or %NULL if request
|
1092 |
|
|
* was not found.
|
1093 |
|
|
*/
|
1094 |
|
|
static MPT_FRAME_HDR *
|
1095 |
|
|
search_taskQ(int remove, Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, u8 task_type)
|
1096 |
|
|
{
|
1097 |
|
|
MPT_FRAME_HDR *mf = NULL;
|
1098 |
|
|
unsigned long flags;
|
1099 |
|
|
int count = 0;
|
1100 |
|
|
int list_sz;
|
1101 |
|
|
|
1102 |
|
|
dprintk((KERN_INFO MYNAM ": search_taskQ(%d,sc=%p,%d) called\n",
|
1103 |
|
|
remove, sc, task_type));
|
1104 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
1105 |
|
|
list_sz = hd->taskQcnt;
|
1106 |
|
|
if (! Q_IS_EMPTY(&hd->taskQ)) {
|
1107 |
|
|
mf = hd->taskQ.head;
|
1108 |
|
|
do {
|
1109 |
|
|
count++;
|
1110 |
|
|
if (mf->u.frame.linkage.argp1 == sc &&
|
1111 |
|
|
mf->u.frame.linkage.arg1 == task_type) {
|
1112 |
|
|
if (remove) {
|
1113 |
|
|
Q_DEL_ITEM(&mf->u.frame.linkage);
|
1114 |
|
|
hd->taskQcnt--;
|
1115 |
|
|
atomic_dec(&mpt_taskQdepth);
|
1116 |
|
|
|
1117 |
|
|
/* Don't save mf into nextmf because
|
1118 |
|
|
* exit after command has been deleted.
|
1119 |
|
|
*/
|
1120 |
|
|
|
1121 |
|
|
/* Place the MF back on the FreeQ */
|
1122 |
|
|
Q_ADD_TAIL(&hd->ioc->FreeQ,
|
1123 |
|
|
&mf->u.frame.linkage,
|
1124 |
|
|
MPT_FRAME_HDR);
|
1125 |
|
|
#ifdef MFCNT
|
1126 |
|
|
hd->ioc->mfcnt--;
|
1127 |
|
|
#endif
|
1128 |
|
|
}
|
1129 |
|
|
break;
|
1130 |
|
|
}
|
1131 |
|
|
} while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
|
1132 |
|
|
if (mf == (MPT_FRAME_HDR*)&hd->taskQ) {
|
1133 |
|
|
mf = NULL;
|
1134 |
|
|
}
|
1135 |
|
|
}
|
1136 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
1137 |
|
|
|
1138 |
|
|
if (list_sz) {
|
1139 |
|
|
dprintk((KERN_INFO " Results=%p (%sFOUND%s)!\n",
|
1140 |
|
|
mf,
|
1141 |
|
|
mf ? "" : "NOT_",
|
1142 |
|
|
(mf && remove) ? "+REMOVED" : "" ));
|
1143 |
|
|
dprintk((KERN_INFO " (searched thru %d of %d items on taskQ)\n",
|
1144 |
|
|
count,
|
1145 |
|
|
list_sz ));
|
1146 |
|
|
}
|
1147 |
|
|
|
1148 |
|
|
return mf;
|
1149 |
|
|
}
|
1150 |
|
|
|
1151 |
|
|
/*
|
1152 |
|
|
* clean_taskQ - Clean the SCSI task mgmt request for
|
1153 |
|
|
* this SCSI host instance.
|
1154 |
|
|
* @hd: MPT_SCSI_HOST pointer
|
1155 |
|
|
*
|
1156 |
|
|
* Returns: None.
|
1157 |
|
|
*/
|
1158 |
|
|
static void
|
1159 |
|
|
clean_taskQ(MPT_SCSI_HOST *hd)
|
1160 |
|
|
{
|
1161 |
|
|
MPT_FRAME_HDR *mf;
|
1162 |
|
|
MPT_FRAME_HDR *nextmf;
|
1163 |
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
1164 |
|
|
unsigned long flags;
|
1165 |
|
|
|
1166 |
|
|
dprintk((KERN_INFO MYNAM ": clean_taskQ called\n"));
|
1167 |
|
|
|
1168 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
1169 |
|
|
if (! Q_IS_EMPTY(&hd->taskQ)) {
|
1170 |
|
|
mf = hd->taskQ.head;
|
1171 |
|
|
do {
|
1172 |
|
|
Q_DEL_ITEM(&mf->u.frame.linkage);
|
1173 |
|
|
hd->taskQcnt--;
|
1174 |
|
|
atomic_dec(&mpt_taskQdepth);
|
1175 |
|
|
|
1176 |
|
|
nextmf = mf->u.frame.linkage.forw;
|
1177 |
|
|
|
1178 |
|
|
/* Place the MF back on the FreeQ */
|
1179 |
|
|
Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage,
|
1180 |
|
|
MPT_FRAME_HDR);
|
1181 |
|
|
#ifdef MFCNT
|
1182 |
|
|
hd->ioc->mfcnt--;
|
1183 |
|
|
#endif
|
1184 |
|
|
} while ((mf = nextmf) != (MPT_FRAME_HDR*)&hd->taskQ);
|
1185 |
|
|
}
|
1186 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
1187 |
|
|
|
1188 |
|
|
return;
|
1189 |
|
|
}
|
1190 |
|
|
|
1191 |
|
|
/*
|
1192 |
|
|
* search_taskQ_for_cmd - Search the SCSI task mgmt request queue for
|
1193 |
|
|
* the specified command. If found, delete
|
1194 |
|
|
* @hd: MPT_SCSI_HOST pointer
|
1195 |
|
|
*
|
1196 |
|
|
* Returns: None.
|
1197 |
|
|
*/
|
1198 |
|
|
static void
|
1199 |
|
|
search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd)
|
1200 |
|
|
{
|
1201 |
|
|
MPT_FRAME_HDR *mf;
|
1202 |
|
|
unsigned long flags;
|
1203 |
|
|
int count = 0;
|
1204 |
|
|
|
1205 |
|
|
dprintk((KERN_INFO MYNAM ": search_taskQ_for_cmd(sc=%p) called\n", sc));
|
1206 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
1207 |
|
|
if (! Q_IS_EMPTY(&hd->taskQ)) {
|
1208 |
|
|
mf = hd->taskQ.head;
|
1209 |
|
|
do {
|
1210 |
|
|
count++;
|
1211 |
|
|
if (mf->u.frame.linkage.argp1 == sc) {
|
1212 |
|
|
Q_DEL_ITEM(&mf->u.frame.linkage);
|
1213 |
|
|
hd->taskQcnt--;
|
1214 |
|
|
atomic_dec(&mpt_taskQdepth);
|
1215 |
|
|
dprintk((KERN_INFO MYNAM
|
1216 |
|
|
": Cmd %p found! Deleting.\n", sc));
|
1217 |
|
|
|
1218 |
|
|
/* Don't save mf into nextmf because
|
1219 |
|
|
* exit after command has been deleted.
|
1220 |
|
|
*/
|
1221 |
|
|
|
1222 |
|
|
/* Place the MF back on the FreeQ */
|
1223 |
|
|
Q_ADD_TAIL(&hd->ioc->FreeQ,
|
1224 |
|
|
&mf->u.frame.linkage,
|
1225 |
|
|
MPT_FRAME_HDR);
|
1226 |
|
|
#ifdef MFCNT
|
1227 |
|
|
hd->ioc->mfcnt--;
|
1228 |
|
|
#endif
|
1229 |
|
|
break;
|
1230 |
|
|
}
|
1231 |
|
|
} while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
|
1232 |
|
|
}
|
1233 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
1234 |
|
|
|
1235 |
|
|
return;
|
1236 |
|
|
}
|
1237 |
|
|
|
1238 |
|
|
#endif /* } MPT_SCSI_USE_NEW_EH */
|
1239 |
|
|
|
1240 |
|
|
|
1241 |
|
|
/*
|
1242 |
|
|
* Flush all commands on the doneQ.
|
1243 |
|
|
* Lock Q when deleting/adding members
|
1244 |
|
|
* Lock io_request_lock for OS callback.
|
1245 |
|
|
*/
|
1246 |
|
|
static void
|
1247 |
|
|
flush_doneQ(MPT_SCSI_HOST *hd)
|
1248 |
|
|
{
|
1249 |
|
|
MPT_DONE_Q *buffer;
|
1250 |
|
|
Scsi_Cmnd *SCpnt;
|
1251 |
|
|
unsigned long flags;
|
1252 |
|
|
|
1253 |
|
|
/* Flush the doneQ.
|
1254 |
|
|
*/
|
1255 |
|
|
dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
|
1256 |
|
|
while (1) {
|
1257 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
1258 |
|
|
if (Q_IS_EMPTY(&hd->doneQ)) {
|
1259 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
1260 |
|
|
break;
|
1261 |
|
|
}
|
1262 |
|
|
|
1263 |
|
|
buffer = hd->doneQ.head;
|
1264 |
|
|
/* Delete from Q
|
1265 |
|
|
*/
|
1266 |
|
|
Q_DEL_ITEM(buffer);
|
1267 |
|
|
|
1268 |
|
|
/* Set the Scsi_Cmnd pointer
|
1269 |
|
|
*/
|
1270 |
|
|
SCpnt = (Scsi_Cmnd *) buffer->argp;
|
1271 |
|
|
buffer->argp = NULL;
|
1272 |
|
|
|
1273 |
|
|
/* Add to the freeQ
|
1274 |
|
|
*/
|
1275 |
|
|
Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
|
1276 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
1277 |
|
|
|
1278 |
|
|
/* Do the OS callback.
|
1279 |
|
|
*/
|
1280 |
|
|
MPT_HOST_LOCK(flags);
|
1281 |
|
|
SCpnt->scsi_done(SCpnt);
|
1282 |
|
|
MPT_HOST_UNLOCK(flags);
|
1283 |
|
|
}
|
1284 |
|
|
|
1285 |
|
|
return;
|
1286 |
|
|
}
|
1287 |
|
|
|
1288 |
|
|
/*
|
1289 |
|
|
* Search the doneQ for a specific command. If found, delete from Q.
|
1290 |
|
|
* Calling function will finish processing.
|
1291 |
|
|
*/
|
1292 |
|
|
static void
|
1293 |
|
|
search_doneQ_for_cmd(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt)
|
1294 |
|
|
{
|
1295 |
|
|
unsigned long flags;
|
1296 |
|
|
MPT_DONE_Q *buffer;
|
1297 |
|
|
|
1298 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
1299 |
|
|
if (!Q_IS_EMPTY(&hd->doneQ)) {
|
1300 |
|
|
buffer = hd->doneQ.head;
|
1301 |
|
|
do {
|
1302 |
|
|
Scsi_Cmnd *sc = (Scsi_Cmnd *) buffer->argp;
|
1303 |
|
|
if (SCpnt == sc) {
|
1304 |
|
|
Q_DEL_ITEM(buffer);
|
1305 |
|
|
SCpnt->result = sc->result;
|
1306 |
|
|
|
1307 |
|
|
/* Set the Scsi_Cmnd pointer
|
1308 |
|
|
*/
|
1309 |
|
|
buffer->argp = NULL;
|
1310 |
|
|
|
1311 |
|
|
/* Add to the freeQ
|
1312 |
|
|
*/
|
1313 |
|
|
Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
|
1314 |
|
|
break;
|
1315 |
|
|
}
|
1316 |
|
|
} while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ);
|
1317 |
|
|
}
|
1318 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
1319 |
|
|
return;
|
1320 |
|
|
}
|
1321 |
|
|
|
1322 |
|
|
static void
|
1323 |
|
|
mptscsih_reset_timeouts (MPT_SCSI_HOST *hd)
|
1324 |
|
|
{
|
1325 |
|
|
Scsi_Cmnd *SCpnt;
|
1326 |
|
|
int ii;
|
1327 |
|
|
int max = hd->ioc->req_depth;
|
1328 |
|
|
|
1329 |
|
|
for (ii= 0; ii < max; ii++) {
|
1330 |
|
|
if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
|
1331 |
|
|
mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
|
1332 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "resetting SCpnt=%p timeout + 60HZ",
|
1333 |
|
|
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
|
1334 |
|
|
}
|
1335 |
|
|
}
|
1336 |
|
|
}
|
1337 |
|
|
|
1338 |
|
|
/*
|
1339 |
|
|
* mptscsih_flush_running_cmds - For each command found, search
|
1340 |
|
|
* Scsi_Host instance taskQ and reply to OS.
|
1341 |
|
|
* Called only if recovering from a FW reload.
|
1342 |
|
|
* @hd: Pointer to a SCSI HOST structure
|
1343 |
|
|
*
|
1344 |
|
|
* Returns: None.
|
1345 |
|
|
*
|
1346 |
|
|
* Must be called while new I/Os are being queued.
|
1347 |
|
|
*/
|
1348 |
|
|
static void
|
1349 |
|
|
mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
|
1350 |
|
|
{
|
1351 |
|
|
Scsi_Cmnd *SCpnt;
|
1352 |
|
|
MPT_FRAME_HDR *mf;
|
1353 |
|
|
MPT_DONE_Q *buffer;
|
1354 |
|
|
int ii;
|
1355 |
|
|
int max = hd->ioc->req_depth;
|
1356 |
|
|
|
1357 |
|
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
|
1358 |
|
|
unsigned long flags;
|
1359 |
|
|
#endif
|
1360 |
|
|
|
1361 |
|
|
dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
|
1362 |
|
|
for (ii= 0; ii < max; ii++) {
|
1363 |
|
|
if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
|
1364 |
|
|
|
1365 |
|
|
/* Command found.
|
1366 |
|
|
*/
|
1367 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
1368 |
|
|
/* Search taskQ, if found, delete.
|
1369 |
|
|
*/
|
1370 |
|
|
search_taskQ_for_cmd(SCpnt, hd);
|
1371 |
|
|
#endif
|
1372 |
|
|
|
1373 |
|
|
/* Search pendingQ, if found,
|
1374 |
|
|
* delete from Q. If found, do not decrement
|
1375 |
|
|
* queue_depth, command never posted.
|
1376 |
|
|
*/
|
1377 |
|
|
if (mptscsih_search_pendingQ(hd, ii) == NULL)
|
1378 |
|
|
atomic_dec(&queue_depth);
|
1379 |
|
|
|
1380 |
|
|
/* Null ScsiLookup index
|
1381 |
|
|
*/
|
1382 |
|
|
hd->ScsiLookup[ii] = NULL;
|
1383 |
|
|
|
1384 |
|
|
mf = MPT_INDEX_2_MFPTR(hd->ioc, ii);
|
1385 |
|
|
dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", mf, SCpnt));
|
1386 |
|
|
|
1387 |
|
|
/* Set status, free OS resources (SG DMA buffers)
|
1388 |
|
|
* Free driver resources (chain, msg buffers)
|
1389 |
|
|
*/
|
1390 |
|
|
if (SCpnt->use_sg) {
|
1391 |
|
|
pci_unmap_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer,
|
1392 |
|
|
SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
|
1393 |
|
|
} else if (SCpnt->request_bufflen) {
|
1394 |
|
|
scPrivate *my_priv;
|
1395 |
|
|
|
1396 |
|
|
my_priv = (scPrivate *) &SCpnt->SCp;
|
1397 |
|
|
pci_unmap_single(hd->ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
|
1398 |
|
|
SCpnt->request_bufflen,
|
1399 |
|
|
scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
|
1400 |
|
|
}
|
1401 |
|
|
SCpnt->result = DID_RESET << 16;
|
1402 |
|
|
SCpnt->host_scribble = NULL;
|
1403 |
|
|
|
1404 |
|
|
/* Free Chain buffers */
|
1405 |
|
|
mptscsih_freeChainBuffers(hd, ii);
|
1406 |
|
|
|
1407 |
|
|
/* Free Message frames */
|
1408 |
|
|
mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
|
1409 |
|
|
|
1410 |
|
|
#if 1
|
1411 |
|
|
/* Post to doneQ, do not reply until POST phase
|
1412 |
|
|
* of reset handler....prevents new commands from
|
1413 |
|
|
* being queued.
|
1414 |
|
|
*/
|
1415 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
1416 |
|
|
if (!Q_IS_EMPTY(&hd->freeQ)) {
|
1417 |
|
|
buffer = hd->freeQ.head;
|
1418 |
|
|
Q_DEL_ITEM(buffer);
|
1419 |
|
|
|
1420 |
|
|
/* Set the Scsi_Cmnd pointer
|
1421 |
|
|
*/
|
1422 |
|
|
buffer->argp = (void *)SCpnt;
|
1423 |
|
|
|
1424 |
|
|
/* Add to the doneQ
|
1425 |
|
|
*/
|
1426 |
|
|
Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
|
1427 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
1428 |
|
|
} else {
|
1429 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
1430 |
|
|
SCpnt->scsi_done(SCpnt);
|
1431 |
|
|
}
|
1432 |
|
|
#else
|
1433 |
|
|
MPT_HOST_LOCK(flags);
|
1434 |
|
|
SCpnt->scsi_done(SCpnt); /* Issue the command callback */
|
1435 |
|
|
MPT_HOST_UNLOCK(flags);
|
1436 |
|
|
#endif
|
1437 |
|
|
}
|
1438 |
|
|
}
|
1439 |
|
|
|
1440 |
|
|
return;
|
1441 |
|
|
}
|
1442 |
|
|
|
1443 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1444 |
|
|
/*
|
1445 |
|
|
* mptscsih_initChainBuffers - Allocate memory for and initialize
|
1446 |
|
|
* chain buffers, chain buffer control arrays and spinlock.
|
1447 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure
|
1448 |
|
|
* @init: If set, initialize the spin lock.
|
1449 |
|
|
*/
|
1450 |
|
|
static int
|
1451 |
|
|
mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init)
|
1452 |
|
|
{
|
1453 |
|
|
MPT_FRAME_HDR *chain;
|
1454 |
|
|
u8 *mem;
|
1455 |
|
|
unsigned long flags;
|
1456 |
|
|
int sz, ii, num_chain;
|
1457 |
|
|
int scale, num_sge;
|
1458 |
|
|
|
1459 |
|
|
/* ReqToChain size must equal the req_depth
|
1460 |
|
|
* index = req_idx
|
1461 |
|
|
*/
|
1462 |
|
|
if (hd->ReqToChain == NULL) {
|
1463 |
|
|
sz = hd->ioc->req_depth * sizeof(int);
|
1464 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
1465 |
|
|
if (mem == NULL)
|
1466 |
|
|
return -1;
|
1467 |
|
|
|
1468 |
|
|
hd->ReqToChain = (int *) mem;
|
1469 |
|
|
}
|
1470 |
|
|
for (ii = 0; ii < hd->ioc->req_depth; ii++)
|
1471 |
|
|
hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
|
1472 |
|
|
|
1473 |
|
|
/* ChainToChain size must equal the total number
|
1474 |
|
|
* of chain buffers to be allocated.
|
1475 |
|
|
* index = chain_idx
|
1476 |
|
|
*
|
1477 |
|
|
* Calculate the number of chain buffers needed(plus 1) per I/O
|
1478 |
|
|
* then multiply the the maximum number of simultaneous cmds
|
1479 |
|
|
*
|
1480 |
|
|
* num_sge = num sge in request frame + last chain buffer
|
1481 |
|
|
* scale = num sge per chain buffer if no chain element
|
1482 |
|
|
*/
|
1483 |
|
|
scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
|
1484 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64))
|
1485 |
|
|
num_sge = scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
|
1486 |
|
|
else
|
1487 |
|
|
num_sge = 1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
|
1488 |
|
|
|
1489 |
|
|
num_chain = 1;
|
1490 |
|
|
while (hd->max_sge - num_sge > 0) {
|
1491 |
|
|
num_chain++;
|
1492 |
|
|
num_sge += (scale - 1);
|
1493 |
|
|
}
|
1494 |
|
|
num_chain++;
|
1495 |
|
|
|
1496 |
|
|
if ((int) hd->ioc->chip_type > (int) FC929)
|
1497 |
|
|
num_chain *= MPT_SCSI_CAN_QUEUE;
|
1498 |
|
|
else
|
1499 |
|
|
num_chain *= MPT_FC_CAN_QUEUE;
|
1500 |
|
|
|
1501 |
|
|
hd->num_chain = num_chain;
|
1502 |
|
|
|
1503 |
|
|
sz = num_chain * sizeof(int);
|
1504 |
|
|
if (hd->ChainToChain == NULL) {
|
1505 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
1506 |
|
|
if (mem == NULL)
|
1507 |
|
|
return -1;
|
1508 |
|
|
|
1509 |
|
|
hd->ChainToChain = (int *) mem;
|
1510 |
|
|
} else {
|
1511 |
|
|
mem = (u8 *) hd->ChainToChain;
|
1512 |
|
|
}
|
1513 |
|
|
memset(mem, 0xFF, sz);
|
1514 |
|
|
|
1515 |
|
|
sz = num_chain * hd->ioc->req_sz;
|
1516 |
|
|
if (hd->ChainBuffer == NULL) {
|
1517 |
|
|
/* Allocate free chain buffer pool
|
1518 |
|
|
*/
|
1519 |
|
|
mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
|
1520 |
|
|
if (mem == NULL)
|
1521 |
|
|
return -1;
|
1522 |
|
|
|
1523 |
|
|
hd->ChainBuffer = (u8*)mem;
|
1524 |
|
|
} else {
|
1525 |
|
|
mem = (u8 *) hd->ChainBuffer;
|
1526 |
|
|
}
|
1527 |
|
|
memset(mem, 0, sz);
|
1528 |
|
|
|
1529 |
|
|
dprintk((KERN_INFO " ChainBuffer @ %p(%p), sz=%d\n",
|
1530 |
|
|
hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz));
|
1531 |
|
|
|
1532 |
|
|
/* Initialize the free chain Q.
|
1533 |
|
|
*/
|
1534 |
|
|
if (init) {
|
1535 |
|
|
spin_lock_init(&hd->FreeChainQlock);
|
1536 |
|
|
}
|
1537 |
|
|
|
1538 |
|
|
spin_lock_irqsave (&hd->FreeChainQlock, flags);
|
1539 |
|
|
Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR);
|
1540 |
|
|
|
1541 |
|
|
/* Post the chain buffers to the FreeChainQ.
|
1542 |
|
|
*/
|
1543 |
|
|
mem = (u8 *)hd->ChainBuffer;
|
1544 |
|
|
for (ii=0; ii < num_chain; ii++) {
|
1545 |
|
|
chain = (MPT_FRAME_HDR *) mem;
|
1546 |
|
|
Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
|
1547 |
|
|
mem += hd->ioc->req_sz;
|
1548 |
|
|
}
|
1549 |
|
|
spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
|
1550 |
|
|
|
1551 |
|
|
return 0;
|
1552 |
|
|
}
|
1553 |
|
|
|
1554 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1555 |
|
|
/*
|
1556 |
|
|
* Hack! It might be nice to report if a device is returning QUEUE_FULL
|
1557 |
|
|
* but maybe not each and every time...
|
1558 |
|
|
*/
|
1559 |
|
|
static long last_queue_full = 0;
|
1560 |
|
|
|
1561 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1562 |
|
|
/*
|
1563 |
|
|
* mptscsih_report_queue_full - Report QUEUE_FULL status returned
|
1564 |
|
|
* from a SCSI target device.
|
1565 |
|
|
* @sc: Pointer to Scsi_Cmnd structure
|
1566 |
|
|
* @pScsiReply: Pointer to SCSIIOReply_t
|
1567 |
|
|
* @pScsiReq: Pointer to original SCSI request
|
1568 |
|
|
*
|
1569 |
|
|
* This routine periodically reports QUEUE_FULL status returned from a
|
1570 |
|
|
* SCSI target device. It reports this to the console via kernel
|
1571 |
|
|
* printk() API call, not more than once every 10 seconds.
|
1572 |
|
|
*/
|
1573 |
|
|
static void
|
1574 |
|
|
mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
|
1575 |
|
|
{
|
1576 |
|
|
long time = jiffies;
|
1577 |
|
|
|
1578 |
|
|
if (time - last_queue_full > 10 * HZ) {
|
1579 |
|
|
char *ioc_str = "ioc?";
|
1580 |
|
|
|
1581 |
|
|
if (sc->host != NULL && sc->host->hostdata != NULL)
|
1582 |
|
|
ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name;
|
1583 |
|
|
printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
|
1584 |
|
|
ioc_str, 0, sc->target, sc->lun);
|
1585 |
|
|
last_queue_full = time;
|
1586 |
|
|
}
|
1587 |
|
|
}
|
1588 |
|
|
|
1589 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1590 |
|
|
static int BeenHereDoneThat = 0;
|
1591 |
|
|
static char *info_kbuf = NULL;
|
1592 |
|
|
|
1593 |
|
|
/* SCSI host fops start here... */
|
1594 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1595 |
|
|
/**
|
1596 |
|
|
* mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
|
1597 |
|
|
* linux scsi mid-layer.
|
1598 |
|
|
* @tpnt: Pointer to Scsi_Host_Template structure
|
1599 |
|
|
*
|
1600 |
|
|
* (linux Scsi_Host_Template.detect routine)
|
1601 |
|
|
*
|
1602 |
|
|
* Returns number of SCSI host adapters that were successfully
|
1603 |
|
|
* registered with the linux scsi mid-layer via the scsi_register()
|
1604 |
|
|
* API call.
|
1605 |
|
|
*/
|
1606 |
|
|
int
|
1607 |
|
|
mptscsih_detect(Scsi_Host_Template *tpnt)
|
1608 |
|
|
{
|
1609 |
|
|
struct Scsi_Host *sh;
|
1610 |
|
|
MPT_SCSI_HOST *hd;
|
1611 |
|
|
MPT_ADAPTER *ioc;
|
1612 |
|
|
MPT_DONE_Q *freedoneQ;
|
1613 |
|
|
unsigned long flags;
|
1614 |
|
|
int sz, ii;
|
1615 |
|
|
int numSGE = 0;
|
1616 |
|
|
int scale;
|
1617 |
|
|
int ioc_cap;
|
1618 |
|
|
u8 *mem;
|
1619 |
|
|
|
1620 |
|
|
if (! BeenHereDoneThat++) {
|
1621 |
|
|
show_mptmod_ver(my_NAME, my_VERSION);
|
1622 |
|
|
|
1623 |
|
|
ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
|
1624 |
|
|
ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
|
1625 |
|
|
ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER);
|
1626 |
|
|
|
1627 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
1628 |
|
|
spin_lock_init(&mytaskQ_lock);
|
1629 |
|
|
#endif
|
1630 |
|
|
|
1631 |
|
|
if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
|
1632 |
|
|
dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
|
1633 |
|
|
} else {
|
1634 |
|
|
/* FIXME! */
|
1635 |
|
|
}
|
1636 |
|
|
|
1637 |
|
|
if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {
|
1638 |
|
|
dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
|
1639 |
|
|
} else {
|
1640 |
|
|
/* FIXME! */
|
1641 |
|
|
}
|
1642 |
|
|
}
|
1643 |
|
|
dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));
|
1644 |
|
|
|
1645 |
|
|
#ifdef MODULE
|
1646 |
|
|
/* Evaluate the command line arguments, if any */
|
1647 |
|
|
if (mptscsih)
|
1648 |
|
|
mptscsih_setup(mptscsih);
|
1649 |
|
|
#endif
|
1650 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
1651 |
|
|
atomic_set(&mpt_taskQdepth, 0);
|
1652 |
|
|
#endif
|
1653 |
|
|
|
1654 |
|
|
for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
|
1655 |
|
|
/* 20010202 -sralston
|
1656 |
|
|
* Added sanity check on readiness of the MPT adapter.
|
1657 |
|
|
*/
|
1658 |
|
|
if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
|
1659 |
|
|
printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
|
1660 |
|
|
ioc->name);
|
1661 |
|
|
continue;
|
1662 |
|
|
}
|
1663 |
|
|
|
1664 |
|
|
if (!ioc->active) {
|
1665 |
|
|
printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
|
1666 |
|
|
ioc->name);
|
1667 |
|
|
continue;
|
1668 |
|
|
}
|
1669 |
|
|
|
1670 |
|
|
|
1671 |
|
|
/* Sanity check - ensure at least 1 port is INITIATOR capable
|
1672 |
|
|
*/
|
1673 |
|
|
ioc_cap = 0;
|
1674 |
|
|
for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
|
1675 |
|
|
if (ioc->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)
|
1676 |
|
|
ioc_cap ++;
|
1677 |
|
|
}
|
1678 |
|
|
|
1679 |
|
|
if (!ioc_cap) {
|
1680 |
|
|
printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
|
1681 |
|
|
ioc->name, ioc);
|
1682 |
|
|
continue;
|
1683 |
|
|
}
|
1684 |
|
|
|
1685 |
|
|
|
1686 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
|
1687 |
|
|
tpnt->proc_dir = &proc_mpt_scsihost;
|
1688 |
|
|
#endif
|
1689 |
|
|
tpnt->proc_info = mptscsih_proc_info;
|
1690 |
|
|
sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
|
1691 |
|
|
if (sh != NULL) {
|
1692 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
1693 |
|
|
sh->io_port = 0;
|
1694 |
|
|
sh->n_io_port = 0;
|
1695 |
|
|
sh->irq = 0;
|
1696 |
|
|
|
1697 |
|
|
/* Yikes! This is important!
|
1698 |
|
|
* Otherwise, by default, linux
|
1699 |
|
|
* only scans target IDs 0-7!
|
1700 |
|
|
* pfactsN->MaxDevices unreliable
|
1701 |
|
|
* (not supported in early
|
1702 |
|
|
* versions of the FW).
|
1703 |
|
|
* max_id = 1 + actual max id,
|
1704 |
|
|
* max_lun = 1 + actual last lun,
|
1705 |
|
|
* see hosts.h :o(
|
1706 |
|
|
*/
|
1707 |
|
|
if ((int)ioc->chip_type > (int)FC929)
|
1708 |
|
|
sh->max_id = MPT_MAX_SCSI_DEVICES;
|
1709 |
|
|
else {
|
1710 |
|
|
/* For FC, increase the queue depth
|
1711 |
|
|
* from MPT_SCSI_CAN_QUEUE (31)
|
1712 |
|
|
* to MPT_FC_CAN_QUEUE (63).
|
1713 |
|
|
*/
|
1714 |
|
|
sh->can_queue = MPT_FC_CAN_QUEUE;
|
1715 |
|
|
sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
|
1716 |
|
|
}
|
1717 |
|
|
sh->max_lun = MPT_LAST_LUN + 1;
|
1718 |
|
|
|
1719 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
|
1720 |
|
|
sh->max_sectors = MPT_SCSI_MAX_SECTORS;
|
1721 |
|
|
#endif
|
1722 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO
|
1723 |
|
|
sh->highmem_io = 1;
|
1724 |
|
|
#endif
|
1725 |
|
|
/* MPI uses {port, bus, id, lun}, but logically maps
|
1726 |
|
|
* devices on different ports to different buses, i.e.,
|
1727 |
|
|
* bus 1 may be the 2nd bus on port 0 or the 1st bus on port 1.
|
1728 |
|
|
* Map bus to channel, ignore port number in SCSI....
|
1729 |
|
|
* hd->port = 0;
|
1730 |
|
|
* If max_channel > 0, need to adjust mem alloc, free, DV
|
1731 |
|
|
* and all access to VirtDev
|
1732 |
|
|
*/
|
1733 |
|
|
sh->max_channel = 0;
|
1734 |
|
|
sh->this_id = ioc->pfacts[0].PortSCSIID;
|
1735 |
|
|
|
1736 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
|
1737 |
|
|
/* OS entry to allow host drivers to force
|
1738 |
|
|
* a queue depth on a per device basis.
|
1739 |
|
|
*/
|
1740 |
|
|
sh->select_queue_depths = mptscsih_select_queue_depths;
|
1741 |
|
|
#endif
|
1742 |
|
|
/* Required entry.
|
1743 |
|
|
*/
|
1744 |
|
|
sh->unique_id = ioc->id;
|
1745 |
|
|
|
1746 |
|
|
/* Verify that we won't exceed the maximum
|
1747 |
|
|
* number of chain buffers
|
1748 |
|
|
* We can optimize: ZZ = req_sz/sizeof(SGE)
|
1749 |
|
|
* For 32bit SGE's:
|
1750 |
|
|
* numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
|
1751 |
|
|
* + (req_sz - 64)/sizeof(SGE)
|
1752 |
|
|
* A slightly different algorithm is required for
|
1753 |
|
|
* 64bit SGEs.
|
1754 |
|
|
*/
|
1755 |
|
|
scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
|
1756 |
|
|
if (sizeof(dma_addr_t) == sizeof(u64)) {
|
1757 |
|
|
numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
|
1758 |
|
|
(ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
|
1759 |
|
|
} else {
|
1760 |
|
|
numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
|
1761 |
|
|
(ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
|
1762 |
|
|
}
|
1763 |
|
|
|
1764 |
|
|
if (numSGE < sh->sg_tablesize) {
|
1765 |
|
|
/* Reset this value */
|
1766 |
|
|
dprintk((MYIOC_s_INFO_FMT
|
1767 |
|
|
"Resetting sg_tablesize to %d from %d\n",
|
1768 |
|
|
ioc->name, numSGE, sh->sg_tablesize));
|
1769 |
|
|
sh->sg_tablesize = numSGE;
|
1770 |
|
|
}
|
1771 |
|
|
|
1772 |
|
|
/* Set the pci device pointer in Scsi_Host structure.
|
1773 |
|
|
*/
|
1774 |
|
|
scsi_set_pci_device(sh, ioc->pcidev);
|
1775 |
|
|
|
1776 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
1777 |
|
|
|
1778 |
|
|
hd = (MPT_SCSI_HOST *) sh->hostdata;
|
1779 |
|
|
hd->ioc = ioc;
|
1780 |
|
|
hd->max_sge = sh->sg_tablesize;
|
1781 |
|
|
|
1782 |
|
|
if ((int)ioc->chip_type > (int)FC929)
|
1783 |
|
|
hd->is_spi = 1;
|
1784 |
|
|
|
1785 |
|
|
if (DmpService &&
|
1786 |
|
|
(ioc->chip_type == FC919 || ioc->chip_type == FC929))
|
1787 |
|
|
hd->is_multipath = 1;
|
1788 |
|
|
|
1789 |
|
|
/* SCSI needs Scsi_Cmnd lookup table!
|
1790 |
|
|
* (with size equal to req_depth*PtrSz!)
|
1791 |
|
|
*/
|
1792 |
|
|
sz = hd->ioc->req_depth * sizeof(void *);
|
1793 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
1794 |
|
|
if (mem == NULL)
|
1795 |
|
|
goto done;
|
1796 |
|
|
|
1797 |
|
|
memset(mem, 0, sz);
|
1798 |
|
|
hd->ScsiLookup = (struct scsi_cmnd **) mem;
|
1799 |
|
|
|
1800 |
|
|
dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
|
1801 |
|
|
ioc->name, hd->ScsiLookup, sz));
|
1802 |
|
|
|
1803 |
|
|
if (mptscsih_initChainBuffers(hd, 1) < 0)
|
1804 |
|
|
goto done;
|
1805 |
|
|
|
1806 |
|
|
/* Allocate memory for free and doneQ's
|
1807 |
|
|
*/
|
1808 |
|
|
sz = sh->can_queue * sizeof(MPT_DONE_Q);
|
1809 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
1810 |
|
|
if (mem == NULL)
|
1811 |
|
|
goto done;
|
1812 |
|
|
|
1813 |
|
|
memset(mem, 0xFF, sz);
|
1814 |
|
|
hd->memQ = mem;
|
1815 |
|
|
|
1816 |
|
|
/* Initialize the free, done and pending Qs.
|
1817 |
|
|
*/
|
1818 |
|
|
Q_INIT(&hd->freeQ, MPT_DONE_Q);
|
1819 |
|
|
Q_INIT(&hd->doneQ, MPT_DONE_Q);
|
1820 |
|
|
Q_INIT(&hd->pendingQ, MPT_DONE_Q);
|
1821 |
|
|
spin_lock_init(&hd->freedoneQlock);
|
1822 |
|
|
|
1823 |
|
|
mem = hd->memQ;
|
1824 |
|
|
for (ii=0; ii < sh->can_queue; ii++) {
|
1825 |
|
|
freedoneQ = (MPT_DONE_Q *) mem;
|
1826 |
|
|
Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
|
1827 |
|
|
mem += sizeof(MPT_DONE_Q);
|
1828 |
|
|
}
|
1829 |
|
|
|
1830 |
|
|
/* Initialize this Scsi_Host
|
1831 |
|
|
* internal task Q.
|
1832 |
|
|
*/
|
1833 |
|
|
Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
|
1834 |
|
|
hd->taskQcnt = 0;
|
1835 |
|
|
|
1836 |
|
|
/* Allocate memory for the device structures.
|
1837 |
|
|
* A non-Null pointer at an offset
|
1838 |
|
|
* indicates a device exists.
|
1839 |
|
|
* max_id = 1 + maximum id (hosts.h)
|
1840 |
|
|
*/
|
1841 |
|
|
sz = sh->max_id * sizeof(void *);
|
1842 |
|
|
mem = kmalloc(sz, GFP_ATOMIC);
|
1843 |
|
|
if (mem == NULL)
|
1844 |
|
|
goto done;
|
1845 |
|
|
|
1846 |
|
|
memset(mem, 0, sz);
|
1847 |
|
|
hd->Targets = (VirtDevice **) mem;
|
1848 |
|
|
|
1849 |
|
|
dprintk((KERN_INFO " Targets @ %p, sz=%d\n", hd->Targets, sz));
|
1850 |
|
|
|
1851 |
|
|
|
1852 |
|
|
/* Clear the TM flags
|
1853 |
|
|
*/
|
1854 |
|
|
hd->tmPending = 0;
|
1855 |
|
|
#ifdef MPT_SCSI_USE_NEW_EH
|
1856 |
|
|
hd->tmState = TM_STATE_NONE;
|
1857 |
|
|
#endif
|
1858 |
|
|
hd->resetPending = 0;
|
1859 |
|
|
hd->abortSCpnt = NULL;
|
1860 |
|
|
hd->tmPtr = NULL;
|
1861 |
|
|
hd->numTMrequests = 0;
|
1862 |
|
|
|
1863 |
|
|
/* Clear the pointer used to store
|
1864 |
|
|
* single-threaded commands, i.e., those
|
1865 |
|
|
* issued during a bus scan, dv and
|
1866 |
|
|
* configuration pages.
|
1867 |
|
|
*/
|
1868 |
|
|
hd->cmdPtr = NULL;
|
1869 |
|
|
|
1870 |
|
|
/* Attach the SCSI Host to the IOC structure
|
1871 |
|
|
*/
|
1872 |
|
|
ioc->sh = sh;
|
1873 |
|
|
|
1874 |
|
|
/* Initialize this SCSI Hosts' timers
|
1875 |
|
|
* To use, set the timer expires field
|
1876 |
|
|
* and add_timer
|
1877 |
|
|
*/
|
1878 |
|
|
init_timer(&hd->timer);
|
1879 |
|
|
hd->timer.data = (unsigned long) hd;
|
1880 |
|
|
hd->timer.function = mptscsih_timer_expired;
|
1881 |
|
|
|
1882 |
|
|
init_timer(&hd->TMtimer);
|
1883 |
|
|
hd->TMtimer.data = (unsigned long) hd;
|
1884 |
|
|
hd->TMtimer.function = mptscsih_taskmgmt_timeout;
|
1885 |
|
|
hd->qtag_tick = jiffies;
|
1886 |
|
|
|
1887 |
|
|
/* Moved Earlier Pam D */
|
1888 |
|
|
/* ioc->sh = sh; */
|
1889 |
|
|
|
1890 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
1891 |
|
|
hd->ioc->timeout_hard = 0;
|
1892 |
|
|
hd->ioc->timeout_delta = 30 * HZ;
|
1893 |
|
|
hd->ioc->timeout_maxcnt = 0;
|
1894 |
|
|
hd->ioc->timeout_cnt = 0;
|
1895 |
|
|
for (ii=0; ii < 8; ii++)
|
1896 |
|
|
foo_to[ii] = NULL;
|
1897 |
|
|
#endif
|
1898 |
|
|
|
1899 |
|
|
if (hd->is_spi) {
|
1900 |
|
|
/* Update with the driver setup
|
1901 |
|
|
* values.
|
1902 |
|
|
*/
|
1903 |
|
|
if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)
|
1904 |
|
|
hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;
|
1905 |
|
|
if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)
|
1906 |
|
|
hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac;
|
1907 |
|
|
|
1908 |
|
|
if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
|
1909 |
|
|
hd->ioc->spi_data.maxSyncOffset = 0;
|
1910 |
|
|
|
1911 |
|
|
hd->ioc->spi_data.Saf_Te = driver_setup.saf_te;
|
1912 |
|
|
|
1913 |
|
|
hd->negoNvram = 0;
|
1914 |
|
|
#ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
1915 |
|
|
hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
|
1916 |
|
|
#endif
|
1917 |
|
|
if (driver_setup.dv == 0)
|
1918 |
|
|
hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
|
1919 |
|
|
|
1920 |
|
|
hd->ioc->spi_data.forceDv = 0;
|
1921 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
|
1922 |
|
|
hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
|
1923 |
|
|
|
1924 |
|
|
if (hd->negoNvram == 0) {
|
1925 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
|
1926 |
|
|
hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE;
|
1927 |
|
|
}
|
1928 |
|
|
|
1929 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
1930 |
|
|
"dv %x width %x factor %x saf_te %x\n",
|
1931 |
|
|
hd->ioc->name, driver_setup.dv,
|
1932 |
|
|
driver_setup.max_width,
|
1933 |
|
|
driver_setup.min_sync_fac,
|
1934 |
|
|
driver_setup.saf_te));
|
1935 |
|
|
}
|
1936 |
|
|
|
1937 |
|
|
mpt_scsi_hosts++;
|
1938 |
|
|
}
|
1939 |
|
|
}
|
1940 |
|
|
|
1941 |
|
|
done:
|
1942 |
|
|
if (mpt_scsi_hosts > 0)
|
1943 |
|
|
register_reboot_notifier(&mptscsih_notifier);
|
1944 |
|
|
else {
|
1945 |
|
|
mpt_reset_deregister(ScsiDoneCtx);
|
1946 |
|
|
dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
|
1947 |
|
|
|
1948 |
|
|
mpt_event_deregister(ScsiDoneCtx);
|
1949 |
|
|
dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
|
1950 |
|
|
|
1951 |
|
|
mpt_deregister(ScsiScanDvCtx);
|
1952 |
|
|
mpt_deregister(ScsiTaskCtx);
|
1953 |
|
|
mpt_deregister(ScsiDoneCtx);
|
1954 |
|
|
|
1955 |
|
|
if (info_kbuf != NULL)
|
1956 |
|
|
kfree(info_kbuf);
|
1957 |
|
|
}
|
1958 |
|
|
|
1959 |
|
|
return mpt_scsi_hosts;
|
1960 |
|
|
}
|
1961 |
|
|
|
1962 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1963 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
1964 |
|
|
/**
|
1965 |
|
|
* mptscsih_release - Unregister SCSI host from linux scsi mid-layer
|
1966 |
|
|
* @host: Pointer to Scsi_Host structure
|
1967 |
|
|
*
|
1968 |
|
|
* (linux Scsi_Host_Template.release routine)
|
1969 |
|
|
* This routine releases all resources associated with the SCSI host
|
1970 |
|
|
* adapter.
|
1971 |
|
|
*
|
1972 |
|
|
* Returns 0 for success.
|
1973 |
|
|
*/
|
1974 |
|
|
int
|
1975 |
|
|
mptscsih_release(struct Scsi_Host *host)
|
1976 |
|
|
{
|
1977 |
|
|
MPT_SCSI_HOST *hd;
|
1978 |
|
|
int count;
|
1979 |
|
|
unsigned long flags;
|
1980 |
|
|
|
1981 |
|
|
hd = (MPT_SCSI_HOST *) host->hostdata;
|
1982 |
|
|
|
1983 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
1984 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
1985 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, flags);
|
1986 |
|
|
dvtaskQ_release = 1;
|
1987 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
1988 |
|
|
#endif
|
1989 |
|
|
|
1990 |
|
|
count = 10 * HZ;
|
1991 |
|
|
spin_lock_irqsave(&mytaskQ_lock, flags);
|
1992 |
|
|
if (mytaskQ_bh_active) {
|
1993 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
1994 |
|
|
dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
|
1995 |
|
|
clean_taskQ(hd);
|
1996 |
|
|
|
1997 |
|
|
while(mytaskQ_bh_active && --count) {
|
1998 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
1999 |
|
|
schedule_timeout(1);
|
2000 |
|
|
}
|
2001 |
|
|
} else {
|
2002 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
2003 |
|
|
}
|
2004 |
|
|
if (!count)
|
2005 |
|
|
printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");
|
2006 |
|
|
|
2007 |
|
|
#endif
|
2008 |
|
|
|
2009 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
2010 |
|
|
/* Check DV thread active */
|
2011 |
|
|
count = 10 * HZ;
|
2012 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, flags);
|
2013 |
|
|
if (dvtaskQ_active) {
|
2014 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
2015 |
|
|
while(dvtaskQ_active && --count) {
|
2016 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2017 |
|
|
schedule_timeout(1);
|
2018 |
|
|
}
|
2019 |
|
|
} else {
|
2020 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
2021 |
|
|
}
|
2022 |
|
|
if (!count)
|
2023 |
|
|
printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
|
2024 |
|
|
#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
|
2025 |
|
|
else
|
2026 |
|
|
printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
|
2027 |
|
|
#endif
|
2028 |
|
|
#endif
|
2029 |
|
|
|
2030 |
|
|
unregister_reboot_notifier(&mptscsih_notifier);
|
2031 |
|
|
|
2032 |
|
|
if (hd != NULL) {
|
2033 |
|
|
int sz1, sz2, sz3, sztarget=0;
|
2034 |
|
|
int szr2chain = 0;
|
2035 |
|
|
int szc2chain = 0;
|
2036 |
|
|
int szchain = 0;
|
2037 |
|
|
int szQ = 0;
|
2038 |
|
|
|
2039 |
|
|
/* Synchronize disk caches
|
2040 |
|
|
*/
|
2041 |
|
|
(void) mptscsih_synchronize_cache(hd, 0);
|
2042 |
|
|
|
2043 |
|
|
sz1 = sz2 = sz3 = 0;
|
2044 |
|
|
|
2045 |
|
|
if (hd->ScsiLookup != NULL) {
|
2046 |
|
|
sz1 = hd->ioc->req_depth * sizeof(void *);
|
2047 |
|
|
kfree(hd->ScsiLookup);
|
2048 |
|
|
hd->ScsiLookup = NULL;
|
2049 |
|
|
}
|
2050 |
|
|
|
2051 |
|
|
if (hd->ReqToChain != NULL) {
|
2052 |
|
|
szr2chain = hd->ioc->req_depth * sizeof(int);
|
2053 |
|
|
kfree(hd->ReqToChain);
|
2054 |
|
|
hd->ReqToChain = NULL;
|
2055 |
|
|
}
|
2056 |
|
|
|
2057 |
|
|
if (hd->ChainToChain != NULL) {
|
2058 |
|
|
szc2chain = hd->num_chain * sizeof(int);
|
2059 |
|
|
kfree(hd->ChainToChain);
|
2060 |
|
|
hd->ChainToChain = NULL;
|
2061 |
|
|
}
|
2062 |
|
|
|
2063 |
|
|
if (hd->ChainBuffer != NULL) {
|
2064 |
|
|
sz2 = hd->num_chain * hd->ioc->req_sz;
|
2065 |
|
|
szchain = szr2chain + szc2chain + sz2;
|
2066 |
|
|
|
2067 |
|
|
pci_free_consistent(hd->ioc->pcidev, sz2,
|
2068 |
|
|
hd->ChainBuffer, hd->ChainBufferDMA);
|
2069 |
|
|
hd->ChainBuffer = NULL;
|
2070 |
|
|
}
|
2071 |
|
|
|
2072 |
|
|
if (hd->memQ != NULL) {
|
2073 |
|
|
szQ = host->can_queue * sizeof(MPT_DONE_Q);
|
2074 |
|
|
kfree(hd->memQ);
|
2075 |
|
|
hd->memQ = NULL;
|
2076 |
|
|
}
|
2077 |
|
|
|
2078 |
|
|
if (hd->Targets != NULL) {
|
2079 |
|
|
int max, ii;
|
2080 |
|
|
|
2081 |
|
|
/*
|
2082 |
|
|
* Free any target structures that were allocated.
|
2083 |
|
|
*/
|
2084 |
|
|
if (hd->is_spi) {
|
2085 |
|
|
max = MPT_MAX_SCSI_DEVICES;
|
2086 |
|
|
} else {
|
2087 |
|
|
max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
|
2088 |
|
|
}
|
2089 |
|
|
for (ii=0; ii < max; ii++) {
|
2090 |
|
|
if (hd->Targets[ii]) {
|
2091 |
|
|
kfree(hd->Targets[ii]);
|
2092 |
|
|
hd->Targets[ii] = NULL;
|
2093 |
|
|
sztarget += sizeof(VirtDevice);
|
2094 |
|
|
}
|
2095 |
|
|
}
|
2096 |
|
|
|
2097 |
|
|
/*
|
2098 |
|
|
* Free pointer array.
|
2099 |
|
|
*/
|
2100 |
|
|
sz3 = max * sizeof(void *);
|
2101 |
|
|
kfree(hd->Targets);
|
2102 |
|
|
hd->Targets = NULL;
|
2103 |
|
|
}
|
2104 |
|
|
|
2105 |
|
|
dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
|
2106 |
|
|
hd->ioc->name, sz1, szchain, sz3, sztarget));
|
2107 |
|
|
dprintk(("Free'd done and free Q (%d) memory\n", szQ));
|
2108 |
|
|
}
|
2109 |
|
|
/* NULL the Scsi_Host pointer
|
2110 |
|
|
*/
|
2111 |
|
|
hd->ioc->sh = NULL;
|
2112 |
|
|
scsi_unregister(host);
|
2113 |
|
|
|
2114 |
|
|
if (mpt_scsi_hosts) {
|
2115 |
|
|
if (--mpt_scsi_hosts == 0) {
|
2116 |
|
|
mpt_reset_deregister(ScsiDoneCtx);
|
2117 |
|
|
dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
|
2118 |
|
|
|
2119 |
|
|
mpt_event_deregister(ScsiDoneCtx);
|
2120 |
|
|
dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
|
2121 |
|
|
|
2122 |
|
|
mpt_deregister(ScsiScanDvCtx);
|
2123 |
|
|
mpt_deregister(ScsiTaskCtx);
|
2124 |
|
|
mpt_deregister(ScsiDoneCtx);
|
2125 |
|
|
|
2126 |
|
|
if (info_kbuf != NULL)
|
2127 |
|
|
kfree(info_kbuf);
|
2128 |
|
|
}
|
2129 |
|
|
}
|
2130 |
|
|
|
2131 |
|
|
return 0;
|
2132 |
|
|
}
|
2133 |
|
|
|
2134 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2135 |
|
|
/**
|
2136 |
|
|
* mptscsih_halt - Process the reboot notification
|
2137 |
|
|
* @nb: Pointer to a struct notifier_block (ignored)
|
2138 |
|
|
* @event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF)
|
2139 |
|
|
* @buf: Pointer to a data buffer (ignored)
|
2140 |
|
|
*
|
2141 |
|
|
* This routine called if a system shutdown or reboot is to occur.
|
2142 |
|
|
*
|
2143 |
|
|
* Return NOTIFY_DONE if this is something other than a reboot message.
|
2144 |
|
|
* NOTIFY_OK if this is a reboot message.
|
2145 |
|
|
*/
|
2146 |
|
|
static int
|
2147 |
|
|
mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
|
2148 |
|
|
{
|
2149 |
|
|
MPT_ADAPTER *ioc;
|
2150 |
|
|
MPT_SCSI_HOST *hd;
|
2151 |
|
|
|
2152 |
|
|
/* Ignore all messages other than reboot message
|
2153 |
|
|
*/
|
2154 |
|
|
if ((event != SYS_RESTART) && (event != SYS_HALT)
|
2155 |
|
|
&& (event != SYS_POWER_OFF))
|
2156 |
|
|
return (NOTIFY_DONE);
|
2157 |
|
|
|
2158 |
|
|
for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
|
2159 |
|
|
/* Flush the cache of this adapter
|
2160 |
|
|
*/
|
2161 |
|
|
if (ioc->sh) {
|
2162 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
2163 |
|
|
if (hd) {
|
2164 |
|
|
mptscsih_synchronize_cache(hd, 0);
|
2165 |
|
|
}
|
2166 |
|
|
}
|
2167 |
|
|
}
|
2168 |
|
|
|
2169 |
|
|
unregister_reboot_notifier(&mptscsih_notifier);
|
2170 |
|
|
return NOTIFY_OK;
|
2171 |
|
|
}
|
2172 |
|
|
|
2173 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2174 |
|
|
/**
|
2175 |
|
|
* mptscsih_info - Return information about MPT adapter
|
2176 |
|
|
* @SChost: Pointer to Scsi_Host structure
|
2177 |
|
|
*
|
2178 |
|
|
* (linux Scsi_Host_Template.info routine)
|
2179 |
|
|
*
|
2180 |
|
|
* Returns pointer to buffer where information was written.
|
2181 |
|
|
*/
|
2182 |
|
|
const char *
|
2183 |
|
|
mptscsih_info(struct Scsi_Host *SChost)
|
2184 |
|
|
{
|
2185 |
|
|
MPT_SCSI_HOST *h;
|
2186 |
|
|
int size = 0;
|
2187 |
|
|
|
2188 |
|
|
if (info_kbuf == NULL)
|
2189 |
|
|
if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
|
2190 |
|
|
return info_kbuf;
|
2191 |
|
|
|
2192 |
|
|
h = (MPT_SCSI_HOST *)SChost->hostdata;
|
2193 |
|
|
info_kbuf[0] = '\0';
|
2194 |
|
|
if (h) {
|
2195 |
|
|
mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
|
2196 |
|
|
info_kbuf[size-1] = '\0';
|
2197 |
|
|
}
|
2198 |
|
|
|
2199 |
|
|
return info_kbuf;
|
2200 |
|
|
}
|
2201 |
|
|
|
2202 |
|
|
struct info_str {
|
2203 |
|
|
char *buffer;
|
2204 |
|
|
int length;
|
2205 |
|
|
int offset;
|
2206 |
|
|
int pos;
|
2207 |
|
|
};
|
2208 |
|
|
|
2209 |
|
|
static void copy_mem_info(struct info_str *info, char *data, int len)
|
2210 |
|
|
{
|
2211 |
|
|
if (info->pos + len > info->length)
|
2212 |
|
|
len = info->length - info->pos;
|
2213 |
|
|
|
2214 |
|
|
if (info->pos + len < info->offset) {
|
2215 |
|
|
info->pos += len;
|
2216 |
|
|
return;
|
2217 |
|
|
}
|
2218 |
|
|
|
2219 |
|
|
if (info->pos < info->offset) {
|
2220 |
|
|
data += (info->offset - info->pos);
|
2221 |
|
|
len -= (info->offset - info->pos);
|
2222 |
|
|
}
|
2223 |
|
|
|
2224 |
|
|
if (len > 0) {
|
2225 |
|
|
memcpy(info->buffer + info->pos, data, len);
|
2226 |
|
|
info->pos += len;
|
2227 |
|
|
}
|
2228 |
|
|
}
|
2229 |
|
|
|
2230 |
|
|
static int copy_info(struct info_str *info, char *fmt, ...)
|
2231 |
|
|
{
|
2232 |
|
|
va_list args;
|
2233 |
|
|
char buf[81];
|
2234 |
|
|
int len;
|
2235 |
|
|
|
2236 |
|
|
va_start(args, fmt);
|
2237 |
|
|
len = vsprintf(buf, fmt, args);
|
2238 |
|
|
va_end(args);
|
2239 |
|
|
|
2240 |
|
|
copy_mem_info(info, buf, len);
|
2241 |
|
|
return len;
|
2242 |
|
|
}
|
2243 |
|
|
|
2244 |
|
|
static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
|
2245 |
|
|
{
|
2246 |
|
|
struct info_str info;
|
2247 |
|
|
|
2248 |
|
|
info.buffer = pbuf;
|
2249 |
|
|
info.length = len;
|
2250 |
|
|
info.offset = offset;
|
2251 |
|
|
info.pos = 0;
|
2252 |
|
|
|
2253 |
|
|
copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
|
2254 |
|
|
copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
|
2255 |
|
|
copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
|
2256 |
|
|
copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
|
2257 |
|
|
|
2258 |
|
|
return ((info.pos > info.offset) ? info.pos - info.offset : 0);
|
2259 |
|
|
}
|
2260 |
|
|
|
2261 |
|
|
#ifndef MPTSCSIH_DBG_TIMEOUT
|
2262 |
|
|
static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len)
|
2263 |
|
|
{
|
2264 |
|
|
/* Not yet implemented */
|
2265 |
|
|
return len;
|
2266 |
|
|
}
|
2267 |
|
|
#else
|
2268 |
|
|
#define is_digit(c) ((c) >= '0' && (c) <= '9')
|
2269 |
|
|
#define digit_to_bin(c) ((c) - '0')
|
2270 |
|
|
#define is_space(c) ((c) == ' ' || (c) == '\t')
|
2271 |
|
|
|
2272 |
|
|
#define UC_DBG_TIMEOUT 0x01
|
2273 |
|
|
#define UC_DBG_HARDRESET 0x02
|
2274 |
|
|
|
2275 |
|
|
static int skip_spaces(char *ptr, int len)
|
2276 |
|
|
{
|
2277 |
|
|
int cnt, c;
|
2278 |
|
|
|
2279 |
|
|
for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
|
2280 |
|
|
|
2281 |
|
|
return (len - cnt);
|
2282 |
|
|
}
|
2283 |
|
|
|
2284 |
|
|
static int get_int_arg(char *ptr, int len, ulong *pv)
|
2285 |
|
|
{
|
2286 |
|
|
int cnt, c;
|
2287 |
|
|
ulong v;
|
2288 |
|
|
for (v = 0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) {
|
2289 |
|
|
v = (v * 10) + digit_to_bin(c);
|
2290 |
|
|
}
|
2291 |
|
|
|
2292 |
|
|
if (pv)
|
2293 |
|
|
*pv = v;
|
2294 |
|
|
|
2295 |
|
|
return (len - cnt);
|
2296 |
|
|
}
|
2297 |
|
|
|
2298 |
|
|
|
2299 |
|
|
static int is_keyword(char *ptr, int len, char *verb)
|
2300 |
|
|
{
|
2301 |
|
|
int verb_len = strlen(verb);
|
2302 |
|
|
|
2303 |
|
|
if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
|
2304 |
|
|
return verb_len;
|
2305 |
|
|
else
|
2306 |
|
|
return 0;
|
2307 |
|
|
}
|
2308 |
|
|
|
2309 |
|
|
#define SKIP_SPACES(min_spaces) \
|
2310 |
|
|
if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \
|
2311 |
|
|
return -EINVAL; \
|
2312 |
|
|
ptr += arg_len; \
|
2313 |
|
|
len -= arg_len;
|
2314 |
|
|
|
2315 |
|
|
#define GET_INT_ARG(v) \
|
2316 |
|
|
if (!(arg_len = get_int_arg(ptr,len, &(v)))) \
|
2317 |
|
|
return -EINVAL; \
|
2318 |
|
|
ptr += arg_len; \
|
2319 |
|
|
len -= arg_len;
|
2320 |
|
|
|
2321 |
|
|
static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length)
|
2322 |
|
|
{
|
2323 |
|
|
char *ptr = buffer;
|
2324 |
|
|
char btmp[24]; /* REMOVE */
|
2325 |
|
|
int arg_len;
|
2326 |
|
|
int len = length;
|
2327 |
|
|
int cmd;
|
2328 |
|
|
ulong number = 1;
|
2329 |
|
|
ulong delta = 10;
|
2330 |
|
|
|
2331 |
|
|
if ((len > 0) && (ptr[len -1] == '\n'))
|
2332 |
|
|
--len;
|
2333 |
|
|
|
2334 |
|
|
if (len < 22) {
|
2335 |
|
|
strncpy(btmp, buffer, len);
|
2336 |
|
|
btmp[len+1]='\0';
|
2337 |
|
|
} else {
|
2338 |
|
|
strncpy(btmp, buffer, 22);
|
2339 |
|
|
btmp[23]='\0';
|
2340 |
|
|
}
|
2341 |
|
|
printk("user_command: ioc %d, buffer %s, length %d\n",
|
2342 |
|
|
ioc->id, btmp, length);
|
2343 |
|
|
|
2344 |
|
|
if ((arg_len = is_keyword(ptr, len, "timeout")) != 0)
|
2345 |
|
|
cmd = UC_DBG_TIMEOUT;
|
2346 |
|
|
else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0)
|
2347 |
|
|
cmd = UC_DBG_HARDRESET;
|
2348 |
|
|
else
|
2349 |
|
|
return -EINVAL;
|
2350 |
|
|
|
2351 |
|
|
ptr += arg_len;
|
2352 |
|
|
len -= arg_len;
|
2353 |
|
|
|
2354 |
|
|
switch(cmd) {
|
2355 |
|
|
case UC_DBG_TIMEOUT:
|
2356 |
|
|
SKIP_SPACES(1);
|
2357 |
|
|
GET_INT_ARG(number);
|
2358 |
|
|
SKIP_SPACES(1);
|
2359 |
|
|
GET_INT_ARG(delta);
|
2360 |
|
|
break;
|
2361 |
|
|
}
|
2362 |
|
|
|
2363 |
|
|
printk("user_command: cnt=%ld delta=%ld\n", number, delta);
|
2364 |
|
|
|
2365 |
|
|
if (len)
|
2366 |
|
|
return -EINVAL;
|
2367 |
|
|
else {
|
2368 |
|
|
if (cmd == UC_DBG_HARDRESET) {
|
2369 |
|
|
ioc->timeout_hard = 1;
|
2370 |
|
|
} else if (cmd == UC_DBG_TIMEOUT) {
|
2371 |
|
|
/* process this command ...
|
2372 |
|
|
*/
|
2373 |
|
|
ioc->timeout_maxcnt = 0;
|
2374 |
|
|
ioc->timeout_delta = delta < 2 ? 2 : delta;
|
2375 |
|
|
ioc->timeout_cnt = 0;
|
2376 |
|
|
ioc->timeout_maxcnt = number < 8 ? number: 8;
|
2377 |
|
|
}
|
2378 |
|
|
}
|
2379 |
|
|
/* Not yet implemented */
|
2380 |
|
|
return length;
|
2381 |
|
|
}
|
2382 |
|
|
#endif
|
2383 |
|
|
|
2384 |
|
|
|
2385 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2386 |
|
|
/**
|
2387 |
|
|
* mptscsih_proc_info - Return information about MPT adapter
|
2388 |
|
|
*
|
2389 |
|
|
* (linux Scsi_Host_Template.info routine)
|
2390 |
|
|
*
|
2391 |
|
|
* buffer: if write, user data; if read, buffer for user
|
2392 |
|
|
* length: if write, return length;
|
2393 |
|
|
* offset: if write, 0; if read, the current offset into the buffer from
|
2394 |
|
|
* the previous read.
|
2395 |
|
|
* hostno: scsi host number
|
2396 |
|
|
* func: if write = 1; if read = 0
|
2397 |
|
|
*/
|
2398 |
|
|
int mptscsih_proc_info(char *buffer, char **start, off_t offset,
|
2399 |
|
|
int length, int hostno, int func)
|
2400 |
|
|
{
|
2401 |
|
|
MPT_ADAPTER *ioc;
|
2402 |
|
|
MPT_SCSI_HOST *hd = NULL;
|
2403 |
|
|
int size = 0;
|
2404 |
|
|
|
2405 |
|
|
dprintk(("Called mptscsih_proc_info: hostno=%d, func=%d\n", hostno, func));
|
2406 |
|
|
dprintk(("buffer %p, start=%p (%p) offset=%ld length = %d\n",
|
2407 |
|
|
buffer, start, *start, offset, length));
|
2408 |
|
|
|
2409 |
|
|
for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
|
2410 |
|
|
if ((ioc->sh) && (ioc->sh->host_no == hostno)) {
|
2411 |
|
|
hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
|
2412 |
|
|
break;
|
2413 |
|
|
}
|
2414 |
|
|
}
|
2415 |
|
|
if ((ioc == NULL) || (ioc->sh == NULL) || (hd == NULL))
|
2416 |
|
|
return 0;
|
2417 |
|
|
|
2418 |
|
|
if (func) {
|
2419 |
|
|
size = mptscsih_user_command(ioc, buffer, length);
|
2420 |
|
|
} else {
|
2421 |
|
|
if (start)
|
2422 |
|
|
*start = buffer;
|
2423 |
|
|
|
2424 |
|
|
size = mptscsih_host_info(ioc, buffer, offset, length);
|
2425 |
|
|
}
|
2426 |
|
|
|
2427 |
|
|
return size;
|
2428 |
|
|
}
|
2429 |
|
|
|
2430 |
|
|
|
2431 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2432 |
|
|
static int max_qd = 1;
|
2433 |
|
|
#if 0
|
2434 |
|
|
static int index_log[128];
|
2435 |
|
|
static int index_ent = 0;
|
2436 |
|
|
static __inline__ void ADD_INDEX_LOG(int req_ent)
|
2437 |
|
|
{
|
2438 |
|
|
int i = index_ent++;
|
2439 |
|
|
|
2440 |
|
|
index_log[i & (128 - 1)] = req_ent;
|
2441 |
|
|
}
|
2442 |
|
|
#else
|
2443 |
|
|
#define ADD_INDEX_LOG(req_ent) do { } while(0)
|
2444 |
|
|
#endif
|
2445 |
|
|
|
2446 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2447 |
|
|
/*
|
2448 |
|
|
* mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
|
2449 |
|
|
* @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
|
2450 |
|
|
* @id: IOC id number
|
2451 |
|
|
* @mf: Pointer to message frame
|
2452 |
|
|
*
|
2453 |
|
|
* Handles the call to mptbase for posting request and queue depth
|
2454 |
|
|
* tracking.
|
2455 |
|
|
*
|
2456 |
|
|
* Returns none.
|
2457 |
|
|
*/
|
2458 |
|
|
static inline void
|
2459 |
|
|
mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
|
2460 |
|
|
{
|
2461 |
|
|
/* Main banana... */
|
2462 |
|
|
atomic_inc(&queue_depth);
|
2463 |
|
|
if (atomic_read(&queue_depth) > max_qd) {
|
2464 |
|
|
max_qd = atomic_read(&queue_depth);
|
2465 |
|
|
dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
|
2466 |
|
|
}
|
2467 |
|
|
|
2468 |
|
|
mpt_put_msg_frame(context, id, mf);
|
2469 |
|
|
|
2470 |
|
|
return;
|
2471 |
|
|
}
|
2472 |
|
|
|
2473 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2474 |
|
|
/**
|
2475 |
|
|
* mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
|
2476 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure
|
2477 |
|
|
* @done: Pointer SCSI mid-layer IO completion function
|
2478 |
|
|
*
|
2479 |
|
|
* (linux Scsi_Host_Template.queuecommand routine)
|
2480 |
|
|
* This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
|
2481 |
|
|
* from a linux Scsi_Cmnd request and send it to the IOC.
|
2482 |
|
|
*
|
2483 |
|
|
* Returns 0. (rtn value discarded by linux scsi mid-layer)
|
2484 |
|
|
*/
|
2485 |
|
|
int
|
2486 |
|
|
mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
2487 |
|
|
{
|
2488 |
|
|
MPT_SCSI_HOST *hd;
|
2489 |
|
|
MPT_FRAME_HDR *mf;
|
2490 |
|
|
SCSIIORequest_t *pScsiReq;
|
2491 |
|
|
VirtDevice *pTarget;
|
2492 |
|
|
MPT_DONE_Q *buffer;
|
2493 |
|
|
unsigned long flags;
|
2494 |
|
|
int target;
|
2495 |
|
|
int lun;
|
2496 |
|
|
int datadir;
|
2497 |
|
|
u32 datalen;
|
2498 |
|
|
u32 scsictl;
|
2499 |
|
|
u32 scsidir;
|
2500 |
|
|
u32 cmd_len;
|
2501 |
|
|
int my_idx;
|
2502 |
|
|
int ii;
|
2503 |
|
|
int rc;
|
2504 |
|
|
int did_errcode;
|
2505 |
|
|
int issueCmd;
|
2506 |
|
|
|
2507 |
|
|
did_errcode = 0;
|
2508 |
|
|
hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
|
2509 |
|
|
target = SCpnt->target;
|
2510 |
|
|
lun = SCpnt->lun;
|
2511 |
|
|
SCpnt->scsi_done = done;
|
2512 |
|
|
|
2513 |
|
|
pTarget = hd->Targets[target];
|
2514 |
|
|
|
2515 |
|
|
dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
|
2516 |
|
|
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
|
2517 |
|
|
|
2518 |
|
|
if (hd->resetPending) {
|
2519 |
|
|
/* Prevent new commands from being issued
|
2520 |
|
|
* while reloading the FW. Reset timer to 60 seconds,
|
2521 |
|
|
* as the FW can take some time to come ready.
|
2522 |
|
|
* For New EH, cmds on doneQ posted to FW.
|
2523 |
|
|
*/
|
2524 |
|
|
did_errcode = 1;
|
2525 |
|
|
mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
|
2526 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
|
2527 |
|
|
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
|
2528 |
|
|
goto did_error;
|
2529 |
|
|
}
|
2530 |
|
|
|
2531 |
|
|
/*
|
2532 |
|
|
* Put together a MPT SCSI request...
|
2533 |
|
|
*/
|
2534 |
|
|
if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
|
2535 |
|
|
dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
|
2536 |
|
|
hd->ioc->name));
|
2537 |
|
|
did_errcode = 2;
|
2538 |
|
|
goto did_error;
|
2539 |
|
|
}
|
2540 |
|
|
|
2541 |
|
|
pScsiReq = (SCSIIORequest_t *) mf;
|
2542 |
|
|
|
2543 |
|
|
my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
2544 |
|
|
|
2545 |
|
|
ADD_INDEX_LOG(my_idx);
|
2546 |
|
|
|
2547 |
|
|
/*
|
2548 |
|
|
* The scsi layer should be handling this stuff
|
2549 |
|
|
* (In 2.3.x it does -DaveM)
|
2550 |
|
|
*/
|
2551 |
|
|
|
2552 |
|
|
/* BUG FIX! 19991030 -sralston
|
2553 |
|
|
* TUR's being issued with scsictl=0x02000000 (DATA_IN)!
|
2554 |
|
|
* Seems we may receive a buffer (datalen>0) even when there
|
2555 |
|
|
* will be no data transfer! GRRRRR...
|
2556 |
|
|
*/
|
2557 |
|
|
datadir = mptscsih_io_direction(SCpnt);
|
2558 |
|
|
if (datadir == SCSI_DATA_READ) {
|
2559 |
|
|
datalen = SCpnt->request_bufflen;
|
2560 |
|
|
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
|
2561 |
|
|
} else if (datadir == SCSI_DATA_WRITE) {
|
2562 |
|
|
datalen = SCpnt->request_bufflen;
|
2563 |
|
|
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
|
2564 |
|
|
} else {
|
2565 |
|
|
datalen = 0;
|
2566 |
|
|
scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
|
2567 |
|
|
}
|
2568 |
|
|
|
2569 |
|
|
/* Default to untagged. Once a target structure has been allocated,
|
2570 |
|
|
* use the Inquiry data to determine if device supports tagged.
|
2571 |
|
|
*/
|
2572 |
|
|
if ( pTarget
|
2573 |
|
|
&& (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
|
2574 |
|
|
&& (SCpnt->device->tagged_supported)) {
|
2575 |
|
|
scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
|
2576 |
|
|
} else {
|
2577 |
|
|
scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
|
2578 |
|
|
}
|
2579 |
|
|
|
2580 |
|
|
/* Use the above information to set up the message frame
|
2581 |
|
|
*/
|
2582 |
|
|
pScsiReq->TargetID = (u8) target;
|
2583 |
|
|
pScsiReq->Bus = (u8) SCpnt->channel;
|
2584 |
|
|
pScsiReq->ChainOffset = 0;
|
2585 |
|
|
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
|
2586 |
|
|
pScsiReq->CDBLength = SCpnt->cmd_len;
|
2587 |
|
|
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
|
2588 |
|
|
pScsiReq->Reserved = 0;
|
2589 |
|
|
pScsiReq->MsgFlags = mpt_msg_flags();
|
2590 |
|
|
pScsiReq->LUN[0] = 0;
|
2591 |
|
|
pScsiReq->LUN[1] = lun;
|
2592 |
|
|
pScsiReq->LUN[2] = 0;
|
2593 |
|
|
pScsiReq->LUN[3] = 0;
|
2594 |
|
|
pScsiReq->LUN[4] = 0;
|
2595 |
|
|
pScsiReq->LUN[5] = 0;
|
2596 |
|
|
pScsiReq->LUN[6] = 0;
|
2597 |
|
|
pScsiReq->LUN[7] = 0;
|
2598 |
|
|
pScsiReq->Control = cpu_to_le32(scsictl);
|
2599 |
|
|
|
2600 |
|
|
/*
|
2601 |
|
|
* Write SCSI CDB into the message
|
2602 |
|
|
* Should write from cmd_len up to 16, but skip for performance reasons.
|
2603 |
|
|
*/
|
2604 |
|
|
cmd_len = SCpnt->cmd_len;
|
2605 |
|
|
for (ii=0; ii < cmd_len; ii++)
|
2606 |
|
|
pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
|
2607 |
|
|
|
2608 |
|
|
for (ii=cmd_len; ii < 16; ii++)
|
2609 |
|
|
pScsiReq->CDB[ii] = 0;
|
2610 |
|
|
|
2611 |
|
|
/* DataLength */
|
2612 |
|
|
pScsiReq->DataLength = cpu_to_le32(datalen);
|
2613 |
|
|
|
2614 |
|
|
/* SenseBuffer low address */
|
2615 |
|
|
pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
|
2616 |
|
|
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
|
2617 |
|
|
|
2618 |
|
|
/* Now add the SG list
|
2619 |
|
|
* Always have a SGE even if null length.
|
2620 |
|
|
*/
|
2621 |
|
|
rc = SUCCESS;
|
2622 |
|
|
if (datalen == 0) {
|
2623 |
|
|
/* Add a NULL SGE */
|
2624 |
|
|
mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
|
2625 |
|
|
(dma_addr_t) -1);
|
2626 |
|
|
} else {
|
2627 |
|
|
/* Add a 32 or 64 bit SGE */
|
2628 |
|
|
rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
|
2629 |
|
|
}
|
2630 |
|
|
|
2631 |
|
|
|
2632 |
|
|
if (rc == SUCCESS) {
|
2633 |
|
|
hd->ScsiLookup[my_idx] = SCpnt;
|
2634 |
|
|
SCpnt->host_scribble = NULL;
|
2635 |
|
|
|
2636 |
|
|
/* SCSI specific processing */
|
2637 |
|
|
issueCmd = 1;
|
2638 |
|
|
if (hd->is_spi) {
|
2639 |
|
|
int dvStatus = hd->ioc->spi_data.dvStatus[target];
|
2640 |
|
|
|
2641 |
|
|
if (dvStatus || hd->ioc->spi_data.forceDv) {
|
2642 |
|
|
|
2643 |
|
|
/* Write SDP1 on this I/O to this target */
|
2644 |
|
|
if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
|
2645 |
|
|
mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
|
2646 |
|
|
dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
|
2647 |
|
|
hd->ioc->spi_data.dvStatus[target] = dvStatus;
|
2648 |
|
|
} else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
|
2649 |
|
|
mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
|
2650 |
|
|
dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
|
2651 |
|
|
hd->ioc->spi_data.dvStatus[target] = dvStatus;
|
2652 |
|
|
}
|
2653 |
|
|
|
2654 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
2655 |
|
|
if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
|
2656 |
|
|
(hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
|
2657 |
|
|
unsigned long lflags;
|
2658 |
|
|
/* Schedule DV if necessary */
|
2659 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, lflags);
|
2660 |
|
|
if (!dvtaskQ_active) {
|
2661 |
|
|
dvtaskQ_active = 1;
|
2662 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
|
2663 |
|
|
MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
|
2664 |
|
|
|
2665 |
|
|
SCHEDULE_TASK(&mptscsih_dvTask);
|
2666 |
|
|
} else {
|
2667 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
|
2668 |
|
|
}
|
2669 |
|
|
hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
|
2670 |
|
|
}
|
2671 |
|
|
|
2672 |
|
|
/* Trying to do DV to this target, extend timeout.
|
2673 |
|
|
* Wait to issue intil flag is clear
|
2674 |
|
|
*/
|
2675 |
|
|
if (dvStatus & MPT_SCSICFG_DV_PENDING) {
|
2676 |
|
|
mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
|
2677 |
|
|
issueCmd = 0;
|
2678 |
|
|
}
|
2679 |
|
|
|
2680 |
|
|
/* Set the DV flags.
|
2681 |
|
|
*/
|
2682 |
|
|
if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
|
2683 |
|
|
mptscsih_set_dvflags(hd, pScsiReq);
|
2684 |
|
|
#endif
|
2685 |
|
|
}
|
2686 |
|
|
}
|
2687 |
|
|
|
2688 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
2689 |
|
|
if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) {
|
2690 |
|
|
foo_to[hd->ioc->timeout_cnt] = SCpnt;
|
2691 |
|
|
hd->ioc->timeout_cnt++;
|
2692 |
|
|
//mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta);
|
2693 |
|
|
issueCmd = 0;
|
2694 |
|
|
printk(MYIOC_s_WARN_FMT
|
2695 |
|
|
"to pendingQ: (sc=%p, mf=%p, time=%ld)\n",
|
2696 |
|
|
hd->ioc->name, SCpnt, mf, jiffies);
|
2697 |
|
|
}
|
2698 |
|
|
#endif
|
2699 |
|
|
|
2700 |
|
|
if (issueCmd) {
|
2701 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
|
2702 |
|
|
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
|
2703 |
|
|
hd->ioc->name, SCpnt, mf, my_idx));
|
2704 |
|
|
} else {
|
2705 |
|
|
ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
|
2706 |
|
|
hd->ioc->name, SCpnt, my_idx));
|
2707 |
|
|
/* Place this command on the pendingQ if possible */
|
2708 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
2709 |
|
|
if (!Q_IS_EMPTY(&hd->freeQ)) {
|
2710 |
|
|
buffer = hd->freeQ.head;
|
2711 |
|
|
Q_DEL_ITEM(buffer);
|
2712 |
|
|
|
2713 |
|
|
/* Save the mf pointer
|
2714 |
|
|
*/
|
2715 |
|
|
buffer->argp = (void *)mf;
|
2716 |
|
|
|
2717 |
|
|
/* Add to the pendingQ
|
2718 |
|
|
*/
|
2719 |
|
|
Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
|
2720 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
2721 |
|
|
} else {
|
2722 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
2723 |
|
|
SCpnt->result = (DID_BUS_BUSY << 16);
|
2724 |
|
|
SCpnt->scsi_done(SCpnt);
|
2725 |
|
|
}
|
2726 |
|
|
}
|
2727 |
|
|
} else {
|
2728 |
|
|
mptscsih_freeChainBuffers(hd, my_idx);
|
2729 |
|
|
mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
|
2730 |
|
|
did_errcode = 3;
|
2731 |
|
|
goto did_error;
|
2732 |
|
|
}
|
2733 |
|
|
|
2734 |
|
|
return 0;
|
2735 |
|
|
|
2736 |
|
|
did_error:
|
2737 |
|
|
dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
|
2738 |
|
|
hd->ioc->name, did_errcode, SCpnt));
|
2739 |
|
|
/* Just wish OS to issue a retry */
|
2740 |
|
|
SCpnt->result = (DID_BUS_BUSY << 16);
|
2741 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
2742 |
|
|
if (!Q_IS_EMPTY(&hd->freeQ)) {
|
2743 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n",
|
2744 |
|
|
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
|
2745 |
|
|
buffer = hd->freeQ.head;
|
2746 |
|
|
Q_DEL_ITEM(buffer);
|
2747 |
|
|
|
2748 |
|
|
/* Set the Scsi_Cmnd pointer
|
2749 |
|
|
*/
|
2750 |
|
|
buffer->argp = (void *)SCpnt;
|
2751 |
|
|
|
2752 |
|
|
/* Add to the doneQ
|
2753 |
|
|
*/
|
2754 |
|
|
Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
|
2755 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
2756 |
|
|
} else {
|
2757 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
2758 |
|
|
SCpnt->scsi_done(SCpnt);
|
2759 |
|
|
}
|
2760 |
|
|
|
2761 |
|
|
return 0;
|
2762 |
|
|
}
|
2763 |
|
|
|
2764 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2765 |
|
|
/*
|
2766 |
|
|
* mptscsih_freeChainBuffers - Function to free chain buffers associated
|
2767 |
|
|
* with a SCSI IO request
|
2768 |
|
|
* @hd: Pointer to the MPT_SCSI_HOST instance
|
2769 |
|
|
* @req_idx: Index of the SCSI IO request frame.
|
2770 |
|
|
*
|
2771 |
|
|
* Called if SG chain buffer allocation fails and mptscsih callbacks.
|
2772 |
|
|
* No return.
|
2773 |
|
|
*/
|
2774 |
|
|
static void
|
2775 |
|
|
mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx)
|
2776 |
|
|
{
|
2777 |
|
|
MPT_FRAME_HDR *chain;
|
2778 |
|
|
unsigned long flags;
|
2779 |
|
|
int chain_idx;
|
2780 |
|
|
int next;
|
2781 |
|
|
|
2782 |
|
|
/* Get the first chain index and reset
|
2783 |
|
|
* tracker state.
|
2784 |
|
|
*/
|
2785 |
|
|
chain_idx = hd->ReqToChain[req_idx];
|
2786 |
|
|
hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
|
2787 |
|
|
|
2788 |
|
|
while (chain_idx != MPT_HOST_NO_CHAIN) {
|
2789 |
|
|
|
2790 |
|
|
/* Save the next chain buffer index */
|
2791 |
|
|
next = hd->ChainToChain[chain_idx];
|
2792 |
|
|
|
2793 |
|
|
/* Free this chain buffer and reset
|
2794 |
|
|
* tracker
|
2795 |
|
|
*/
|
2796 |
|
|
hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
|
2797 |
|
|
|
2798 |
|
|
chain = (MPT_FRAME_HDR *) (hd->ChainBuffer
|
2799 |
|
|
+ (chain_idx * hd->ioc->req_sz));
|
2800 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
2801 |
|
|
Q_ADD_TAIL(&hd->FreeChainQ.head,
|
2802 |
|
|
&chain->u.frame.linkage, MPT_FRAME_HDR);
|
2803 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
2804 |
|
|
|
2805 |
|
|
dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
|
2806 |
|
|
hd->ioc->name, chain_idx));
|
2807 |
|
|
|
2808 |
|
|
/* handle next */
|
2809 |
|
|
chain_idx = next;
|
2810 |
|
|
}
|
2811 |
|
|
return;
|
2812 |
|
|
}
|
2813 |
|
|
|
2814 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2815 |
|
|
/*
|
2816 |
|
|
* Reset Handling
|
2817 |
|
|
*/
|
2818 |
|
|
|
2819 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2820 |
|
|
/*
|
2821 |
|
|
* mptscsih_TMHandler - Generic handler for SCSI Task Management.
|
2822 |
|
|
* Fall through to mpt_HardResetHandler if: not operational, too many
|
2823 |
|
|
* failed TM requests or handshake failure.
|
2824 |
|
|
*
|
2825 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
2826 |
|
|
* @type: Task Management type
|
2827 |
|
|
* @target: Logical Target ID for reset (if appropriate)
|
2828 |
|
|
* @lun: Logical Unit for reset (if appropriate)
|
2829 |
|
|
* @ctx2abort: Context for the task to be aborted (if appropriate)
|
2830 |
|
|
* @sleepFlag: If set, use udelay instead of schedule in handshake code.
|
2831 |
|
|
*
|
2832 |
|
|
* Remark: Currently invoked from a non-interrupt thread (_bh).
|
2833 |
|
|
*
|
2834 |
|
|
* Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
|
2835 |
|
|
* will be active.
|
2836 |
|
|
*
|
2837 |
|
|
* Returns 0 for SUCCESS or -1 if FAILED.
|
2838 |
|
|
*/
|
2839 |
|
|
static int
|
2840 |
|
|
mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
|
2841 |
|
|
{
|
2842 |
|
|
MPT_ADAPTER *ioc;
|
2843 |
|
|
int rc = -1;
|
2844 |
|
|
int doTask = 1;
|
2845 |
|
|
u32 ioc_raw_state;
|
2846 |
|
|
unsigned long flags;
|
2847 |
|
|
|
2848 |
|
|
/* If FW is being reloaded currently, return success to
|
2849 |
|
|
* the calling function.
|
2850 |
|
|
*/
|
2851 |
|
|
if (hd == NULL)
|
2852 |
|
|
return 0;
|
2853 |
|
|
|
2854 |
|
|
ioc = hd->ioc;
|
2855 |
|
|
if (ioc == NULL) {
|
2856 |
|
|
printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
|
2857 |
|
|
return FAILED;
|
2858 |
|
|
}
|
2859 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
|
2860 |
|
|
|
2861 |
|
|
// SJR - CHECKME - Can we avoid this here?
|
2862 |
|
|
// (mpt_HardResetHandler has this check...)
|
2863 |
|
|
spin_lock_irqsave(&ioc->diagLock, flags);
|
2864 |
|
|
if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
|
2865 |
|
|
spin_unlock_irqrestore(&ioc->diagLock, flags);
|
2866 |
|
|
return FAILED;
|
2867 |
|
|
}
|
2868 |
|
|
spin_unlock_irqrestore(&ioc->diagLock, flags);
|
2869 |
|
|
|
2870 |
|
|
/* Do not do a Task Management if there are
|
2871 |
|
|
* too many failed TMs on this adapter.
|
2872 |
|
|
*/
|
2873 |
|
|
if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM)
|
2874 |
|
|
doTask = 0;
|
2875 |
|
|
|
2876 |
|
|
#ifdef MPT_SCSI_USE_NEW_EH
|
2877 |
|
|
/* Wait a fixed amount of time for the TM pending flag to be cleared.
|
2878 |
|
|
* If we time out and not bus reset, then we return a FAILED status to the caller.
|
2879 |
|
|
* The call to mptscsih_tm_pending_wait() will set the pending flag if we are
|
2880 |
|
|
* successful. Otherwise, reload the FW.
|
2881 |
|
|
*/
|
2882 |
|
|
if (mptscsih_tm_pending_wait(hd) == FAILED) {
|
2883 |
|
|
if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
|
2884 |
|
|
nehprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: "
|
2885 |
|
|
"Timed out waiting for last TM (%d) to complete! \n",
|
2886 |
|
|
hd->ioc->name, hd->tmPending));
|
2887 |
|
|
return FAILED;
|
2888 |
|
|
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
|
2889 |
|
|
nehprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: "
|
2890 |
|
|
"Timed out waiting for last TM (%d) to complete! \n",
|
2891 |
|
|
hd->ioc->name, hd->tmPending));
|
2892 |
|
|
return FAILED;
|
2893 |
|
|
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
|
2894 |
|
|
nehprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: "
|
2895 |
|
|
"Timed out waiting for last TM (%d) to complete! \n",
|
2896 |
|
|
hd->ioc->name, hd->tmPending));
|
2897 |
|
|
if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
|
2898 |
|
|
return FAILED;
|
2899 |
|
|
|
2900 |
|
|
doTask = 0;
|
2901 |
|
|
}
|
2902 |
|
|
} else {
|
2903 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
2904 |
|
|
hd->tmPending |= (1 << type);
|
2905 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
2906 |
|
|
}
|
2907 |
|
|
#endif
|
2908 |
|
|
|
2909 |
|
|
/* Is operational?
|
2910 |
|
|
*/
|
2911 |
|
|
ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
|
2912 |
|
|
|
2913 |
|
|
#ifdef MPT_DEBUG_RESET
|
2914 |
|
|
if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
|
2915 |
|
|
printk(MYIOC_s_WARN_FMT
|
2916 |
|
|
"TM Handler: IOC Not operational(0x%x)!\n",
|
2917 |
|
|
hd->ioc->name, ioc_raw_state);
|
2918 |
|
|
}
|
2919 |
|
|
#endif
|
2920 |
|
|
|
2921 |
|
|
if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
|
2922 |
|
|
&& !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
|
2923 |
|
|
|
2924 |
|
|
/* Isse the Task Mgmt request.
|
2925 |
|
|
*/
|
2926 |
|
|
if (hd->hard_resets < -1)
|
2927 |
|
|
hd->hard_resets++;
|
2928 |
|
|
rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, sleepFlag);
|
2929 |
|
|
if (rc) {
|
2930 |
|
|
printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
|
2931 |
|
|
} else {
|
2932 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
|
2933 |
|
|
}
|
2934 |
|
|
}
|
2935 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
2936 |
|
|
if (hd->ioc->timeout_hard)
|
2937 |
|
|
rc = 1;
|
2938 |
|
|
#endif
|
2939 |
|
|
|
2940 |
|
|
/* Only fall through to the HRH if this is a bus reset
|
2941 |
|
|
*/
|
2942 |
|
|
if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
|
2943 |
|
|
ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
|
2944 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
|
2945 |
|
|
hd->ioc->name));
|
2946 |
|
|
rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
|
2947 |
|
|
}
|
2948 |
|
|
|
2949 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
|
2950 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
2951 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "TMHandler: _bh_handler state (%d) taskQ count (%d)\n",
|
2952 |
|
|
ioc->name, mytaskQ_bh_active, hd->taskQcnt));
|
2953 |
|
|
#endif
|
2954 |
|
|
|
2955 |
|
|
return rc;
|
2956 |
|
|
}
|
2957 |
|
|
|
2958 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
2959 |
|
|
/*
|
2960 |
|
|
* mptscsih_IssueTaskMgmt - Generic send Task Management function.
|
2961 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure
|
2962 |
|
|
* @type: Task Management type
|
2963 |
|
|
* @target: Logical Target ID for reset (if appropriate)
|
2964 |
|
|
* @lun: Logical Unit for reset (if appropriate)
|
2965 |
|
|
* @ctx2abort: Context for the task to be aborted (if appropriate)
|
2966 |
|
|
* @sleepFlag: If set, use udelay instead of schedule in handshake code.
|
2967 |
|
|
*
|
2968 |
|
|
* Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
|
2969 |
|
|
* or a non-interrupt thread. In the former, must not call schedule().
|
2970 |
|
|
*
|
2971 |
|
|
* Not all fields are meaningfull for all task types.
|
2972 |
|
|
*
|
2973 |
|
|
* Returns 0 for SUCCESS, -999 for "no msg frames",
|
2974 |
|
|
* else other non-zero value returned.
|
2975 |
|
|
*/
|
2976 |
|
|
static int
|
2977 |
|
|
mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
|
2978 |
|
|
{
|
2979 |
|
|
MPT_FRAME_HDR *mf;
|
2980 |
|
|
SCSITaskMgmt_t *pScsiTm;
|
2981 |
|
|
int ii;
|
2982 |
|
|
int retval;
|
2983 |
|
|
|
2984 |
|
|
/* Return Fail to calling function if no message frames available.
|
2985 |
|
|
*/
|
2986 |
|
|
if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
|
2987 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
|
2988 |
|
|
hd->ioc->name));
|
2989 |
|
|
//return FAILED;
|
2990 |
|
|
return -999;
|
2991 |
|
|
}
|
2992 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
|
2993 |
|
|
hd->ioc->name, mf));
|
2994 |
|
|
|
2995 |
|
|
/* Format the Request
|
2996 |
|
|
*/
|
2997 |
|
|
pScsiTm = (SCSITaskMgmt_t *) mf;
|
2998 |
|
|
pScsiTm->TargetID = target;
|
2999 |
|
|
pScsiTm->Bus = channel;
|
3000 |
|
|
pScsiTm->ChainOffset = 0;
|
3001 |
|
|
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
|
3002 |
|
|
|
3003 |
|
|
pScsiTm->Reserved = 0;
|
3004 |
|
|
pScsiTm->TaskType = type;
|
3005 |
|
|
pScsiTm->Reserved1 = 0;
|
3006 |
|
|
pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
|
3007 |
|
|
? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
|
3008 |
|
|
|
3009 |
|
|
for (ii= 0; ii < 8; ii++) {
|
3010 |
|
|
pScsiTm->LUN[ii] = 0;
|
3011 |
|
|
}
|
3012 |
|
|
pScsiTm->LUN[1] = lun;
|
3013 |
|
|
|
3014 |
|
|
for (ii=0; ii < 7; ii++)
|
3015 |
|
|
pScsiTm->Reserved2[ii] = 0;
|
3016 |
|
|
|
3017 |
|
|
pScsiTm->TaskMsgContext = ctx2abort;
|
3018 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n",
|
3019 |
|
|
hd->ioc->name, ctx2abort, type));
|
3020 |
|
|
|
3021 |
|
|
/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
|
3022 |
|
|
mpt_put_msg_frame(hd->ioc->id, mf);
|
3023 |
|
|
* Save the MF pointer in case the request times out.
|
3024 |
|
|
*/
|
3025 |
|
|
hd->tmPtr = mf;
|
3026 |
|
|
hd->numTMrequests++;
|
3027 |
|
|
hd->TMtimer.expires = jiffies + HZ*20; /* 20 seconds */
|
3028 |
|
|
add_timer(&hd->TMtimer);
|
3029 |
|
|
|
3030 |
|
|
if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
|
3031 |
|
|
sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag))
|
3032 |
|
|
!= 0) {
|
3033 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"
|
3034 |
|
|
" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf));
|
3035 |
|
|
hd->numTMrequests--;
|
3036 |
|
|
hd->tmPtr = NULL;
|
3037 |
|
|
del_timer(&hd->TMtimer);
|
3038 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
|
3039 |
|
|
}
|
3040 |
|
|
|
3041 |
|
|
return retval;
|
3042 |
|
|
}
|
3043 |
|
|
|
3044 |
|
|
#ifdef MPT_SCSI_USE_NEW_EH /* { */
|
3045 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3046 |
|
|
/**
|
3047 |
|
|
* mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
|
3048 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
|
3049 |
|
|
*
|
3050 |
|
|
* (linux Scsi_Host_Template.eh_abort_handler routine)
|
3051 |
|
|
*
|
3052 |
|
|
* Returns SUCCESS or FAILED.
|
3053 |
|
|
*/
|
3054 |
|
|
int
|
3055 |
|
|
mptscsih_abort(Scsi_Cmnd * SCpnt)
|
3056 |
|
|
{
|
3057 |
|
|
MPT_SCSI_HOST *hd;
|
3058 |
|
|
MPT_FRAME_HDR *mf;
|
3059 |
|
|
u32 ctx2abort;
|
3060 |
|
|
int scpnt_idx;
|
3061 |
|
|
|
3062 |
|
|
/* If we can't locate our host adapter structure, return FAILED status.
|
3063 |
|
|
*/
|
3064 |
|
|
if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
|
3065 |
|
|
SCpnt->result = DID_RESET << 16;
|
3066 |
|
|
SCpnt->scsi_done(SCpnt);
|
3067 |
|
|
nehprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
|
3068 |
|
|
"Can't locate host! (sc=%p)\n",
|
3069 |
|
|
SCpnt));
|
3070 |
|
|
return FAILED;
|
3071 |
|
|
}
|
3072 |
|
|
|
3073 |
|
|
if (hd->resetPending)
|
3074 |
|
|
return FAILED;
|
3075 |
|
|
|
3076 |
|
|
printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n",
|
3077 |
|
|
hd->ioc->name, SCpnt, atomic_read(&queue_depth));
|
3078 |
|
|
|
3079 |
|
|
if (hd->timeouts < -1)
|
3080 |
|
|
hd->timeouts++;
|
3081 |
|
|
|
3082 |
|
|
/* Find this command
|
3083 |
|
|
*/
|
3084 |
|
|
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
|
3085 |
|
|
/* Cmd not found in ScsiLookup. If found in
|
3086 |
|
|
* doneQ, delete from Q. Do OS callback.
|
3087 |
|
|
*/
|
3088 |
|
|
search_doneQ_for_cmd(hd, SCpnt);
|
3089 |
|
|
|
3090 |
|
|
SCpnt->result = DID_RESET << 16;
|
3091 |
|
|
nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
|
3092 |
|
|
"Command not in the active list! (sc=%p)\n",
|
3093 |
|
|
hd->ioc->name, SCpnt));
|
3094 |
|
|
return SUCCESS;
|
3095 |
|
|
}
|
3096 |
|
|
|
3097 |
|
|
/* If this command is pended, then timeout/hang occurred
|
3098 |
|
|
* during DV. Post command and flush pending Q
|
3099 |
|
|
* and then following up with the reset request.
|
3100 |
|
|
*/
|
3101 |
|
|
if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
|
3102 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
|
3103 |
|
|
post_pendingQ_commands(hd);
|
3104 |
|
|
nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
|
3105 |
|
|
"Posting pended cmd! (sc=%p)\n",
|
3106 |
|
|
hd->ioc->name, SCpnt));
|
3107 |
|
|
}
|
3108 |
|
|
|
3109 |
|
|
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
|
3110 |
|
|
* (the IO to be ABORT'd)
|
3111 |
|
|
*
|
3112 |
|
|
* NOTE: Since we do not byteswap MsgContext, we do not
|
3113 |
|
|
* swap it here either. It is an opaque cookie to
|
3114 |
|
|
* the controller, so it does not matter. -DaveM
|
3115 |
|
|
*/
|
3116 |
|
|
mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
|
3117 |
|
|
ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
|
3118 |
|
|
|
3119 |
|
|
hd->abortSCpnt = SCpnt;
|
3120 |
|
|
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
|
3121 |
|
|
SCpnt->channel, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
|
3122 |
|
|
< 0) {
|
3123 |
|
|
|
3124 |
|
|
/* The TM request failed and the subsequent FW-reload failed!
|
3125 |
|
|
* Fatal error case.
|
3126 |
|
|
*/
|
3127 |
|
|
printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
|
3128 |
|
|
hd->ioc->name, SCpnt);
|
3129 |
|
|
|
3130 |
|
|
/* We must clear our pending flag before clearing our state.
|
3131 |
|
|
*/
|
3132 |
|
|
hd->tmPending = 0;
|
3133 |
|
|
hd->tmState = TM_STATE_NONE;
|
3134 |
|
|
|
3135 |
|
|
return FAILED;
|
3136 |
|
|
}
|
3137 |
|
|
return FAILED;
|
3138 |
|
|
|
3139 |
|
|
}
|
3140 |
|
|
|
3141 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3142 |
|
|
/**
|
3143 |
|
|
* mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant
|
3144 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
|
3145 |
|
|
*
|
3146 |
|
|
* (linux Scsi_Host_Template.eh_dev_reset_handler routine)
|
3147 |
|
|
*
|
3148 |
|
|
* Returns SUCCESS or FAILED.
|
3149 |
|
|
*/
|
3150 |
|
|
int
|
3151 |
|
|
mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
|
3152 |
|
|
{
|
3153 |
|
|
MPT_SCSI_HOST *hd;
|
3154 |
|
|
|
3155 |
|
|
/* If we can't locate our host adapter structure, return FAILED status.
|
3156 |
|
|
*/
|
3157 |
|
|
if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
|
3158 |
|
|
nehprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
|
3159 |
|
|
"Can't locate host! (sc=%p)\n",
|
3160 |
|
|
SCpnt));
|
3161 |
|
|
return FAILED;
|
3162 |
|
|
}
|
3163 |
|
|
|
3164 |
|
|
if (hd->resetPending)
|
3165 |
|
|
return FAILED;
|
3166 |
|
|
|
3167 |
|
|
printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n",
|
3168 |
|
|
hd->ioc->name, SCpnt, atomic_read(&queue_depth));
|
3169 |
|
|
|
3170 |
|
|
/* Unsupported for SCSI. Supported for FCP
|
3171 |
|
|
*/
|
3172 |
|
|
if (hd->is_spi)
|
3173 |
|
|
return FAILED;
|
3174 |
|
|
|
3175 |
|
|
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
|
3176 |
|
|
SCpnt->channel, SCpnt->target, 0, 0, NO_SLEEP)
|
3177 |
|
|
< 0){
|
3178 |
|
|
/* The TM request failed and the subsequent FW-reload failed!
|
3179 |
|
|
* Fatal error case.
|
3180 |
|
|
*/
|
3181 |
|
|
printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
|
3182 |
|
|
hd->ioc->name, SCpnt);
|
3183 |
|
|
hd->tmPending = 0;
|
3184 |
|
|
hd->tmState = TM_STATE_NONE;
|
3185 |
|
|
return FAILED;
|
3186 |
|
|
}
|
3187 |
|
|
return SUCCESS;
|
3188 |
|
|
|
3189 |
|
|
}
|
3190 |
|
|
|
3191 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3192 |
|
|
/**
|
3193 |
|
|
* mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
|
3194 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
|
3195 |
|
|
*
|
3196 |
|
|
* (linux Scsi_Host_Template.eh_bus_reset_handler routine)
|
3197 |
|
|
*
|
3198 |
|
|
* Returns SUCCESS or FAILED.
|
3199 |
|
|
*/
|
3200 |
|
|
int
|
3201 |
|
|
mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
|
3202 |
|
|
{
|
3203 |
|
|
MPT_SCSI_HOST *hd;
|
3204 |
|
|
|
3205 |
|
|
/* If we can't locate our host adapter structure, return FAILED status.
|
3206 |
|
|
*/
|
3207 |
|
|
if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
|
3208 |
|
|
nehprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
|
3209 |
|
|
"Can't locate host! (sc=%p)\n",
|
3210 |
|
|
SCpnt ) );
|
3211 |
|
|
return FAILED;
|
3212 |
|
|
}
|
3213 |
|
|
|
3214 |
|
|
printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n",
|
3215 |
|
|
hd->ioc->name, SCpnt, atomic_read(&queue_depth));
|
3216 |
|
|
|
3217 |
|
|
if (hd->timeouts < -1)
|
3218 |
|
|
hd->timeouts++;
|
3219 |
|
|
|
3220 |
|
|
/* We are now ready to execute the task management request. */
|
3221 |
|
|
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
3222 |
|
|
SCpnt->channel, 0, 0, 0, NO_SLEEP)
|
3223 |
|
|
< 0){
|
3224 |
|
|
|
3225 |
|
|
/* The TM request failed and the subsequent FW-reload failed!
|
3226 |
|
|
* Fatal error case.
|
3227 |
|
|
*/
|
3228 |
|
|
printk(MYIOC_s_WARN_FMT
|
3229 |
|
|
"Error processing TaskMgmt request (sc=%p)\n",
|
3230 |
|
|
hd->ioc->name, SCpnt);
|
3231 |
|
|
hd->tmPending = 0;
|
3232 |
|
|
hd->tmState = TM_STATE_NONE;
|
3233 |
|
|
return FAILED;
|
3234 |
|
|
}
|
3235 |
|
|
|
3236 |
|
|
return SUCCESS;
|
3237 |
|
|
}
|
3238 |
|
|
|
3239 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3240 |
|
|
/**
|
3241 |
|
|
* mptscsih_host_reset - Perform a SCSI host adapter RESET!
|
3242 |
|
|
* new_eh variant
|
3243 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
|
3244 |
|
|
*
|
3245 |
|
|
* (linux Scsi_Host_Template.eh_host_reset_handler routine)
|
3246 |
|
|
*
|
3247 |
|
|
* Returns SUCCESS or FAILED.
|
3248 |
|
|
*/
|
3249 |
|
|
int
|
3250 |
|
|
mptscsih_host_reset(Scsi_Cmnd *SCpnt)
|
3251 |
|
|
{
|
3252 |
|
|
MPT_SCSI_HOST * hd;
|
3253 |
|
|
int status = SUCCESS;
|
3254 |
|
|
|
3255 |
|
|
/* If we can't locate the host to reset, then we failed. */
|
3256 |
|
|
if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
|
3257 |
|
|
nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
|
3258 |
|
|
"Can't locate host! (sc=%p)\n",
|
3259 |
|
|
SCpnt ) );
|
3260 |
|
|
return FAILED;
|
3261 |
|
|
}
|
3262 |
|
|
|
3263 |
|
|
printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
|
3264 |
|
|
hd->ioc->name, SCpnt);
|
3265 |
|
|
printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
|
3266 |
|
|
hd->ioc->name, atomic_read(&queue_depth));
|
3267 |
|
|
|
3268 |
|
|
/* If our attempts to reset the host failed, then return a failed
|
3269 |
|
|
* status. The host will be taken off line by the SCSI mid-layer.
|
3270 |
|
|
*/
|
3271 |
|
|
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0){
|
3272 |
|
|
status = FAILED;
|
3273 |
|
|
} else {
|
3274 |
|
|
/* Make sure TM pending is cleared and TM state is set to
|
3275 |
|
|
* NONE.
|
3276 |
|
|
*/
|
3277 |
|
|
hd->tmPending = 0;
|
3278 |
|
|
hd->tmState = TM_STATE_NONE;
|
3279 |
|
|
}
|
3280 |
|
|
|
3281 |
|
|
|
3282 |
|
|
nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
|
3283 |
|
|
"Status = %s\n",
|
3284 |
|
|
(status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
|
3285 |
|
|
|
3286 |
|
|
return status;
|
3287 |
|
|
}
|
3288 |
|
|
|
3289 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3290 |
|
|
/**
|
3291 |
|
|
* mptscsih_tm_pending_wait - wait for pending task management request to
|
3292 |
|
|
* complete.
|
3293 |
|
|
* @hd: Pointer to MPT host structure.
|
3294 |
|
|
*
|
3295 |
|
|
* Returns {SUCCESS,FAILED}.
|
3296 |
|
|
*/
|
3297 |
|
|
static int
|
3298 |
|
|
mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
|
3299 |
|
|
{
|
3300 |
|
|
unsigned long flags;
|
3301 |
|
|
int loop_count = 2 * 10 * 4; /* Wait 2 seconds */
|
3302 |
|
|
int status = FAILED;
|
3303 |
|
|
|
3304 |
|
|
do {
|
3305 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
3306 |
|
|
if (hd->tmState == TM_STATE_NONE) {
|
3307 |
|
|
hd->tmState = TM_STATE_IN_PROGRESS;
|
3308 |
|
|
hd->tmPending = 1;
|
3309 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
3310 |
|
|
status = SUCCESS;
|
3311 |
|
|
break;
|
3312 |
|
|
}
|
3313 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
3314 |
|
|
//set_current_state(TASK_INTERRUPTIBLE);
|
3315 |
|
|
//schedule_timeout(HZ/4);
|
3316 |
|
|
mdelay(250);
|
3317 |
|
|
} while (--loop_count);
|
3318 |
|
|
|
3319 |
|
|
return status;
|
3320 |
|
|
}
|
3321 |
|
|
|
3322 |
|
|
#else /* MPT_SCSI old EH stuff... */
|
3323 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3324 |
|
|
/**
|
3325 |
|
|
* mptscsih_old_abort - Abort linux Scsi_Cmnd routine
|
3326 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
|
3327 |
|
|
*
|
3328 |
|
|
* (linux Scsi_Host_Template.abort routine)
|
3329 |
|
|
*
|
3330 |
|
|
* Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
|
3331 |
|
|
*/
|
3332 |
|
|
int
|
3333 |
|
|
mptscsih_old_abort(Scsi_Cmnd *SCpnt)
|
3334 |
|
|
{
|
3335 |
|
|
MPT_SCSI_HOST *hd;
|
3336 |
|
|
MPT_FRAME_HDR *mf;
|
3337 |
|
|
struct mpt_work_struct *ptaskfoo;
|
3338 |
|
|
unsigned long flags;
|
3339 |
|
|
int scpnt_idx;
|
3340 |
|
|
|
3341 |
|
|
printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", (void *) SCpnt);
|
3342 |
|
|
printk(KERN_WARNING " IOs outstanding = %d\n", atomic_read(&queue_depth));
|
3343 |
|
|
|
3344 |
|
|
if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
|
3345 |
|
|
printk(KERN_WARNING " WARNING - OldAbort, NULL hostdata ptr!!\n");
|
3346 |
|
|
SCpnt->result = DID_ERROR << 16;
|
3347 |
|
|
return SCSI_ABORT_NOT_RUNNING;
|
3348 |
|
|
}
|
3349 |
|
|
|
3350 |
|
|
if (hd->timeouts < -1)
|
3351 |
|
|
hd->timeouts++;
|
3352 |
|
|
|
3353 |
|
|
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
|
3354 |
|
|
/* Cmd not found in ScsiLookup.
|
3355 |
|
|
* If found in doneQ, delete from Q.
|
3356 |
|
|
* Do OS callback.
|
3357 |
|
|
*/
|
3358 |
|
|
search_doneQ_for_cmd(hd, SCpnt);
|
3359 |
|
|
|
3360 |
|
|
SCpnt->result = DID_ABORT << 16;
|
3361 |
|
|
return SCSI_ABORT_SUCCESS;
|
3362 |
|
|
} else {
|
3363 |
|
|
/* If this command is pended, then timeout/hang occurred
|
3364 |
|
|
* during DV. Force bus reset by posting command to F/W
|
3365 |
|
|
* and then following up with the reset request.
|
3366 |
|
|
*/
|
3367 |
|
|
#ifndef MPTSCSIH_DBG_TIMEOUT
|
3368 |
|
|
if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
|
3369 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
|
3370 |
|
|
post_pendingQ_commands(hd);
|
3371 |
|
|
}
|
3372 |
|
|
#endif
|
3373 |
|
|
}
|
3374 |
|
|
|
3375 |
|
|
/*
|
3376 |
|
|
* Check to see if there's already an ABORT queued for this guy.
|
3377 |
|
|
*/
|
3378 |
|
|
mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
|
3379 |
|
|
if (mf != NULL) {
|
3380 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "OldAbort:Abort Task PENDING cmd (%p) taskQ depth (%d)\n",
|
3381 |
|
|
hd->ioc->name, SCpnt, hd->taskQcnt));
|
3382 |
|
|
return SCSI_ABORT_PENDING;
|
3383 |
|
|
}
|
3384 |
|
|
|
3385 |
|
|
// SJR - CHECKME - Can we avoid this here?
|
3386 |
|
|
// (mpt_HardResetHandler has this check...)
|
3387 |
|
|
/* If IOC is reloading FW, return PENDING.
|
3388 |
|
|
*/
|
3389 |
|
|
spin_lock_irqsave(&hd->ioc->diagLock, flags);
|
3390 |
|
|
if (hd->ioc->diagPending) {
|
3391 |
|
|
spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
|
3392 |
|
|
return SCSI_ABORT_PENDING;
|
3393 |
|
|
}
|
3394 |
|
|
spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
|
3395 |
|
|
|
3396 |
|
|
/* If there are no message frames what should we do?
|
3397 |
|
|
*/
|
3398 |
|
|
if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
|
3399 |
|
|
printk((KERN_WARNING " WARNING - OldAbort, no msg frames!!\n"));
|
3400 |
|
|
/* We are out of message frames!
|
3401 |
|
|
* Call the reset handler to do a FW reload.
|
3402 |
|
|
*/
|
3403 |
|
|
printk((KERN_WARNING " Reloading Firmware!!\n"));
|
3404 |
|
|
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
|
3405 |
|
|
printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
|
3406 |
|
|
}
|
3407 |
|
|
return SCSI_ABORT_PENDING;
|
3408 |
|
|
}
|
3409 |
|
|
|
3410 |
|
|
/*
|
3411 |
|
|
* Add ourselves to (end of) taskQ .
|
3412 |
|
|
* Check to see if our _bh is running. If NOT, schedule it.
|
3413 |
|
|
*/
|
3414 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
3415 |
|
|
Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
|
3416 |
|
|
hd->taskQcnt++;
|
3417 |
|
|
atomic_inc(&mpt_taskQdepth);
|
3418 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
3419 |
|
|
|
3420 |
|
|
spin_lock_irqsave(&mytaskQ_lock, flags);
|
3421 |
|
|
|
3422 |
|
|
/* Save the original SCpnt mf pointer
|
3423 |
|
|
*/
|
3424 |
|
|
SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
|
3425 |
|
|
|
3426 |
|
|
/* For the time being, force bus reset on any abort
|
3427 |
|
|
* requests for the 1030/1035 FW.
|
3428 |
|
|
*/
|
3429 |
|
|
if (hd->is_spi)
|
3430 |
|
|
mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
|
3431 |
|
|
else
|
3432 |
|
|
mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
|
3433 |
|
|
|
3434 |
|
|
mf->u.frame.linkage.argp1 = SCpnt;
|
3435 |
|
|
mf->u.frame.linkage.argp2 = (void *) hd;
|
3436 |
|
|
|
3437 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "OldAbort:_bh_handler state (%d) taskQ count (%d)\n",
|
3438 |
|
|
hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
|
3439 |
|
|
|
3440 |
|
|
if (! mytaskQ_bh_active) {
|
3441 |
|
|
mytaskQ_bh_active = 1;
|
3442 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
3443 |
|
|
|
3444 |
|
|
ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
|
3445 |
|
|
MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
|
3446 |
|
|
|
3447 |
|
|
SCHEDULE_TASK(ptaskfoo);
|
3448 |
|
|
} else {
|
3449 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
3450 |
|
|
}
|
3451 |
|
|
|
3452 |
|
|
return SCSI_ABORT_PENDING;
|
3453 |
|
|
}
|
3454 |
|
|
|
3455 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3456 |
|
|
/**
|
3457 |
|
|
* mptscsih_old_reset - Perform a SCSI BUS_RESET!
|
3458 |
|
|
* @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
|
3459 |
|
|
* @reset_flags: (not used?)
|
3460 |
|
|
*
|
3461 |
|
|
* (linux Scsi_Host_Template.reset routine)
|
3462 |
|
|
*
|
3463 |
|
|
* Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
|
3464 |
|
|
*/
|
3465 |
|
|
int
|
3466 |
|
|
mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
|
3467 |
|
|
{
|
3468 |
|
|
MPT_SCSI_HOST *hd;
|
3469 |
|
|
MPT_FRAME_HDR *mf;
|
3470 |
|
|
struct mpt_work_struct *ptaskfoo;
|
3471 |
|
|
unsigned long flags;
|
3472 |
|
|
int scpnt_idx;
|
3473 |
|
|
|
3474 |
|
|
printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", (void *) SCpnt);
|
3475 |
|
|
printk(KERN_WARNING " IOs outstanding = %d\n", atomic_read(&queue_depth));
|
3476 |
|
|
|
3477 |
|
|
if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
|
3478 |
|
|
SCpnt->result = DID_ERROR << 16;
|
3479 |
|
|
return SCSI_RESET_SUCCESS;
|
3480 |
|
|
}
|
3481 |
|
|
|
3482 |
|
|
if (hd->timeouts < -1)
|
3483 |
|
|
hd->timeouts++;
|
3484 |
|
|
|
3485 |
|
|
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
|
3486 |
|
|
/* Cmd not found in ScsiLookup.
|
3487 |
|
|
* If found in doneQ, delete from Q.
|
3488 |
|
|
* Do OS callback.
|
3489 |
|
|
*/
|
3490 |
|
|
search_doneQ_for_cmd(hd, SCpnt);
|
3491 |
|
|
|
3492 |
|
|
SCpnt->result = DID_RESET << 16;
|
3493 |
|
|
return SCSI_RESET_SUCCESS;
|
3494 |
|
|
} else {
|
3495 |
|
|
/* If this command is pended, then timeout/hang occurred
|
3496 |
|
|
* during DV. Force bus reset by posting command to F/W
|
3497 |
|
|
* and then following up with the reset request.
|
3498 |
|
|
*/
|
3499 |
|
|
#ifndef MPTSCSIH_DBG_TIMEOUT
|
3500 |
|
|
if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
|
3501 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
|
3502 |
|
|
post_pendingQ_commands(hd);
|
3503 |
|
|
}
|
3504 |
|
|
#endif
|
3505 |
|
|
}
|
3506 |
|
|
|
3507 |
|
|
/*
|
3508 |
|
|
* Check to see if there's an ABORT_TASK queued for this guy.
|
3509 |
|
|
* If so, delete.
|
3510 |
|
|
*/
|
3511 |
|
|
search_taskQ(1, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
|
3512 |
|
|
|
3513 |
|
|
/*
|
3514 |
|
|
* Check to see if there's already a BUS_RESET queued for this guy.
|
3515 |
|
|
*/
|
3516 |
|
|
mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
|
3517 |
|
|
if (mf != NULL) {
|
3518 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "OldReset:Reset Task PENDING cmd (%p) taskQ depth (%d)\n",
|
3519 |
|
|
hd->ioc->name, SCpnt, hd->taskQcnt));
|
3520 |
|
|
return SCSI_RESET_PENDING;
|
3521 |
|
|
}
|
3522 |
|
|
|
3523 |
|
|
// SJR - CHECKME - Can we avoid this here?
|
3524 |
|
|
// (mpt_HardResetHandler has this check...)
|
3525 |
|
|
/* If IOC is reloading FW, return PENDING.
|
3526 |
|
|
*/
|
3527 |
|
|
spin_lock_irqsave(&hd->ioc->diagLock, flags);
|
3528 |
|
|
if (hd->ioc->diagPending) {
|
3529 |
|
|
spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
|
3530 |
|
|
return SCSI_RESET_PENDING;
|
3531 |
|
|
}
|
3532 |
|
|
spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
|
3533 |
|
|
|
3534 |
|
|
if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
|
3535 |
|
|
/* We are out of message frames!
|
3536 |
|
|
* Call the reset handler to do a FW reload.
|
3537 |
|
|
*/
|
3538 |
|
|
printk((KERN_WARNING " Reloading Firmware!!\n"));
|
3539 |
|
|
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
|
3540 |
|
|
printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
|
3541 |
|
|
}
|
3542 |
|
|
return SCSI_RESET_PENDING;
|
3543 |
|
|
}
|
3544 |
|
|
|
3545 |
|
|
/*
|
3546 |
|
|
* Add ourselves to (end of) taskQ.
|
3547 |
|
|
* Check to see if our _bh is running. If NOT, schedule it.
|
3548 |
|
|
*/
|
3549 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
3550 |
|
|
Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
|
3551 |
|
|
hd->taskQcnt++;
|
3552 |
|
|
atomic_inc(&mpt_taskQdepth);
|
3553 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
3554 |
|
|
|
3555 |
|
|
|
3556 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n",
|
3557 |
|
|
hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
|
3558 |
|
|
|
3559 |
|
|
spin_lock_irqsave(&mytaskQ_lock, flags);
|
3560 |
|
|
/* Save the original SCpnt mf pointer
|
3561 |
|
|
*/
|
3562 |
|
|
SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
|
3563 |
|
|
|
3564 |
|
|
mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
|
3565 |
|
|
mf->u.frame.linkage.argp1 = SCpnt;
|
3566 |
|
|
mf->u.frame.linkage.argp2 = (void *) hd;
|
3567 |
|
|
|
3568 |
|
|
if (! mytaskQ_bh_active) {
|
3569 |
|
|
mytaskQ_bh_active = 1;
|
3570 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
3571 |
|
|
/*
|
3572 |
|
|
* Oh how cute, no alloc/free/mgmt needed if we use
|
3573 |
|
|
* (bottom/unused portion of) MPT request frame.
|
3574 |
|
|
*/
|
3575 |
|
|
ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
|
3576 |
|
|
MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
|
3577 |
|
|
|
3578 |
|
|
SCHEDULE_TASK(ptaskfoo);
|
3579 |
|
|
} else {
|
3580 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
3581 |
|
|
}
|
3582 |
|
|
return SCSI_RESET_PENDING;
|
3583 |
|
|
}
|
3584 |
|
|
|
3585 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3586 |
|
|
/*
|
3587 |
|
|
* mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
|
3588 |
|
|
* @sc: (unused)
|
3589 |
|
|
*
|
3590 |
|
|
* This routine (thread) is active whenever there are any outstanding
|
3591 |
|
|
* SCSI task management requests for a SCSI host adapter.
|
3592 |
|
|
* IMPORTANT! This routine is scheduled therefore should never be
|
3593 |
|
|
* running in ISR context. i.e., it's safe to sleep here.
|
3594 |
|
|
*/
|
3595 |
|
|
void
|
3596 |
|
|
mptscsih_taskmgmt_bh(void *sc)
|
3597 |
|
|
{
|
3598 |
|
|
MPT_ADAPTER *ioc;
|
3599 |
|
|
Scsi_Cmnd *SCpnt;
|
3600 |
|
|
MPT_FRAME_HDR *mf = NULL;
|
3601 |
|
|
MPT_SCSI_HOST *hd;
|
3602 |
|
|
u32 ctx2abort = 0;
|
3603 |
|
|
unsigned long flags;
|
3604 |
|
|
int scpnt_idx;
|
3605 |
|
|
int did;
|
3606 |
|
|
u8 task_type;
|
3607 |
|
|
|
3608 |
|
|
spin_lock_irqsave(&mytaskQ_lock, flags);
|
3609 |
|
|
mytaskQ_bh_active = 1;
|
3610 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
3611 |
|
|
|
3612 |
|
|
do {
|
3613 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
3614 |
|
|
schedule_timeout(HZ/4);
|
3615 |
|
|
did = 0;
|
3616 |
|
|
|
3617 |
|
|
for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
|
3618 |
|
|
if (ioc->sh) {
|
3619 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
3620 |
|
|
if (hd == NULL) {
|
3621 |
|
|
printk(KERN_ERR MYNAM
|
3622 |
|
|
": ERROR - TaskMgmt NULL SCSI Host!"
|
3623 |
|
|
"(ioc=%p, sh=%p hd=%p)\n",
|
3624 |
|
|
(void *) ioc, (void *) ioc->sh, (void *) hd);
|
3625 |
|
|
continue;
|
3626 |
|
|
}
|
3627 |
|
|
|
3628 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
3629 |
|
|
if (ioc->timeout_hard == 1) {
|
3630 |
|
|
mptscsih_TMHandler(hd,
|
3631 |
|
|
MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
3632 |
|
|
0, 0, 0, 0, CAN_SLEEP);
|
3633 |
|
|
|
3634 |
|
|
}
|
3635 |
|
|
#endif
|
3636 |
|
|
|
3637 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3638 |
|
|
if (Q_IS_EMPTY(&hd->taskQ)) {
|
3639 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3640 |
|
|
continue;
|
3641 |
|
|
}
|
3642 |
|
|
|
3643 |
|
|
/* If we ever find a non-empty queue,
|
3644 |
|
|
* keep the handler alive
|
3645 |
|
|
*/
|
3646 |
|
|
did++;
|
3647 |
|
|
|
3648 |
|
|
/* tmPending is SMP lock-protected */
|
3649 |
|
|
if (hd->tmPending || hd->tmPtr) {
|
3650 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3651 |
|
|
continue;
|
3652 |
|
|
}
|
3653 |
|
|
hd->tmPending = 1;
|
3654 |
|
|
|
3655 |
|
|
/* Process this request
|
3656 |
|
|
*/
|
3657 |
|
|
mf = hd->taskQ.head;
|
3658 |
|
|
Q_DEL_ITEM(&mf->u.frame.linkage);
|
3659 |
|
|
hd->taskQcnt--;
|
3660 |
|
|
atomic_dec(&mpt_taskQdepth);
|
3661 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3662 |
|
|
|
3663 |
|
|
SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
|
3664 |
|
|
if (SCpnt == NULL) {
|
3665 |
|
|
printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (mf=%p:sc=%p)\n",
|
3666 |
|
|
(void *) mf, (void *) SCpnt);
|
3667 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
|
3668 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3669 |
|
|
hd->tmPending = 0;
|
3670 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3671 |
|
|
continue;
|
3672 |
|
|
}
|
3673 |
|
|
|
3674 |
|
|
/* Get the ScsiLookup index pointer
|
3675 |
|
|
* from the SC pointer.
|
3676 |
|
|
*/
|
3677 |
|
|
if (!SCpnt->host_scribble || ((MPT_SCSI_HOST *)SCpnt->host->hostdata != hd)) {
|
3678 |
|
|
/* The command associated with the
|
3679 |
|
|
* abort/reset request must have
|
3680 |
|
|
* completed and this is a stale
|
3681 |
|
|
* request. We are done.
|
3682 |
|
|
* Free the current MF and continue.
|
3683 |
|
|
*/
|
3684 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
|
3685 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3686 |
|
|
hd->tmPending = 0;
|
3687 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3688 |
|
|
continue;
|
3689 |
|
|
}
|
3690 |
|
|
|
3691 |
|
|
scpnt_idx = MFPTR_2_MPT_INDEX(hd->ioc, SCpnt->host_scribble);
|
3692 |
|
|
if (scpnt_idx != SCPNT_TO_LOOKUP_IDX(SCpnt)) {
|
3693 |
|
|
/* Error! this should never happen!!
|
3694 |
|
|
*/
|
3695 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
|
3696 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3697 |
|
|
hd->tmPending = 0;
|
3698 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3699 |
|
|
continue;
|
3700 |
|
|
}
|
3701 |
|
|
|
3702 |
|
|
task_type = mf->u.frame.linkage.arg1;
|
3703 |
|
|
ctx2abort = 0;
|
3704 |
|
|
if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
|
3705 |
|
|
MPT_FRAME_HDR *SCpntMf;
|
3706 |
|
|
|
3707 |
|
|
/*
|
3708 |
|
|
* Most important! Set TaskMsgContext to SCpnt's MsgContext!
|
3709 |
|
|
* (the IO to be ABORT'd)
|
3710 |
|
|
*
|
3711 |
|
|
* NOTE: Since we do not byteswap MsgContext, we do not
|
3712 |
|
|
* swap it here either. It is an opaque cookie to
|
3713 |
|
|
* the controller, so it does not matter. -DaveM
|
3714 |
|
|
*/
|
3715 |
|
|
SCpntMf = (MPT_FRAME_HDR *) SCpnt->host_scribble;
|
3716 |
|
|
ctx2abort = SCpntMf->u.frame.hwhdr.msgctxu.MsgContext;
|
3717 |
|
|
|
3718 |
|
|
hd->abortSCpnt = SCpnt;
|
3719 |
|
|
printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (mf=%p:sc=%p)\n",
|
3720 |
|
|
(void *) mf, (void *) SCpnt);
|
3721 |
|
|
}
|
3722 |
|
|
|
3723 |
|
|
/* The TM handler will allocate a new mf,
|
3724 |
|
|
* so free the current mf.
|
3725 |
|
|
*/
|
3726 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
|
3727 |
|
|
mf = NULL;
|
3728 |
|
|
|
3729 |
|
|
#ifndef MPTSCSIH_DBG_TIMEOUT
|
3730 |
|
|
post_pendingQ_commands(hd);
|
3731 |
|
|
#endif
|
3732 |
|
|
if (mptscsih_TMHandler(hd, task_type, SCpnt->channel,
|
3733 |
|
|
SCpnt->target, SCpnt->lun,
|
3734 |
|
|
ctx2abort, CAN_SLEEP) < 0) {
|
3735 |
|
|
|
3736 |
|
|
/* The TM request failed and the subsequent FW-reload failed!
|
3737 |
|
|
* Fatal error case.
|
3738 |
|
|
*/
|
3739 |
|
|
printk(KERN_WARNING MYNAM
|
3740 |
|
|
": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", (void *) SCpnt);
|
3741 |
|
|
|
3742 |
|
|
if (hd->ScsiLookup[scpnt_idx] != NULL) {
|
3743 |
|
|
atomic_dec(&queue_depth);
|
3744 |
|
|
SCpnt->result = DID_SOFT_ERROR << 16;
|
3745 |
|
|
MPT_HOST_LOCK(flags);
|
3746 |
|
|
SCpnt->scsi_done(SCpnt);
|
3747 |
|
|
MPT_HOST_UNLOCK(flags);
|
3748 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
|
3749 |
|
|
}
|
3750 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3751 |
|
|
hd->tmPending = 0;
|
3752 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3753 |
|
|
hd->abortSCpnt = NULL;
|
3754 |
|
|
}
|
3755 |
|
|
}
|
3756 |
|
|
}
|
3757 |
|
|
if (atomic_read(&mpt_taskQdepth) > 0)
|
3758 |
|
|
did++;
|
3759 |
|
|
|
3760 |
|
|
} while ( did );
|
3761 |
|
|
|
3762 |
|
|
spin_lock_irqsave(&mytaskQ_lock, flags);
|
3763 |
|
|
mytaskQ_bh_active = 0;
|
3764 |
|
|
spin_unlock_irqrestore(&mytaskQ_lock, flags);
|
3765 |
|
|
|
3766 |
|
|
return;
|
3767 |
|
|
}
|
3768 |
|
|
#endif /* } */
|
3769 |
|
|
|
3770 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3771 |
|
|
/**
|
3772 |
|
|
* mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
|
3773 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
3774 |
|
|
* @mf: Pointer to SCSI task mgmt request frame
|
3775 |
|
|
* @mr: Pointer to SCSI task mgmt reply frame
|
3776 |
|
|
*
|
3777 |
|
|
* This routine is called from mptbase.c::mpt_interrupt() at the completion
|
3778 |
|
|
* of any SCSI task management request.
|
3779 |
|
|
* This routine is registered with the MPT (base) driver at driver
|
3780 |
|
|
* load/init time via the mpt_register() API call.
|
3781 |
|
|
*
|
3782 |
|
|
* Returns 1 indicating alloc'd request frame ptr should be freed.
|
3783 |
|
|
*/
|
3784 |
|
|
static int
|
3785 |
|
|
mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
3786 |
|
|
{
|
3787 |
|
|
SCSITaskMgmtReply_t *pScsiTmReply;
|
3788 |
|
|
SCSITaskMgmt_t *pScsiTmReq;
|
3789 |
|
|
MPT_SCSI_HOST *hd;
|
3790 |
|
|
unsigned long flags;
|
3791 |
|
|
u8 tmType = 0;
|
3792 |
|
|
|
3793 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n",
|
3794 |
|
|
ioc->name, mf, mr));
|
3795 |
|
|
if (ioc->sh) {
|
3796 |
|
|
/* Depending on the thread, a timer is activated for
|
3797 |
|
|
* the TM request. Delete this timer on completion of TM.
|
3798 |
|
|
* Decrement count of outstanding TM requests.
|
3799 |
|
|
*/
|
3800 |
|
|
hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
|
3801 |
|
|
if (hd->tmPtr) {
|
3802 |
|
|
del_timer(&hd->TMtimer);
|
3803 |
|
|
}
|
3804 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n",
|
3805 |
|
|
ioc->name, hd->taskQcnt));
|
3806 |
|
|
} else {
|
3807 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
|
3808 |
|
|
ioc->name));
|
3809 |
|
|
return 1;
|
3810 |
|
|
}
|
3811 |
|
|
|
3812 |
|
|
if (mr == NULL) {
|
3813 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
|
3814 |
|
|
ioc->name, mf));
|
3815 |
|
|
return 1;
|
3816 |
|
|
} else {
|
3817 |
|
|
pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
|
3818 |
|
|
pScsiTmReq = (SCSITaskMgmt_t*)mf;
|
3819 |
|
|
|
3820 |
|
|
/* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
|
3821 |
|
|
tmType = pScsiTmReq->TaskType;
|
3822 |
|
|
|
3823 |
|
|
dtmprintk((KERN_INFO " TaskType = %d, TerminationCount=%d\n",
|
3824 |
|
|
tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
|
3825 |
|
|
|
3826 |
|
|
/* Error? (anything non-zero?) */
|
3827 |
|
|
if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
|
3828 |
|
|
u16 iocstatus;
|
3829 |
|
|
|
3830 |
|
|
iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
3831 |
|
|
dtmprintk((KERN_INFO " SCSI TaskMgmt (%d) - Oops!\n", tmType));
|
3832 |
|
|
dtmprintk((KERN_INFO " IOCStatus = %04xh\n", iocstatus));
|
3833 |
|
|
dtmprintk((KERN_INFO " IOCLogInfo = %08xh\n",
|
3834 |
|
|
le32_to_cpu(pScsiTmReply->IOCLogInfo)));
|
3835 |
|
|
|
3836 |
|
|
/* clear flags and continue.
|
3837 |
|
|
*/
|
3838 |
|
|
if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
|
3839 |
|
|
hd->abortSCpnt = NULL;
|
3840 |
|
|
|
3841 |
|
|
/* If an internal command is present
|
3842 |
|
|
* or the TM failed - reload the FW.
|
3843 |
|
|
* FC FW may respond FAILED to an ABORT
|
3844 |
|
|
*/
|
3845 |
|
|
if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
|
3846 |
|
|
if ((hd->cmdPtr) ||
|
3847 |
|
|
(iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
|
3848 |
|
|
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
|
3849 |
|
|
printk((KERN_WARNING
|
3850 |
|
|
" Firmware Reload FAILED!!\n"));
|
3851 |
|
|
}
|
3852 |
|
|
}
|
3853 |
|
|
}
|
3854 |
|
|
} else {
|
3855 |
|
|
dtmprintk((KERN_INFO " SCSI TaskMgmt SUCCESS!\n"));
|
3856 |
|
|
|
3857 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
3858 |
|
|
if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
|
3859 |
|
|
/* clean taskQ - remove tasks associated with
|
3860 |
|
|
* completed commands.
|
3861 |
|
|
*/
|
3862 |
|
|
clean_taskQ(hd);
|
3863 |
|
|
} else if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
|
3864 |
|
|
/* If taskQ contains another request
|
3865 |
|
|
* for this SCpnt, delete this request.
|
3866 |
|
|
*/
|
3867 |
|
|
search_taskQ_for_cmd(hd->abortSCpnt, hd);
|
3868 |
|
|
}
|
3869 |
|
|
#endif
|
3870 |
|
|
hd->numTMrequests--;
|
3871 |
|
|
hd->abortSCpnt = NULL;
|
3872 |
|
|
flush_doneQ(hd);
|
3873 |
|
|
|
3874 |
|
|
}
|
3875 |
|
|
}
|
3876 |
|
|
|
3877 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
3878 |
|
|
/*
|
3879 |
|
|
* Signal to _bh thread that we finished.
|
3880 |
|
|
* This IOC can now process another TM command.
|
3881 |
|
|
*/
|
3882 |
|
|
dtmprintk((MYIOC_s_INFO_FMT "taskmgmt_complete: (=%p) done! Num Failed(%d) Task Count (%d)\n",
|
3883 |
|
|
ioc->name, mf, hd->numTMrequests, hd->taskQcnt));
|
3884 |
|
|
#endif
|
3885 |
|
|
hd->tmPtr = NULL;
|
3886 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
3887 |
|
|
hd->tmPending = 0;
|
3888 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
3889 |
|
|
#ifdef MPT_SCSI_USE_NEW_EH
|
3890 |
|
|
hd->tmState = TM_STATE_NONE;
|
3891 |
|
|
#endif
|
3892 |
|
|
|
3893 |
|
|
return 1;
|
3894 |
|
|
}
|
3895 |
|
|
|
3896 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3897 |
|
|
/*
|
3898 |
|
|
* This is anyones guess quite frankly.
|
3899 |
|
|
*/
|
3900 |
|
|
int
|
3901 |
|
|
mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
|
3902 |
|
|
{
|
3903 |
|
|
unsigned capacity = disk->capacity;
|
3904 |
|
|
int size;
|
3905 |
|
|
|
3906 |
|
|
size = capacity;
|
3907 |
|
|
ip[0] = 64; /* heads */
|
3908 |
|
|
ip[1] = 32; /* sectors */
|
3909 |
|
|
if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */
|
3910 |
|
|
ip[0] = 255; /* heads */
|
3911 |
|
|
ip[1] = 63; /* sectors */
|
3912 |
|
|
ip[2] = size / (255 * 63); /* cylinders */
|
3913 |
|
|
}
|
3914 |
|
|
return 0;
|
3915 |
|
|
}
|
3916 |
|
|
|
3917 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3918 |
|
|
/*
|
3919 |
|
|
* OS entry point to adjust the queue_depths on a per-device basis.
|
3920 |
|
|
* Called once per device the bus scan. Use it to force the queue_depth
|
3921 |
|
|
* member to 1 if a device does not support Q tags.
|
3922 |
|
|
*/
|
3923 |
|
|
void
|
3924 |
|
|
mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
|
3925 |
|
|
{
|
3926 |
|
|
struct scsi_device *device;
|
3927 |
|
|
VirtDevice *pTarget;
|
3928 |
|
|
MPT_SCSI_HOST *hd;
|
3929 |
|
|
|
3930 |
|
|
for (device = sdList; device != NULL; device = device->next) {
|
3931 |
|
|
|
3932 |
|
|
if (device->host != sh)
|
3933 |
|
|
continue;
|
3934 |
|
|
|
3935 |
|
|
hd = (MPT_SCSI_HOST *) sh->hostdata;
|
3936 |
|
|
if (hd == NULL)
|
3937 |
|
|
continue;
|
3938 |
|
|
|
3939 |
|
|
if (hd->Targets != NULL) {
|
3940 |
|
|
pTarget = NULL;
|
3941 |
|
|
if (device->id > sh->max_id) {
|
3942 |
|
|
/* error case, should never happen */
|
3943 |
|
|
device->queue_depth = 1;
|
3944 |
|
|
continue;
|
3945 |
|
|
} else {
|
3946 |
|
|
pTarget = hd->Targets[device->id];
|
3947 |
|
|
}
|
3948 |
|
|
|
3949 |
|
|
if (pTarget == NULL) {
|
3950 |
|
|
/* error case - don't know about this device */
|
3951 |
|
|
device->queue_depth = 1;
|
3952 |
|
|
} else if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
|
3953 |
|
|
if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
|
3954 |
|
|
device->queue_depth = 1;
|
3955 |
|
|
else if (((pTarget->inq_data[0] & 0x1f) == 0x00)
|
3956 |
|
|
&& (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)){
|
3957 |
|
|
device->queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
|
3958 |
|
|
} else
|
3959 |
|
|
device->queue_depth = MPT_SCSI_CMD_PER_DEV_LOW;
|
3960 |
|
|
|
3961 |
|
|
} else {
|
3962 |
|
|
/* error case - No Inq. Data */
|
3963 |
|
|
device->queue_depth = 1;
|
3964 |
|
|
}
|
3965 |
|
|
|
3966 |
|
|
if (pTarget != NULL) {
|
3967 |
|
|
dprintk((MYIOC_s_INFO_FMT
|
3968 |
|
|
"scsi%d: Id=%d Lun=%d: Queue depth=%d\n",
|
3969 |
|
|
hd->ioc->name,
|
3970 |
|
|
device->id, device->lun, device->queue_depth));
|
3971 |
|
|
|
3972 |
|
|
dprintk((MYIOC_s_INFO_FMT
|
3973 |
|
|
"Id = %d, sync factor = %x\n",
|
3974 |
|
|
hd->ioc->name, pTarget->target_id,
|
3975 |
|
|
pTarget->minSyncFactor));
|
3976 |
|
|
}
|
3977 |
|
|
}
|
3978 |
|
|
}
|
3979 |
|
|
}
|
3980 |
|
|
|
3981 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3982 |
|
|
/*
|
3983 |
|
|
* Private routines...
|
3984 |
|
|
*/
|
3985 |
|
|
|
3986 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
3987 |
|
|
/* Utility function to copy sense data from the scsi_cmnd buffer
|
3988 |
|
|
* to the FC and SCSI target structures.
|
3989 |
|
|
*
|
3990 |
|
|
*/
|
3991 |
|
|
static void
|
3992 |
|
|
copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
|
3993 |
|
|
{
|
3994 |
|
|
VirtDevice *target;
|
3995 |
|
|
SCSIIORequest_t *pReq;
|
3996 |
|
|
u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
|
3997 |
|
|
int index;
|
3998 |
|
|
char devFoo[96];
|
3999 |
|
|
IO_Info_t thisIo;
|
4000 |
|
|
|
4001 |
|
|
/* Get target structure
|
4002 |
|
|
*/
|
4003 |
|
|
pReq = (SCSIIORequest_t *) mf;
|
4004 |
|
|
index = (int) pReq->TargetID;
|
4005 |
|
|
target = hd->Targets[index];
|
4006 |
|
|
if (hd->is_multipath && sc->device->hostdata)
|
4007 |
|
|
target = (VirtDevice *) sc->device->hostdata;
|
4008 |
|
|
|
4009 |
|
|
if (sense_count) {
|
4010 |
|
|
u8 *sense_data;
|
4011 |
|
|
int req_index;
|
4012 |
|
|
|
4013 |
|
|
/* Copy the sense received into the scsi command block. */
|
4014 |
|
|
req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
4015 |
|
|
sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
|
4016 |
|
|
memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
|
4017 |
|
|
|
4018 |
|
|
/* Log SMART data (asc = 0x5D, non-IM case only) if required.
|
4019 |
|
|
*/
|
4020 |
|
|
if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
|
4021 |
|
|
if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
|
4022 |
|
|
int idx;
|
4023 |
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
4024 |
|
|
|
4025 |
|
|
idx = ioc->eventContext % ioc->eventLogSize;
|
4026 |
|
|
ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
|
4027 |
|
|
ioc->events[idx].eventContext = ioc->eventContext;
|
4028 |
|
|
|
4029 |
|
|
ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
|
4030 |
|
|
(MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
|
4031 |
|
|
(pReq->Bus << 8) || pReq->TargetID;
|
4032 |
|
|
|
4033 |
|
|
ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
|
4034 |
|
|
|
4035 |
|
|
ioc->eventContext++;
|
4036 |
|
|
}
|
4037 |
|
|
}
|
4038 |
|
|
|
4039 |
|
|
/* Print an error report for the user.
|
4040 |
|
|
*/
|
4041 |
|
|
thisIo.cdbPtr = sc->cmnd;
|
4042 |
|
|
thisIo.sensePtr = sc->sense_buffer;
|
4043 |
|
|
thisIo.SCSIStatus = pScsiReply->SCSIStatus;
|
4044 |
|
|
thisIo.DoDisplay = 1;
|
4045 |
|
|
if (hd->is_multipath)
|
4046 |
|
|
sprintf(devFoo, "%d:%d:%d",
|
4047 |
|
|
hd->ioc->id,
|
4048 |
|
|
pReq->TargetID,
|
4049 |
|
|
pReq->LUN[1]);
|
4050 |
|
|
else
|
4051 |
|
|
sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->target, sc->lun);
|
4052 |
|
|
thisIo.DevIDStr = devFoo;
|
4053 |
|
|
/* fubar */
|
4054 |
|
|
thisIo.dataPtr = NULL;
|
4055 |
|
|
thisIo.inqPtr = NULL;
|
4056 |
|
|
if (sc->device) {
|
4057 |
|
|
thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */
|
4058 |
|
|
}
|
4059 |
|
|
(void) mpt_ScsiHost_ErrorReport(&thisIo);
|
4060 |
|
|
|
4061 |
|
|
} else {
|
4062 |
|
|
dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
|
4063 |
|
|
hd->ioc->name));
|
4064 |
|
|
}
|
4065 |
|
|
|
4066 |
|
|
return;
|
4067 |
|
|
}
|
4068 |
|
|
|
4069 |
|
|
static u32
|
4070 |
|
|
SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc)
|
4071 |
|
|
{
|
4072 |
|
|
MPT_SCSI_HOST *hd;
|
4073 |
|
|
int i;
|
4074 |
|
|
|
4075 |
|
|
hd = (MPT_SCSI_HOST *) sc->host->hostdata;
|
4076 |
|
|
|
4077 |
|
|
for (i = 0; i < hd->ioc->req_depth; i++) {
|
4078 |
|
|
if (hd->ScsiLookup[i] == sc) {
|
4079 |
|
|
return i;
|
4080 |
|
|
}
|
4081 |
|
|
}
|
4082 |
|
|
|
4083 |
|
|
return -1;
|
4084 |
|
|
}
|
4085 |
|
|
|
4086 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4087 |
|
|
|
4088 |
|
|
/* see mptscsih.h */
|
4089 |
|
|
|
4090 |
|
|
#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
|
4091 |
|
|
static Scsi_Host_Template driver_template = MPT_SCSIHOST;
|
4092 |
|
|
# include "../../scsi/scsi_module.c"
|
4093 |
|
|
#endif
|
4094 |
|
|
|
4095 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4096 |
|
|
/* Search the pendingQ for a command with specific index.
|
4097 |
|
|
* If found, delete and return mf pointer
|
4098 |
|
|
* If not found, return NULL
|
4099 |
|
|
*/
|
4100 |
|
|
static MPT_FRAME_HDR *
|
4101 |
|
|
mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx)
|
4102 |
|
|
{
|
4103 |
|
|
unsigned long flags;
|
4104 |
|
|
MPT_DONE_Q *buffer;
|
4105 |
|
|
MPT_FRAME_HDR *mf = NULL;
|
4106 |
|
|
MPT_FRAME_HDR *cmdMfPtr;
|
4107 |
|
|
|
4108 |
|
|
ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name));
|
4109 |
|
|
cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
|
4110 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
4111 |
|
|
if (!Q_IS_EMPTY(&hd->pendingQ)) {
|
4112 |
|
|
buffer = hd->pendingQ.head;
|
4113 |
|
|
do {
|
4114 |
|
|
mf = (MPT_FRAME_HDR *) buffer->argp;
|
4115 |
|
|
if (mf == cmdMfPtr) {
|
4116 |
|
|
Q_DEL_ITEM(buffer);
|
4117 |
|
|
|
4118 |
|
|
/* clear the arg pointer
|
4119 |
|
|
*/
|
4120 |
|
|
buffer->argp = NULL;
|
4121 |
|
|
|
4122 |
|
|
/* Add to the freeQ
|
4123 |
|
|
*/
|
4124 |
|
|
Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
|
4125 |
|
|
break;
|
4126 |
|
|
}
|
4127 |
|
|
mf = NULL;
|
4128 |
|
|
} while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ);
|
4129 |
|
|
}
|
4130 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
4131 |
|
|
ddvtprintk((" ...return %p\n", mf));
|
4132 |
|
|
return mf;
|
4133 |
|
|
}
|
4134 |
|
|
|
4135 |
|
|
/* Post all commands on the pendingQ to the FW.
|
4136 |
|
|
* Lock Q when deleting/adding members
|
4137 |
|
|
* Lock io_request_lock for OS callback.
|
4138 |
|
|
*/
|
4139 |
|
|
static void
|
4140 |
|
|
post_pendingQ_commands(MPT_SCSI_HOST *hd)
|
4141 |
|
|
{
|
4142 |
|
|
MPT_FRAME_HDR *mf;
|
4143 |
|
|
MPT_DONE_Q *buffer;
|
4144 |
|
|
unsigned long flags;
|
4145 |
|
|
|
4146 |
|
|
/* Flush the pendingQ.
|
4147 |
|
|
*/
|
4148 |
|
|
ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name));
|
4149 |
|
|
while (1) {
|
4150 |
|
|
spin_lock_irqsave(&hd->freedoneQlock, flags);
|
4151 |
|
|
if (Q_IS_EMPTY(&hd->pendingQ)) {
|
4152 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
4153 |
|
|
break;
|
4154 |
|
|
}
|
4155 |
|
|
|
4156 |
|
|
buffer = hd->pendingQ.head;
|
4157 |
|
|
/* Delete from Q
|
4158 |
|
|
*/
|
4159 |
|
|
Q_DEL_ITEM(buffer);
|
4160 |
|
|
|
4161 |
|
|
mf = (MPT_FRAME_HDR *) buffer->argp;
|
4162 |
|
|
buffer->argp = NULL;
|
4163 |
|
|
|
4164 |
|
|
/* Add to the freeQ
|
4165 |
|
|
*/
|
4166 |
|
|
Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
|
4167 |
|
|
spin_unlock_irqrestore(&hd->freedoneQlock, flags);
|
4168 |
|
|
|
4169 |
|
|
if (!mf) {
|
4170 |
|
|
/* This should never happen */
|
4171 |
|
|
printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, (void *) mf);
|
4172 |
|
|
continue;
|
4173 |
|
|
}
|
4174 |
|
|
|
4175 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
|
4176 |
|
|
|
4177 |
|
|
#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
|
4178 |
|
|
{
|
4179 |
|
|
u16 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
4180 |
|
|
Scsi_Cmnd *sc = hd->ScsiLookup[req_idx];
|
4181 |
|
|
printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n",
|
4182 |
|
|
hd->ioc->name, sc, req_idx, mf);
|
4183 |
|
|
}
|
4184 |
|
|
#endif
|
4185 |
|
|
}
|
4186 |
|
|
|
4187 |
|
|
return;
|
4188 |
|
|
}
|
4189 |
|
|
|
4190 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4191 |
|
|
static int
|
4192 |
|
|
mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
4193 |
|
|
{
|
4194 |
|
|
MPT_SCSI_HOST *hd;
|
4195 |
|
|
unsigned long flags;
|
4196 |
|
|
|
4197 |
|
|
dtmprintk((KERN_WARNING MYNAM
|
4198 |
|
|
": IOC %s_reset routed to SCSI host driver!\n",
|
4199 |
|
|
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
|
4200 |
|
|
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
|
4201 |
|
|
|
4202 |
|
|
/* If a FW reload request arrives after base installed but
|
4203 |
|
|
* before all scsi hosts have been attached, then an alt_ioc
|
4204 |
|
|
* may have a NULL sh pointer.
|
4205 |
|
|
*/
|
4206 |
|
|
if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
|
4207 |
|
|
return 0;
|
4208 |
|
|
else
|
4209 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
4210 |
|
|
|
4211 |
|
|
if (reset_phase == MPT_IOC_SETUP_RESET) {
|
4212 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
|
4213 |
|
|
/* Clean Up:
|
4214 |
|
|
* 1. Set Hard Reset Pending Flag
|
4215 |
|
|
* All new commands go to doneQ
|
4216 |
|
|
*/
|
4217 |
|
|
hd->resetPending = 1;
|
4218 |
|
|
|
4219 |
|
|
/* 2. Reset timeouts on all running commands
|
4220 |
|
|
*/
|
4221 |
|
|
mptscsih_reset_timeouts (hd);
|
4222 |
|
|
|
4223 |
|
|
} else if (reset_phase == MPT_IOC_PRE_RESET) {
|
4224 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
|
4225 |
|
|
|
4226 |
|
|
/* 2. Flush running commands
|
4227 |
|
|
* Clean ScsiLookup (and associated memory)
|
4228 |
|
|
* AND clean mytaskQ
|
4229 |
|
|
*/
|
4230 |
|
|
|
4231 |
|
|
/* 2b. Reply to OS all known outstanding I/O commands.
|
4232 |
|
|
*/
|
4233 |
|
|
mptscsih_flush_running_cmds(hd);
|
4234 |
|
|
|
4235 |
|
|
/* 2c. If there was an internal command that
|
4236 |
|
|
* has not completed, configuration or io request,
|
4237 |
|
|
* free these resources.
|
4238 |
|
|
*/
|
4239 |
|
|
if (hd->cmdPtr) {
|
4240 |
|
|
del_timer(&hd->timer);
|
4241 |
|
|
mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr);
|
4242 |
|
|
atomic_dec(&queue_depth);
|
4243 |
|
|
}
|
4244 |
|
|
|
4245 |
|
|
/* 2d. If a task management has not completed,
|
4246 |
|
|
* free resources associated with this request.
|
4247 |
|
|
*/
|
4248 |
|
|
if (hd->tmPtr) {
|
4249 |
|
|
del_timer(&hd->TMtimer);
|
4250 |
|
|
mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr);
|
4251 |
|
|
}
|
4252 |
|
|
|
4253 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
4254 |
|
|
/* 2e. Delete all commands on taskQ
|
4255 |
|
|
* Should be superfluous - as this taskQ should
|
4256 |
|
|
* be empty.
|
4257 |
|
|
*/
|
4258 |
|
|
clean_taskQ(hd);
|
4259 |
|
|
#endif
|
4260 |
|
|
|
4261 |
|
|
#ifdef MPTSCSIH_DBG_TIMEOUT
|
4262 |
|
|
ioc->timeout_hard = 0;
|
4263 |
|
|
#endif
|
4264 |
|
|
|
4265 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
|
4266 |
|
|
} else {
|
4267 |
|
|
ScsiCfgData *pSpi;
|
4268 |
|
|
|
4269 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
|
4270 |
|
|
|
4271 |
|
|
/* Once a FW reload begins, all new OS commands are
|
4272 |
|
|
* redirected to the doneQ w/ a reset status.
|
4273 |
|
|
* Init all control structures.
|
4274 |
|
|
*/
|
4275 |
|
|
|
4276 |
|
|
/* ScsiLookup initialization
|
4277 |
|
|
*/
|
4278 |
|
|
{
|
4279 |
|
|
int ii;
|
4280 |
|
|
for (ii=0; ii < hd->ioc->req_depth; ii++)
|
4281 |
|
|
hd->ScsiLookup[ii] = NULL;
|
4282 |
|
|
}
|
4283 |
|
|
|
4284 |
|
|
/* 2. Chain Buffer initialization
|
4285 |
|
|
*/
|
4286 |
|
|
mptscsih_initChainBuffers(hd, 0);
|
4287 |
|
|
|
4288 |
|
|
/* 3. tmPtr clear
|
4289 |
|
|
*/
|
4290 |
|
|
if (hd->tmPtr) {
|
4291 |
|
|
hd->tmPtr = NULL;
|
4292 |
|
|
}
|
4293 |
|
|
|
4294 |
|
|
/* 4. Renegotiate to all devices, if SCSI
|
4295 |
|
|
*/
|
4296 |
|
|
if (hd->is_spi)
|
4297 |
|
|
mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
|
4298 |
|
|
|
4299 |
|
|
/* 5. Enable new commands to be posted
|
4300 |
|
|
*/
|
4301 |
|
|
spin_lock_irqsave(&ioc->FreeQlock, flags);
|
4302 |
|
|
hd->tmPending = 0;
|
4303 |
|
|
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
|
4304 |
|
|
hd->resetPending = 0;
|
4305 |
|
|
hd->numTMrequests = 0;
|
4306 |
|
|
#ifdef MPT_SCSI_USE_NEW_EH
|
4307 |
|
|
hd->tmState = TM_STATE_NONE;
|
4308 |
|
|
#endif
|
4309 |
|
|
|
4310 |
|
|
/* 6. If there was an internal command,
|
4311 |
|
|
* wake this process up.
|
4312 |
|
|
*/
|
4313 |
|
|
if (hd->cmdPtr) {
|
4314 |
|
|
/*
|
4315 |
|
|
* Wake up the original calling thread
|
4316 |
|
|
*/
|
4317 |
|
|
hd->pLocal = &hd->localReply;
|
4318 |
|
|
hd->pLocal->completion = MPT_SCANDV_DID_RESET;
|
4319 |
|
|
scandv_wait_done = 1;
|
4320 |
|
|
wake_up(&scandv_waitq);
|
4321 |
|
|
hd->cmdPtr = NULL;
|
4322 |
|
|
}
|
4323 |
|
|
|
4324 |
|
|
/* 7. Flush doneQ
|
4325 |
|
|
*/
|
4326 |
|
|
flush_doneQ(hd);
|
4327 |
|
|
|
4328 |
|
|
/* 8. Set flag to force DV and re-read IOC Page 3
|
4329 |
|
|
*/
|
4330 |
|
|
if (hd->is_spi) {
|
4331 |
|
|
pSpi = &ioc->spi_data;
|
4332 |
|
|
pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
|
4333 |
|
|
ddvtprintk(("Set reload IOC Pg3 Flag\n"));
|
4334 |
|
|
}
|
4335 |
|
|
|
4336 |
|
|
dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
|
4337 |
|
|
}
|
4338 |
|
|
|
4339 |
|
|
return 1; /* currently means nothing really */
|
4340 |
|
|
}
|
4341 |
|
|
|
4342 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4343 |
|
|
static int
|
4344 |
|
|
mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
4345 |
|
|
{
|
4346 |
|
|
MPT_SCSI_HOST *hd;
|
4347 |
|
|
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
|
4348 |
|
|
|
4349 |
|
|
dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
|
4350 |
|
|
ioc->name, event));
|
4351 |
|
|
|
4352 |
|
|
switch (event) {
|
4353 |
|
|
case MPI_EVENT_UNIT_ATTENTION: /* 03 */
|
4354 |
|
|
/* FIXME! */
|
4355 |
|
|
break;
|
4356 |
|
|
case MPI_EVENT_IOC_BUS_RESET: /* 04 */
|
4357 |
|
|
case MPI_EVENT_EXT_BUS_RESET: /* 05 */
|
4358 |
|
|
hd = NULL;
|
4359 |
|
|
if (ioc->sh) {
|
4360 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
4361 |
|
|
if (hd && (hd->is_spi) && (hd->soft_resets < -1))
|
4362 |
|
|
hd->soft_resets++;
|
4363 |
|
|
}
|
4364 |
|
|
break;
|
4365 |
|
|
case MPI_EVENT_LOGOUT: /* 09 */
|
4366 |
|
|
/* FIXME! */
|
4367 |
|
|
break;
|
4368 |
|
|
|
4369 |
|
|
/*
|
4370 |
|
|
* CHECKME! Don't think we need to do
|
4371 |
|
|
* anything for these, but...
|
4372 |
|
|
*/
|
4373 |
|
|
case MPI_EVENT_RESCAN: /* 06 */
|
4374 |
|
|
case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
|
4375 |
|
|
case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
|
4376 |
|
|
/*
|
4377 |
|
|
* CHECKME! Falling thru...
|
4378 |
|
|
*/
|
4379 |
|
|
break;
|
4380 |
|
|
|
4381 |
|
|
case MPI_EVENT_INTEGRATED_RAID: /* 0B */
|
4382 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
4383 |
|
|
/* negoNvram set to 0 if DV enabled and to USE_NVRAM if
|
4384 |
|
|
* if DV disabled. Need to check for target mode.
|
4385 |
|
|
*/
|
4386 |
|
|
hd = NULL;
|
4387 |
|
|
if (ioc->sh)
|
4388 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
4389 |
|
|
|
4390 |
|
|
if (hd && (hd->is_spi) && (hd->negoNvram == 0)) {
|
4391 |
|
|
ScsiCfgData *pSpi;
|
4392 |
|
|
Ioc3PhysDisk_t *pPDisk;
|
4393 |
|
|
int numPDisk;
|
4394 |
|
|
u8 reason;
|
4395 |
|
|
u8 physDiskNum;
|
4396 |
|
|
|
4397 |
|
|
reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
|
4398 |
|
|
if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
|
4399 |
|
|
/* New or replaced disk.
|
4400 |
|
|
* Set DV flag and schedule DV.
|
4401 |
|
|
*/
|
4402 |
|
|
pSpi = &ioc->spi_data;
|
4403 |
|
|
physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
|
4404 |
|
|
ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
|
4405 |
|
|
if (pSpi->pIocPg3) {
|
4406 |
|
|
pPDisk = pSpi->pIocPg3->PhysDisk;
|
4407 |
|
|
numPDisk =pSpi->pIocPg3->NumPhysDisks;
|
4408 |
|
|
|
4409 |
|
|
while (numPDisk) {
|
4410 |
|
|
if (physDiskNum == pPDisk->PhysDiskNum) {
|
4411 |
|
|
pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
|
4412 |
|
|
pSpi->forceDv = MPT_SCSICFG_NEED_DV;
|
4413 |
|
|
ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
|
4414 |
|
|
break;
|
4415 |
|
|
}
|
4416 |
|
|
pPDisk++;
|
4417 |
|
|
numPDisk--;
|
4418 |
|
|
}
|
4419 |
|
|
|
4420 |
|
|
if (numPDisk == 0) {
|
4421 |
|
|
/* The physical disk that needs DV was not found
|
4422 |
|
|
* in the stored IOC Page 3. The driver must reload
|
4423 |
|
|
* this page. DV routine will set the NEED_DV flag for
|
4424 |
|
|
* all phys disks that have DV_NOT_DONE set.
|
4425 |
|
|
*/
|
4426 |
|
|
pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
|
4427 |
|
|
ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
|
4428 |
|
|
}
|
4429 |
|
|
}
|
4430 |
|
|
}
|
4431 |
|
|
}
|
4432 |
|
|
#endif
|
4433 |
|
|
|
4434 |
|
|
#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
|
4435 |
|
|
printk("Raid Event RF: ");
|
4436 |
|
|
{
|
4437 |
|
|
u32 *m = (u32 *)pEvReply;
|
4438 |
|
|
int ii;
|
4439 |
|
|
int n = (int)pEvReply->MsgLength;
|
4440 |
|
|
for (ii=6; ii < n; ii++)
|
4441 |
|
|
printk(" %08x", le32_to_cpu(m[ii]));
|
4442 |
|
|
printk("\n");
|
4443 |
|
|
}
|
4444 |
|
|
#endif
|
4445 |
|
|
break;
|
4446 |
|
|
|
4447 |
|
|
case MPI_EVENT_NONE: /* 00 */
|
4448 |
|
|
case MPI_EVENT_LOG_DATA: /* 01 */
|
4449 |
|
|
case MPI_EVENT_STATE_CHANGE: /* 02 */
|
4450 |
|
|
case MPI_EVENT_EVENT_CHANGE: /* 0A */
|
4451 |
|
|
default:
|
4452 |
|
|
dprintk((KERN_INFO " Ignoring event (=%02Xh)\n", event));
|
4453 |
|
|
break;
|
4454 |
|
|
}
|
4455 |
|
|
|
4456 |
|
|
return 1; /* currently means nothing really */
|
4457 |
|
|
}
|
4458 |
|
|
|
4459 |
|
|
#if 0 /* { */
|
4460 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4461 |
|
|
/*
|
4462 |
|
|
* scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
|
4463 |
|
|
*
|
4464 |
|
|
* drivers/message/fusion/scsiherr.c
|
4465 |
|
|
*/
|
4466 |
|
|
|
4467 |
|
|
//extern const char **mpt_ScsiOpcodesPtr; /* needed by mptscsih.c */
|
4468 |
|
|
//extern ASCQ_Table_t *mpt_ASCQ_TablePtr;
|
4469 |
|
|
//extern int mpt_ASCQ_TableSz;
|
4470 |
|
|
|
4471 |
|
|
#define MYNAM "mptscsih"
|
4472 |
|
|
|
4473 |
|
|
#endif /* } */
|
4474 |
|
|
|
4475 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4476 |
|
|
/*
|
4477 |
|
|
* Private data...
|
4478 |
|
|
*/
|
4479 |
|
|
static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
|
4480 |
|
|
|
4481 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4482 |
|
|
/* old symsense.c stuff... */
|
4483 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4484 |
|
|
/*
|
4485 |
|
|
* Private data...
|
4486 |
|
|
* To protect ourselves against those that would pass us bogus pointers
|
4487 |
|
|
*/
|
4488 |
|
|
static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
|
4489 |
|
|
= { 0x1F, 0x00, 0x00, 0x00,
|
4490 |
|
|
0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
4491 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
4492 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
4493 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
4494 |
|
|
static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
|
4495 |
|
|
= { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
|
4496 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
4497 |
|
|
0x00, 0x00 };
|
4498 |
|
|
static u8 dummyCDB[16]
|
4499 |
|
|
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
4500 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
4501 |
|
|
static u8 dummyScsiData[16]
|
4502 |
|
|
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
4503 |
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
4504 |
|
|
|
4505 |
|
|
#if 0
|
4506 |
|
|
static const char *PeripheralDeviceTypeString[32] = {
|
4507 |
|
|
"Direct-access", /* 00h */
|
4508 |
|
|
"Sequential-access", /* 01h */
|
4509 |
|
|
"Printer", /* 02h */
|
4510 |
|
|
"Processor", /* 03h */
|
4511 |
|
|
/*"Write-Once-Read-Multiple",*/ /* 04h */
|
4512 |
|
|
"WORM", /* 04h */
|
4513 |
|
|
"CD-ROM", /* 05h */
|
4514 |
|
|
"Scanner", /* 06h */
|
4515 |
|
|
"Optical memory", /* 07h */
|
4516 |
|
|
"Media Changer", /* 08h */
|
4517 |
|
|
"Communications", /* 09h */
|
4518 |
|
|
"(Graphics arts pre-press)", /* 0Ah */
|
4519 |
|
|
"(Graphics arts pre-press)", /* 0Bh */
|
4520 |
|
|
"Array controller", /* 0Ch */
|
4521 |
|
|
"Enclosure services", /* 0Dh */
|
4522 |
|
|
"Simplified direct-access", /* 0Eh */
|
4523 |
|
|
"Reserved-0Fh", /* 0Fh */
|
4524 |
|
|
"Reserved-10h", /* 10h */
|
4525 |
|
|
"Reserved-11h", /* 11h */
|
4526 |
|
|
"Reserved-12h", /* 12h */
|
4527 |
|
|
"Reserved-13h", /* 13h */
|
4528 |
|
|
"Reserved-14h", /* 14h */
|
4529 |
|
|
"Reserved-15h", /* 15h */
|
4530 |
|
|
"Reserved-16h", /* 16h */
|
4531 |
|
|
"Reserved-17h", /* 17h */
|
4532 |
|
|
"Reserved-18h", /* 18h */
|
4533 |
|
|
"Reserved-19h", /* 19h */
|
4534 |
|
|
"Reserved-1Ah", /* 1Ah */
|
4535 |
|
|
"Reserved-1Bh", /* 1Bh */
|
4536 |
|
|
"Reserved-1Ch", /* 1Ch */
|
4537 |
|
|
"Reserved-1Dh", /* 1Dh */
|
4538 |
|
|
"Reserved-1Eh", /* 1Eh */
|
4539 |
|
|
"Unknown" /* 1Fh */
|
4540 |
|
|
};
|
4541 |
|
|
#endif
|
4542 |
|
|
|
4543 |
|
|
static char *ScsiStatusString[] = {
|
4544 |
|
|
"GOOD", /* 00h */
|
4545 |
|
|
NULL, /* 01h */
|
4546 |
|
|
"CHECK CONDITION", /* 02h */
|
4547 |
|
|
NULL, /* 03h */
|
4548 |
|
|
"CONDITION MET", /* 04h */
|
4549 |
|
|
NULL, /* 05h */
|
4550 |
|
|
NULL, /* 06h */
|
4551 |
|
|
NULL, /* 07h */
|
4552 |
|
|
"BUSY", /* 08h */
|
4553 |
|
|
NULL, /* 09h */
|
4554 |
|
|
NULL, /* 0Ah */
|
4555 |
|
|
NULL, /* 0Bh */
|
4556 |
|
|
NULL, /* 0Ch */
|
4557 |
|
|
NULL, /* 0Dh */
|
4558 |
|
|
NULL, /* 0Eh */
|
4559 |
|
|
NULL, /* 0Fh */
|
4560 |
|
|
"INTERMEDIATE", /* 10h */
|
4561 |
|
|
NULL, /* 11h */
|
4562 |
|
|
NULL, /* 12h */
|
4563 |
|
|
NULL, /* 13h */
|
4564 |
|
|
"INTERMEDIATE-CONDITION MET", /* 14h */
|
4565 |
|
|
NULL, /* 15h */
|
4566 |
|
|
NULL, /* 16h */
|
4567 |
|
|
NULL, /* 17h */
|
4568 |
|
|
"RESERVATION CONFLICT", /* 18h */
|
4569 |
|
|
NULL, /* 19h */
|
4570 |
|
|
NULL, /* 1Ah */
|
4571 |
|
|
NULL, /* 1Bh */
|
4572 |
|
|
NULL, /* 1Ch */
|
4573 |
|
|
NULL, /* 1Dh */
|
4574 |
|
|
NULL, /* 1Eh */
|
4575 |
|
|
NULL, /* 1Fh */
|
4576 |
|
|
NULL, /* 20h */
|
4577 |
|
|
NULL, /* 21h */
|
4578 |
|
|
"COMMAND TERMINATED", /* 22h */
|
4579 |
|
|
NULL, /* 23h */
|
4580 |
|
|
NULL, /* 24h */
|
4581 |
|
|
NULL, /* 25h */
|
4582 |
|
|
NULL, /* 26h */
|
4583 |
|
|
NULL, /* 27h */
|
4584 |
|
|
"TASK SET FULL", /* 28h */
|
4585 |
|
|
NULL, /* 29h */
|
4586 |
|
|
NULL, /* 2Ah */
|
4587 |
|
|
NULL, /* 2Bh */
|
4588 |
|
|
NULL, /* 2Ch */
|
4589 |
|
|
NULL, /* 2Dh */
|
4590 |
|
|
NULL, /* 2Eh */
|
4591 |
|
|
NULL, /* 2Fh */
|
4592 |
|
|
"ACA ACTIVE", /* 30h */
|
4593 |
|
|
NULL
|
4594 |
|
|
};
|
4595 |
|
|
|
4596 |
|
|
static const char *ScsiCommonOpString[] = {
|
4597 |
|
|
"TEST UNIT READY", /* 00h */
|
4598 |
|
|
"REZERO UNIT (REWIND)", /* 01h */
|
4599 |
|
|
NULL, /* 02h */
|
4600 |
|
|
"REQUEST_SENSE", /* 03h */
|
4601 |
|
|
"FORMAT UNIT (MEDIUM)", /* 04h */
|
4602 |
|
|
"READ BLOCK LIMITS", /* 05h */
|
4603 |
|
|
NULL, /* 06h */
|
4604 |
|
|
"REASSIGN BLOCKS", /* 07h */
|
4605 |
|
|
"READ(6)", /* 08h */
|
4606 |
|
|
NULL, /* 09h */
|
4607 |
|
|
"WRITE(6)", /* 0Ah */
|
4608 |
|
|
"SEEK(6)", /* 0Bh */
|
4609 |
|
|
NULL, /* 0Ch */
|
4610 |
|
|
NULL, /* 0Dh */
|
4611 |
|
|
NULL, /* 0Eh */
|
4612 |
|
|
"READ REVERSE", /* 0Fh */
|
4613 |
|
|
"WRITE_FILEMARKS", /* 10h */
|
4614 |
|
|
"SPACE(6)", /* 11h */
|
4615 |
|
|
"INQUIRY", /* 12h */
|
4616 |
|
|
NULL
|
4617 |
|
|
};
|
4618 |
|
|
|
4619 |
|
|
static const char *SenseKeyString[] = {
|
4620 |
|
|
"NO SENSE", /* 0h */
|
4621 |
|
|
"RECOVERED ERROR", /* 1h */
|
4622 |
|
|
"NOT READY", /* 2h */
|
4623 |
|
|
"MEDIUM ERROR", /* 3h */
|
4624 |
|
|
"HARDWARE ERROR", /* 4h */
|
4625 |
|
|
"ILLEGAL REQUEST", /* 5h */
|
4626 |
|
|
"UNIT ATTENTION", /* 6h */
|
4627 |
|
|
"DATA PROTECT", /* 7h */
|
4628 |
|
|
"BLANK CHECK", /* 8h */
|
4629 |
|
|
"VENDOR-SPECIFIC", /* 9h */
|
4630 |
|
|
"ABORTED COPY", /* Ah */
|
4631 |
|
|
"ABORTED COMMAND", /* Bh */
|
4632 |
|
|
"EQUAL (obsolete)", /* Ch */
|
4633 |
|
|
"VOLUME OVERFLOW", /* Dh */
|
4634 |
|
|
"MISCOMPARE", /* Eh */
|
4635 |
|
|
"RESERVED", /* Fh */
|
4636 |
|
|
NULL
|
4637 |
|
|
};
|
4638 |
|
|
|
4639 |
|
|
#define SPECIAL_ASCQ(c,q) \
|
4640 |
|
|
(((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
|
4641 |
|
|
|
4642 |
|
|
#if 0
|
4643 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4644 |
|
|
/*
|
4645 |
|
|
* Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
|
4646 |
|
|
* then print additional information via
|
4647 |
|
|
* a call to SDMS_SystemAlert().
|
4648 |
|
|
*/
|
4649 |
|
|
static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
|
4650 |
|
|
{
|
4651 |
|
|
u8 *sd;
|
4652 |
|
|
u8 BadValue;
|
4653 |
|
|
u8 SenseKey;
|
4654 |
|
|
int Offset;
|
4655 |
|
|
int len = strlen(msg1);
|
4656 |
|
|
|
4657 |
|
|
sd = ioop->sensePtr;
|
4658 |
|
|
if (SD_Additional_Sense_Length(sd) < 8)
|
4659 |
|
|
return;
|
4660 |
|
|
|
4661 |
|
|
SenseKey = SD_Sense_Key(sd);
|
4662 |
|
|
|
4663 |
|
|
if (SD_Sense_Key_Specific_Valid(sd)) {
|
4664 |
|
|
if (SenseKey == SK_ILLEGAL_REQUEST) {
|
4665 |
|
|
Offset = SD_Bad_Byte(sd);
|
4666 |
|
|
if (SD_Was_Illegal_Request(sd)) {
|
4667 |
|
|
BadValue = ioop->cdbPtr[Offset];
|
4668 |
|
|
len += sprintf(msg1+len, "\n Illegal CDB value=%02Xh found at CDB ",
|
4669 |
|
|
BadValue);
|
4670 |
|
|
} else {
|
4671 |
|
|
BadValue = ioop->dataPtr[Offset];
|
4672 |
|
|
len += sprintf(msg1+len, "\n Illegal DATA value=%02Xh found at DATA ",
|
4673 |
|
|
BadValue);
|
4674 |
|
|
}
|
4675 |
|
|
len += sprintf(msg1+len, "byte=%02Xh", Offset);
|
4676 |
|
|
if (SD_SKS_Bit_Pointer_Valid(sd))
|
4677 |
|
|
len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
|
4678 |
|
|
} else if ((SenseKey == SK_RECOVERED_ERROR) ||
|
4679 |
|
|
(SenseKey == SK_HARDWARE_ERROR) ||
|
4680 |
|
|
(SenseKey == SK_MEDIUM_ERROR)) {
|
4681 |
|
|
len += sprintf(msg1+len, "\n Recovery algorithm Actual_Retry_Count=%02Xh",
|
4682 |
|
|
SD_Actual_Retry_Count(sd));
|
4683 |
|
|
}
|
4684 |
|
|
}
|
4685 |
|
|
}
|
4686 |
|
|
#endif
|
4687 |
|
|
|
4688 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4689 |
|
|
static int dump_cdb(char *foo, unsigned char *cdb)
|
4690 |
|
|
{
|
4691 |
|
|
int i, grpCode, cdbLen;
|
4692 |
|
|
int l = 0;
|
4693 |
|
|
|
4694 |
|
|
grpCode = cdb[0] >> 5;
|
4695 |
|
|
if (grpCode < 1)
|
4696 |
|
|
cdbLen = 6;
|
4697 |
|
|
else if (grpCode < 3)
|
4698 |
|
|
cdbLen = 10;
|
4699 |
|
|
else if (grpCode == 5)
|
4700 |
|
|
cdbLen = 12;
|
4701 |
|
|
else
|
4702 |
|
|
cdbLen = 16;
|
4703 |
|
|
|
4704 |
|
|
for (i=0; i < cdbLen; i++)
|
4705 |
|
|
l += sprintf(foo+l, " %02X", cdb[i]);
|
4706 |
|
|
|
4707 |
|
|
return l;
|
4708 |
|
|
}
|
4709 |
|
|
|
4710 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4711 |
|
|
#if 0
|
4712 |
|
|
static int dump_sd(char *foo, unsigned char *sd)
|
4713 |
|
|
{
|
4714 |
|
|
int snsLen = 8 + SD_Additional_Sense_Length(sd);
|
4715 |
|
|
int l = 0;
|
4716 |
|
|
int i;
|
4717 |
|
|
|
4718 |
|
|
for (i=0; i < MIN(snsLen,18); i++)
|
4719 |
|
|
l += sprintf(foo+l, " %02X", sd[i]);
|
4720 |
|
|
l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
|
4721 |
|
|
|
4722 |
|
|
return l;
|
4723 |
|
|
}
|
4724 |
|
|
#endif
|
4725 |
|
|
|
4726 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4727 |
|
|
/* Do ASC/ASCQ lookup/grindage to English readable string(s) */
|
4728 |
|
|
static const char * ascq_set_strings_4max(
|
4729 |
|
|
u8 ASC, u8 ASCQ,
|
4730 |
|
|
const char **s1, const char **s2, const char **s3, const char **s4)
|
4731 |
|
|
{
|
4732 |
|
|
static const char *asc_04_part1_string = "LOGICAL UNIT ";
|
4733 |
|
|
static const char *asc_04_part2a_string = "NOT READY, ";
|
4734 |
|
|
static const char *asc_04_part2b_string = "IS ";
|
4735 |
|
|
static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */
|
4736 |
|
|
"CAUSE NOT REPORTABLE", /* 04 00 */
|
4737 |
|
|
"IN PROCESS OF BECOMING READY", /* 04 01 */
|
4738 |
|
|
"INITIALIZING CMD. REQUIRED", /* 04 02 */
|
4739 |
|
|
"MANUAL INTERVENTION REQUIRED", /* 04 03 */
|
4740 |
|
|
/* Add " IN PROGRESS" to all the following... */
|
4741 |
|
|
"FORMAT", /* 04 04 */
|
4742 |
|
|
"REBUILD", /* 04 05 */
|
4743 |
|
|
"RECALCULATION", /* 04 06 */
|
4744 |
|
|
"OPERATION", /* 04 07 */
|
4745 |
|
|
"LONG WRITE", /* 04 08 */
|
4746 |
|
|
"SELF-TEST", /* 04 09 */
|
4747 |
|
|
NULL
|
4748 |
|
|
};
|
4749 |
|
|
static char *asc_04_part4_string = " IN PROGRESS";
|
4750 |
|
|
|
4751 |
|
|
static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */
|
4752 |
|
|
"POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */
|
4753 |
|
|
"POWER ON OCCURRED", /* 29 01 */
|
4754 |
|
|
"SCSI BUS RESET OCCURRED", /* 29 02 */
|
4755 |
|
|
"BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */
|
4756 |
|
|
"DEVICE INTERNAL RESET", /* 29 04 */
|
4757 |
|
|
"TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */
|
4758 |
|
|
"TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */
|
4759 |
|
|
NULL
|
4760 |
|
|
};
|
4761 |
|
|
static char *ascq_vendor_uniq = "(Vendor Unique)";
|
4762 |
|
|
static char *ascq_noone = "(no matching ASC/ASCQ description found)";
|
4763 |
|
|
int idx;
|
4764 |
|
|
|
4765 |
|
|
*s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */
|
4766 |
|
|
|
4767 |
|
|
/* CHECKME! Need lock/sem?
|
4768 |
|
|
* Update and examine for isense module presense.
|
4769 |
|
|
*/
|
4770 |
|
|
mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
|
4771 |
|
|
|
4772 |
|
|
if (mptscsih_ASCQ_TablePtr == NULL) {
|
4773 |
|
|
/* 2nd chances... */
|
4774 |
|
|
if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
|
4775 |
|
|
*s1 = asc_04_part1_string;
|
4776 |
|
|
*s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
|
4777 |
|
|
*s3 = asc_04_ascq_NN_part3_strings[ASCQ];
|
4778 |
|
|
/* check for " IN PROGRESS" ones */
|
4779 |
|
|
if (ASCQ >= 0x04)
|
4780 |
|
|
*s4 = asc_04_part4_string;
|
4781 |
|
|
} else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
|
4782 |
|
|
*s1 = asc_29_ascq_NN_strings[ASCQ];
|
4783 |
|
|
/*
|
4784 |
|
|
* Else { leave all *s[1-4] values pointing to the empty "" string }
|
4785 |
|
|
*/
|
4786 |
|
|
return *s1;
|
4787 |
|
|
}
|
4788 |
|
|
|
4789 |
|
|
/*
|
4790 |
|
|
* Need to check ASC here; if it is "special," then
|
4791 |
|
|
* the ASCQ is variable, and indicates failed component number.
|
4792 |
|
|
* We must treat the ASCQ as a "don't care" while searching the
|
4793 |
|
|
* mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
|
4794 |
|
|
* on when we actually need to identify the failed component.
|
4795 |
|
|
*/
|
4796 |
|
|
if (SPECIAL_ASCQ(ASC,ASCQ))
|
4797 |
|
|
ASCQ = 0xFF;
|
4798 |
|
|
|
4799 |
|
|
/* OK, now search mptscsih_ASCQ_Table[] for a matching entry */
|
4800 |
|
|
for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
|
4801 |
|
|
if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) {
|
4802 |
|
|
*s1 = mptscsih_ASCQ_TablePtr[idx].Description;
|
4803 |
|
|
return *s1;
|
4804 |
|
|
}
|
4805 |
|
|
|
4806 |
|
|
if ((ASC >= 0x80) || (ASCQ >= 0x80))
|
4807 |
|
|
*s1 = ascq_vendor_uniq;
|
4808 |
|
|
else
|
4809 |
|
|
*s1 = ascq_noone;
|
4810 |
|
|
|
4811 |
|
|
return *s1;
|
4812 |
|
|
}
|
4813 |
|
|
|
4814 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4815 |
|
|
/*
|
4816 |
|
|
* SCSI Information Report; desired output format...
|
4817 |
|
|
*---
|
4818 |
|
|
SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION)
|
4819 |
|
|
Key=6h (UNIT ATTENTION); FRU=03h
|
4820 |
|
|
ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
|
4821 |
|
|
CDB: 00 00 00 00 00 00 - TestUnitReady
|
4822 |
|
|
*---
|
4823 |
|
|
*/
|
4824 |
|
|
/*
|
4825 |
|
|
* SCSI Error Report; desired output format...
|
4826 |
|
|
*---
|
4827 |
|
|
SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
|
4828 |
|
|
SCSI_Status=02h (CHECK CONDITION)
|
4829 |
|
|
Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
|
4830 |
|
|
SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
|
4831 |
|
|
SenseKey=6h (UNIT ATTENTION); FRU=03h
|
4832 |
|
|
ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
|
4833 |
|
|
*---
|
4834 |
|
|
*/
|
4835 |
|
|
|
4836 |
|
|
int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
|
4837 |
|
|
{
|
4838 |
|
|
char foo[512];
|
4839 |
|
|
char buf2[32];
|
4840 |
|
|
char *statstr;
|
4841 |
|
|
const char *opstr;
|
4842 |
|
|
int sk = SD_Sense_Key(ioop->sensePtr);
|
4843 |
|
|
const char *skstr = SenseKeyString[sk];
|
4844 |
|
|
unsigned char asc = SD_ASC(ioop->sensePtr);
|
4845 |
|
|
unsigned char ascq = SD_ASCQ(ioop->sensePtr);
|
4846 |
|
|
int l;
|
4847 |
|
|
|
4848 |
|
|
/* Change the error logging to only report errors on
|
4849 |
|
|
* read and write commands. Ignore errors on other commands.
|
4850 |
|
|
* Should this be configurable via proc?
|
4851 |
|
|
*/
|
4852 |
|
|
switch (ioop->cdbPtr[0]) {
|
4853 |
|
|
case READ_6:
|
4854 |
|
|
case WRITE_6:
|
4855 |
|
|
case READ_10:
|
4856 |
|
|
case WRITE_10:
|
4857 |
|
|
case READ_12:
|
4858 |
|
|
case WRITE_12:
|
4859 |
|
|
break;
|
4860 |
|
|
default:
|
4861 |
|
|
return 0;
|
4862 |
|
|
}
|
4863 |
|
|
|
4864 |
|
|
/*
|
4865 |
|
|
* More quiet mode.
|
4866 |
|
|
* Filter out common, repetitive, warning-type errors... like:
|
4867 |
|
|
* POWER ON (06,29/00 or 06,29/01),
|
4868 |
|
|
* SPINNING UP (02,04/01),
|
4869 |
|
|
* LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
|
4870 |
|
|
*/
|
4871 |
|
|
if (sk == SK_NO_SENSE) {
|
4872 |
|
|
return 0;
|
4873 |
|
|
}
|
4874 |
|
|
|
4875 |
|
|
if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01))
|
4876 |
|
|
|| (sk==SK_NOT_READY && asc==0x04 && (ascq==0x01 || ascq==0x02))
|
4877 |
|
|
|| (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
|
4878 |
|
|
)
|
4879 |
|
|
{
|
4880 |
|
|
/* Do nothing! */
|
4881 |
|
|
return 0;
|
4882 |
|
|
}
|
4883 |
|
|
|
4884 |
|
|
/* Prevent the system from continually writing to the log
|
4885 |
|
|
* if a medium is not found: 02 3A 00
|
4886 |
|
|
* Changer issues: TUR, Read Capacity, Table of Contents continually
|
4887 |
|
|
*/
|
4888 |
|
|
if (sk==SK_NOT_READY && asc==0x3A) {
|
4889 |
|
|
if (ioop->cdbPtr == NULL) {
|
4890 |
|
|
return 0;
|
4891 |
|
|
} else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) ||
|
4892 |
|
|
(ioop->cdbPtr[0] == CMD_ReadCapacity) ||
|
4893 |
|
|
(ioop->cdbPtr[0] == 0x43)) {
|
4894 |
|
|
return 0;
|
4895 |
|
|
}
|
4896 |
|
|
}
|
4897 |
|
|
if (sk==SK_UNIT_ATTENTION) {
|
4898 |
|
|
if (ioop->cdbPtr == NULL)
|
4899 |
|
|
return 0;
|
4900 |
|
|
else if (ioop->cdbPtr[0] == CMD_TestUnitReady)
|
4901 |
|
|
return 0;
|
4902 |
|
|
}
|
4903 |
|
|
|
4904 |
|
|
/*
|
4905 |
|
|
* Protect ourselves...
|
4906 |
|
|
*/
|
4907 |
|
|
if (ioop->cdbPtr == NULL)
|
4908 |
|
|
ioop->cdbPtr = dummyCDB;
|
4909 |
|
|
if (ioop->sensePtr == NULL)
|
4910 |
|
|
ioop->sensePtr = dummySenseData;
|
4911 |
|
|
if (ioop->inqPtr == NULL)
|
4912 |
|
|
ioop->inqPtr = dummyInqData;
|
4913 |
|
|
if (ioop->dataPtr == NULL)
|
4914 |
|
|
ioop->dataPtr = dummyScsiData;
|
4915 |
|
|
|
4916 |
|
|
statstr = NULL;
|
4917 |
|
|
if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
|
4918 |
|
|
((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
|
4919 |
|
|
(void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
|
4920 |
|
|
statstr = buf2;
|
4921 |
|
|
}
|
4922 |
|
|
|
4923 |
|
|
opstr = NULL;
|
4924 |
|
|
if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
|
4925 |
|
|
opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
|
4926 |
|
|
else if (mpt_ScsiOpcodesPtr)
|
4927 |
|
|
opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
|
4928 |
|
|
|
4929 |
|
|
l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n",
|
4930 |
|
|
ioop->DevIDStr,
|
4931 |
|
|
ioop->SCSIStatus,
|
4932 |
|
|
statstr);
|
4933 |
|
|
l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh",
|
4934 |
|
|
sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
|
4935 |
|
|
{
|
4936 |
|
|
const char *x1, *x2, *x3, *x4;
|
4937 |
|
|
x1 = x2 = x3 = x4 = "";
|
4938 |
|
|
x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
|
4939 |
|
|
if (x1 != NULL) {
|
4940 |
|
|
if (x1[0] != '(')
|
4941 |
|
|
l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
|
4942 |
|
|
else
|
4943 |
|
|
l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
|
4944 |
|
|
}
|
4945 |
|
|
}
|
4946 |
|
|
l += sprintf(foo+l, "\n CDB:");
|
4947 |
|
|
l += dump_cdb(foo+l, ioop->cdbPtr);
|
4948 |
|
|
if (opstr)
|
4949 |
|
|
l += sprintf(foo+l, " - \"%s\"", opstr);
|
4950 |
|
|
l += sprintf(foo+l, "\n");
|
4951 |
|
|
|
4952 |
|
|
PrintF(("%s\n", foo));
|
4953 |
|
|
|
4954 |
|
|
return l;
|
4955 |
|
|
}
|
4956 |
|
|
|
4957 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4958 |
|
|
|
4959 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
4960 |
|
|
/*
|
4961 |
|
|
* mptscsih_initTarget - Target, LUN alloc/free functionality.
|
4962 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure
|
4963 |
|
|
* @bus_id: Bus number (?)
|
4964 |
|
|
* @target_id: SCSI target id
|
4965 |
|
|
* @lun: SCSI LUN id
|
4966 |
|
|
* @data: Pointer to data
|
4967 |
|
|
* @dlen: Number of INQUIRY bytes
|
4968 |
|
|
*
|
4969 |
|
|
* NOTE: It's only SAFE to call this routine if data points to
|
4970 |
|
|
* sane & valid STANDARD INQUIRY data!
|
4971 |
|
|
*
|
4972 |
|
|
* Allocate and initialize memory for this target.
|
4973 |
|
|
* Save inquiry data.
|
4974 |
|
|
*
|
4975 |
|
|
*/
|
4976 |
|
|
static void
|
4977 |
|
|
mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
|
4978 |
|
|
{
|
4979 |
|
|
int indexed_lun, lun_index;
|
4980 |
|
|
VirtDevice *vdev;
|
4981 |
|
|
|
4982 |
|
|
dprintk((MYIOC_s_INFO_FMT "initTarget (%d,%d,%d) called, hd=%p\n",
|
4983 |
|
|
hd->ioc->name, bus_id, target_id, lun, hd));
|
4984 |
|
|
|
4985 |
|
|
if ((vdev = hd->Targets[target_id]) == NULL) {
|
4986 |
|
|
if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
|
4987 |
|
|
printk(MYIOC_s_ERR_FMT "initTarget kmalloc(%d) FAILED!\n",
|
4988 |
|
|
hd->ioc->name, (int)sizeof(VirtDevice));
|
4989 |
|
|
return;
|
4990 |
|
|
} else {
|
4991 |
|
|
memset(vdev, 0, sizeof(VirtDevice));
|
4992 |
|
|
rwlock_init(&vdev->VdevLock);
|
4993 |
|
|
Q_INIT(&vdev->WaitQ, void);
|
4994 |
|
|
Q_INIT(&vdev->SentQ, void);
|
4995 |
|
|
Q_INIT(&vdev->DoneQ, void);
|
4996 |
|
|
vdev->tflags = 0;
|
4997 |
|
|
vdev->ioc_id = hd->ioc->id;
|
4998 |
|
|
vdev->target_id = target_id;
|
4999 |
|
|
vdev->bus_id = bus_id;
|
5000 |
|
|
|
5001 |
|
|
hd->Targets[target_id] = vdev;
|
5002 |
|
|
dprintk((KERN_INFO " *NEW* Target structure (id %d) @ %p\n",
|
5003 |
|
|
target_id, vdev));
|
5004 |
|
|
}
|
5005 |
|
|
}
|
5006 |
|
|
|
5007 |
|
|
vdev->raidVolume = 0;
|
5008 |
|
|
if (hd->is_spi) {
|
5009 |
|
|
if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
|
5010 |
|
|
vdev->raidVolume = 1;
|
5011 |
|
|
ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
|
5012 |
|
|
}
|
5013 |
|
|
}
|
5014 |
|
|
|
5015 |
|
|
if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
|
5016 |
|
|
/* Copy the inquiry data - if we haven't yet.
|
5017 |
|
|
*/
|
5018 |
|
|
|
5019 |
|
|
memcpy (vdev->inq_data, data, 8);
|
5020 |
|
|
|
5021 |
|
|
if ( (data[0] == SCSI_TYPE_PROC) &&
|
5022 |
|
|
!(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
|
5023 |
|
|
if ( dlen > 49 ) {
|
5024 |
|
|
vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
|
5025 |
|
|
if ( data[44] == 'S' &&
|
5026 |
|
|
data[45] == 'A' &&
|
5027 |
|
|
data[46] == 'F' &&
|
5028 |
|
|
data[47] == '-' &&
|
5029 |
|
|
data[48] == 'T' &&
|
5030 |
|
|
data[49] == 'E' ) {
|
5031 |
|
|
vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
|
5032 |
|
|
mptscsih_writeIOCPage4(hd, target_id, bus_id);
|
5033 |
|
|
}
|
5034 |
|
|
} else {
|
5035 |
|
|
/* Treat all Processors as SAF-TE if
|
5036 |
|
|
* command line option is set */
|
5037 |
|
|
if ( hd->ioc->spi_data.Saf_Te ) {
|
5038 |
|
|
vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
|
5039 |
|
|
mptscsih_writeIOCPage4(hd, target_id, bus_id);
|
5040 |
|
|
}
|
5041 |
|
|
}
|
5042 |
|
|
} else
|
5043 |
|
|
vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
|
5044 |
|
|
|
5045 |
|
|
if ((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) {
|
5046 |
|
|
/* Update the target capabilities
|
5047 |
|
|
*/
|
5048 |
|
|
if (dlen > 56) {
|
5049 |
|
|
mptscsih_setTargetNegoParms(hd, vdev, data[56]);
|
5050 |
|
|
vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
|
5051 |
|
|
} else
|
5052 |
|
|
mptscsih_setTargetNegoParms(hd, vdev, 0);
|
5053 |
|
|
|
5054 |
|
|
/* If LUN 0, tape and have not done DV, set the DV flag.
|
5055 |
|
|
*/
|
5056 |
|
|
if (hd->is_spi && (lun == 0) && ((data[0] & 0x1F) == 0x01)) {
|
5057 |
|
|
ScsiCfgData *pSpi = &hd->ioc->spi_data;
|
5058 |
|
|
if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
|
5059 |
|
|
pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
|
5060 |
|
|
}
|
5061 |
|
|
}
|
5062 |
|
|
}
|
5063 |
|
|
|
5064 |
|
|
/* Is LUN supported? If so, upper 3 bits will be 0
|
5065 |
|
|
* in first byte of inquiry data.
|
5066 |
|
|
*/
|
5067 |
|
|
if ((*data & 0xe0) == 0) {
|
5068 |
|
|
lun_index = (lun >> 5); /* 32 luns per lun_index */
|
5069 |
|
|
indexed_lun = (lun % 32);
|
5070 |
|
|
vdev->luns[lun_index] |= (1 << indexed_lun);
|
5071 |
|
|
}
|
5072 |
|
|
|
5073 |
|
|
dprintk((KERN_INFO " target = %p\n", vdev));
|
5074 |
|
|
return;
|
5075 |
|
|
}
|
5076 |
|
|
|
5077 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5078 |
|
|
/*
|
5079 |
|
|
* Update the target negotiation parameters based on the
|
5080 |
|
|
* the Inquiry data, adapter capabilities, and NVRAM settings.
|
5081 |
|
|
*
|
5082 |
|
|
*/
|
5083 |
|
|
void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
|
5084 |
|
|
{
|
5085 |
|
|
ScsiCfgData *pspi_data = &hd->ioc->spi_data;
|
5086 |
|
|
int id = (int) target->target_id;
|
5087 |
|
|
int nvram;
|
5088 |
|
|
char canQ = 0;
|
5089 |
|
|
VirtDevice *vdev;
|
5090 |
|
|
int ii;
|
5091 |
|
|
u8 width = MPT_NARROW;
|
5092 |
|
|
u8 factor = MPT_ASYNC;
|
5093 |
|
|
u8 offset = 0;
|
5094 |
|
|
u8 version, nfactor;
|
5095 |
|
|
u8 noQas = 1;
|
5096 |
|
|
|
5097 |
|
|
if (!hd->is_spi) {
|
5098 |
|
|
if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
|
5099 |
|
|
if (target->inq_data[7] & 0x02)
|
5100 |
|
|
target->tflags |= MPT_TARGET_FLAGS_Q_YES;
|
5101 |
|
|
}
|
5102 |
|
|
return;
|
5103 |
|
|
}
|
5104 |
|
|
|
5105 |
|
|
target->negoFlags = pspi_data->noQas;
|
5106 |
|
|
|
5107 |
|
|
/* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
|
5108 |
|
|
* support. If available, default QAS to off and allow enabling.
|
5109 |
|
|
* If not available, default QAS to on, turn off for non-disks.
|
5110 |
|
|
*/
|
5111 |
|
|
|
5112 |
|
|
/* Set flags based on Inquiry data
|
5113 |
|
|
*/
|
5114 |
|
|
if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
|
5115 |
|
|
version = target->inq_data[2] & 0x07;
|
5116 |
|
|
if (version < 2) {
|
5117 |
|
|
width = 0;
|
5118 |
|
|
factor = MPT_ULTRA2;
|
5119 |
|
|
offset = pspi_data->maxSyncOffset;
|
5120 |
|
|
} else {
|
5121 |
|
|
if (target->inq_data[7] & 0x20) {
|
5122 |
|
|
width = 1;
|
5123 |
|
|
}
|
5124 |
|
|
|
5125 |
|
|
if (target->inq_data[7] & 0x10) {
|
5126 |
|
|
/* bits 2 & 3 show DT support
|
5127 |
|
|
*/
|
5128 |
|
|
if ((byte56 & 0x04) == 0)
|
5129 |
|
|
factor = MPT_ULTRA2;
|
5130 |
|
|
else if ((byte56 & 0x03) == 0)
|
5131 |
|
|
factor = MPT_ULTRA160;
|
5132 |
|
|
else
|
5133 |
|
|
factor = MPT_ULTRA320;
|
5134 |
|
|
offset = pspi_data->maxSyncOffset;
|
5135 |
|
|
|
5136 |
|
|
/* If RAID, never disable QAS
|
5137 |
|
|
* else if non RAID, do not disable
|
5138 |
|
|
* QAS if bit 1 is set
|
5139 |
|
|
* bit 1 QAS support, non-raid only
|
5140 |
|
|
* bit 0 IU support
|
5141 |
|
|
*/
|
5142 |
|
|
if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
|
5143 |
|
|
noQas = 0;
|
5144 |
|
|
} else {
|
5145 |
|
|
factor = MPT_ASYNC;
|
5146 |
|
|
offset = 0;
|
5147 |
|
|
}
|
5148 |
|
|
}
|
5149 |
|
|
|
5150 |
|
|
if (target->inq_data[7] & 0x02) {
|
5151 |
|
|
canQ = 1;
|
5152 |
|
|
}
|
5153 |
|
|
|
5154 |
|
|
/* Update tflags based on NVRAM settings. (SCSI only)
|
5155 |
|
|
*/
|
5156 |
|
|
if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
5157 |
|
|
nvram = pspi_data->nvram[id];
|
5158 |
|
|
nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
|
5159 |
|
|
|
5160 |
|
|
if (width)
|
5161 |
|
|
width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
|
5162 |
|
|
|
5163 |
|
|
if (offset > 0) {
|
5164 |
|
|
/* Ensure factor is set to the
|
5165 |
|
|
* maximum of: adapter, nvram, inquiry
|
5166 |
|
|
*/
|
5167 |
|
|
if (nfactor) {
|
5168 |
|
|
if (nfactor < pspi_data->minSyncFactor )
|
5169 |
|
|
nfactor = pspi_data->minSyncFactor;
|
5170 |
|
|
|
5171 |
|
|
factor = MAX (factor, nfactor);
|
5172 |
|
|
if (factor == MPT_ASYNC)
|
5173 |
|
|
offset = 0;
|
5174 |
|
|
} else {
|
5175 |
|
|
offset = 0;
|
5176 |
|
|
factor = MPT_ASYNC;
|
5177 |
|
|
}
|
5178 |
|
|
} else {
|
5179 |
|
|
factor = MPT_ASYNC;
|
5180 |
|
|
}
|
5181 |
|
|
}
|
5182 |
|
|
|
5183 |
|
|
/* Make sure data is consistent
|
5184 |
|
|
*/
|
5185 |
|
|
if ((!width) && (factor < MPT_ULTRA2)) {
|
5186 |
|
|
factor = MPT_ULTRA2;
|
5187 |
|
|
}
|
5188 |
|
|
|
5189 |
|
|
/* Save the data to the target structure.
|
5190 |
|
|
*/
|
5191 |
|
|
target->minSyncFactor = factor;
|
5192 |
|
|
target->maxOffset = offset;
|
5193 |
|
|
target->maxWidth = width;
|
5194 |
|
|
if (canQ) {
|
5195 |
|
|
target->tflags |= MPT_TARGET_FLAGS_Q_YES;
|
5196 |
|
|
}
|
5197 |
|
|
|
5198 |
|
|
target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
|
5199 |
|
|
|
5200 |
|
|
/* Disable unused features.
|
5201 |
|
|
*/
|
5202 |
|
|
if (!width)
|
5203 |
|
|
target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
|
5204 |
|
|
|
5205 |
|
|
if (!offset)
|
5206 |
|
|
target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
|
5207 |
|
|
|
5208 |
|
|
/* GEM, processor WORKAROUND
|
5209 |
|
|
*/
|
5210 |
|
|
if (((target->inq_data[0] & 0x1F) == 0x03) || ((target->inq_data[0] & 0x1F) > 0x08)) {
|
5211 |
|
|
target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
|
5212 |
|
|
pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
|
5213 |
|
|
} else {
|
5214 |
|
|
if (noQas && (pspi_data->noQas == 0)) {
|
5215 |
|
|
pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
|
5216 |
|
|
target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
|
5217 |
|
|
|
5218 |
|
|
/* Disable QAS in a mixed configuration case
|
5219 |
|
|
*/
|
5220 |
|
|
|
5221 |
|
|
// ddvtprintk((KERN_INFO "Disabling QAS!\n"));
|
5222 |
|
|
for (ii = 0; ii < id; ii++) {
|
5223 |
|
|
if ( (vdev = hd->Targets[ii]) ) {
|
5224 |
|
|
vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
|
5225 |
|
|
}
|
5226 |
|
|
}
|
5227 |
|
|
}
|
5228 |
|
|
}
|
5229 |
|
|
}
|
5230 |
|
|
|
5231 |
|
|
return;
|
5232 |
|
|
}
|
5233 |
|
|
|
5234 |
|
|
/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
|
5235 |
|
|
* Else set the NEED_DV flag after Read Capacity Issued (disks)
|
5236 |
|
|
* or Mode Sense (cdroms).
|
5237 |
|
|
*
|
5238 |
|
|
* Tapes, initTarget will set this flag on completion of Inquiry command.
|
5239 |
|
|
* Called only if DV_NOT_DONE flag is set
|
5240 |
|
|
*/
|
5241 |
|
|
static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
|
5242 |
|
|
{
|
5243 |
|
|
u8 cmd;
|
5244 |
|
|
|
5245 |
|
|
if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
|
5246 |
|
|
return;
|
5247 |
|
|
|
5248 |
|
|
cmd = pReq->CDB[0];
|
5249 |
|
|
|
5250 |
|
|
if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
|
5251 |
|
|
ScsiCfgData *pSpi = &hd->ioc->spi_data;
|
5252 |
|
|
if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
|
5253 |
|
|
/* Set NEED_DV for all hidden disks
|
5254 |
|
|
*/
|
5255 |
|
|
Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk;
|
5256 |
|
|
int numPDisk = pSpi->pIocPg3->NumPhysDisks;
|
5257 |
|
|
|
5258 |
|
|
while (numPDisk) {
|
5259 |
|
|
pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
|
5260 |
|
|
ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
|
5261 |
|
|
pPDisk++;
|
5262 |
|
|
numPDisk--;
|
5263 |
|
|
}
|
5264 |
|
|
}
|
5265 |
|
|
pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
|
5266 |
|
|
ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
|
5267 |
|
|
}
|
5268 |
|
|
}
|
5269 |
|
|
|
5270 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5271 |
|
|
/*
|
5272 |
|
|
* If no Target, bus reset on 1st I/O. Set the flag to
|
5273 |
|
|
* prevent any future negotiations to this device.
|
5274 |
|
|
*/
|
5275 |
|
|
static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
|
5276 |
|
|
{
|
5277 |
|
|
|
5278 |
|
|
if ((hd->Targets) && (hd->Targets[target_id] == NULL))
|
5279 |
|
|
hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
|
5280 |
|
|
|
5281 |
|
|
return;
|
5282 |
|
|
}
|
5283 |
|
|
|
5284 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5285 |
|
|
/*
|
5286 |
|
|
* SCSI Config Page functionality ...
|
5287 |
|
|
*/
|
5288 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5289 |
|
|
/* mptscsih_setDevicePage1Flags - add Requested and Configuration fields flags
|
5290 |
|
|
* based on width, factor and offset parameters.
|
5291 |
|
|
* @width: bus width
|
5292 |
|
|
* @factor: sync factor
|
5293 |
|
|
* @offset: sync offset
|
5294 |
|
|
* @requestedPtr: pointer to requested values (updated)
|
5295 |
|
|
* @configurationPtr: pointer to configuration values (updated)
|
5296 |
|
|
* @flags: flags to block WDTR or SDTR negotiation
|
5297 |
|
|
*
|
5298 |
|
|
* Return: None.
|
5299 |
|
|
*
|
5300 |
|
|
* Remark: Called by writeSDP1 and _dv_params
|
5301 |
|
|
*/
|
5302 |
|
|
static void
|
5303 |
|
|
mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
|
5304 |
|
|
{
|
5305 |
|
|
u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
|
5306 |
|
|
u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
|
5307 |
|
|
|
5308 |
|
|
*configurationPtr = 0;
|
5309 |
|
|
*requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
|
5310 |
|
|
*requestedPtr |= (offset << 16) | (factor << 8);
|
5311 |
|
|
|
5312 |
|
|
if (width && offset && !nowide && !nosync) {
|
5313 |
|
|
if (factor < MPT_ULTRA160) {
|
5314 |
|
|
*requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
|
5315 |
|
|
if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
|
5316 |
|
|
*requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
|
5317 |
|
|
} else if (factor < MPT_ULTRA2) {
|
5318 |
|
|
*requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
|
5319 |
|
|
}
|
5320 |
|
|
}
|
5321 |
|
|
|
5322 |
|
|
if (nowide)
|
5323 |
|
|
*configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
|
5324 |
|
|
|
5325 |
|
|
if (nosync)
|
5326 |
|
|
*configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
|
5327 |
|
|
|
5328 |
|
|
return;
|
5329 |
|
|
}
|
5330 |
|
|
|
5331 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5332 |
|
|
/* mptscsih_writeSDP1 - write SCSI Device Page 1
|
5333 |
|
|
* @hd: Pointer to a SCSI Host Strucutre
|
5334 |
|
|
* @portnum: IOC port number
|
5335 |
|
|
* @target_id: writeSDP1 for single ID
|
5336 |
|
|
* @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
|
5337 |
|
|
*
|
5338 |
|
|
* Return: -EFAULT if read of config page header fails
|
5339 |
|
|
* or 0 if success.
|
5340 |
|
|
*
|
5341 |
|
|
* Remark: If a target has been found, the settings from the
|
5342 |
|
|
* target structure are used, else the device is set
|
5343 |
|
|
* to async/narrow.
|
5344 |
|
|
*
|
5345 |
|
|
* Remark: Called during init and after a FW reload.
|
5346 |
|
|
* Remark: We do not wait for a return, write pages sequentially.
|
5347 |
|
|
*/
|
5348 |
|
|
static int
|
5349 |
|
|
mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
|
5350 |
|
|
{
|
5351 |
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
5352 |
|
|
Config_t *pReq;
|
5353 |
|
|
SCSIDevicePage1_t *pData;
|
5354 |
|
|
VirtDevice *pTarget;
|
5355 |
|
|
MPT_FRAME_HDR *mf;
|
5356 |
|
|
dma_addr_t dataDma;
|
5357 |
|
|
u16 req_idx;
|
5358 |
|
|
u32 frameOffset;
|
5359 |
|
|
u32 requested, configuration, flagsLength;
|
5360 |
|
|
int ii, nvram;
|
5361 |
|
|
int id = 0, maxid = 0;
|
5362 |
|
|
u8 width;
|
5363 |
|
|
u8 factor;
|
5364 |
|
|
u8 offset;
|
5365 |
|
|
u8 bus = 0;
|
5366 |
|
|
u8 negoFlags;
|
5367 |
|
|
u8 maxwidth, maxoffset, maxfactor;
|
5368 |
|
|
|
5369 |
|
|
if (ioc->spi_data.sdp1length == 0)
|
5370 |
|
|
return 0;
|
5371 |
|
|
|
5372 |
|
|
if (flags & MPT_SCSICFG_ALL_IDS) {
|
5373 |
|
|
id = 0;
|
5374 |
|
|
maxid = ioc->sh->max_id - 1;
|
5375 |
|
|
} else if (ioc->sh) {
|
5376 |
|
|
id = target_id;
|
5377 |
|
|
maxid = MIN(id, ioc->sh->max_id - 1);
|
5378 |
|
|
}
|
5379 |
|
|
|
5380 |
|
|
for (; id <= maxid; id++) {
|
5381 |
|
|
|
5382 |
|
|
if (id == ioc->pfacts[portnum].PortSCSIID)
|
5383 |
|
|
continue;
|
5384 |
|
|
|
5385 |
|
|
/* Use NVRAM to get adapter and target maximums
|
5386 |
|
|
* Data over-riden by target structure information, if present
|
5387 |
|
|
*/
|
5388 |
|
|
maxwidth = ioc->spi_data.maxBusWidth;
|
5389 |
|
|
maxoffset = ioc->spi_data.maxSyncOffset;
|
5390 |
|
|
maxfactor = ioc->spi_data.minSyncFactor;
|
5391 |
|
|
if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
5392 |
|
|
nvram = ioc->spi_data.nvram[id];
|
5393 |
|
|
|
5394 |
|
|
if (maxwidth)
|
5395 |
|
|
maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
|
5396 |
|
|
|
5397 |
|
|
if (maxoffset > 0) {
|
5398 |
|
|
maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
|
5399 |
|
|
if (maxfactor == 0) {
|
5400 |
|
|
/* Key for async */
|
5401 |
|
|
maxfactor = MPT_ASYNC;
|
5402 |
|
|
maxoffset = 0;
|
5403 |
|
|
} else if (maxfactor < ioc->spi_data.minSyncFactor) {
|
5404 |
|
|
maxfactor = ioc->spi_data.minSyncFactor;
|
5405 |
|
|
}
|
5406 |
|
|
} else
|
5407 |
|
|
maxfactor = MPT_ASYNC;
|
5408 |
|
|
}
|
5409 |
|
|
|
5410 |
|
|
/* Set the negotiation flags.
|
5411 |
|
|
*/
|
5412 |
|
|
negoFlags = ioc->spi_data.noQas;
|
5413 |
|
|
if (!maxwidth)
|
5414 |
|
|
negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
|
5415 |
|
|
|
5416 |
|
|
if (!maxoffset)
|
5417 |
|
|
negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
|
5418 |
|
|
|
5419 |
|
|
if (flags & MPT_SCSICFG_USE_NVRAM) {
|
5420 |
|
|
width = maxwidth;
|
5421 |
|
|
factor = maxfactor;
|
5422 |
|
|
offset = maxoffset;
|
5423 |
|
|
} else {
|
5424 |
|
|
width = 0;
|
5425 |
|
|
factor = MPT_ASYNC;
|
5426 |
|
|
offset = 0;
|
5427 |
|
|
//negoFlags = 0;
|
5428 |
|
|
//negoFlags = MPT_TARGET_NO_NEGO_SYNC;
|
5429 |
|
|
}
|
5430 |
|
|
|
5431 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
5432 |
|
|
/* Force to async and narrow if DV has not been executed
|
5433 |
|
|
* for this ID
|
5434 |
|
|
*/
|
5435 |
|
|
if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
|
5436 |
|
|
width = 0;
|
5437 |
|
|
factor = MPT_ASYNC;
|
5438 |
|
|
offset = 0;
|
5439 |
|
|
}
|
5440 |
|
|
#endif
|
5441 |
|
|
|
5442 |
|
|
/* If id is not a raid volume, get the updated
|
5443 |
|
|
* transmission settings from the target structure.
|
5444 |
|
|
*/
|
5445 |
|
|
if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
|
5446 |
|
|
width = pTarget->maxWidth;
|
5447 |
|
|
factor = pTarget->minSyncFactor;
|
5448 |
|
|
offset = pTarget->maxOffset;
|
5449 |
|
|
negoFlags = pTarget->negoFlags;
|
5450 |
|
|
}
|
5451 |
|
|
|
5452 |
|
|
if (flags & MPT_SCSICFG_BLK_NEGO)
|
5453 |
|
|
negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
|
5454 |
|
|
|
5455 |
|
|
mptscsih_setDevicePage1Flags(width, factor, offset,
|
5456 |
|
|
&requested, &configuration, negoFlags);
|
5457 |
|
|
|
5458 |
|
|
/* Get a MF for this command.
|
5459 |
|
|
*/
|
5460 |
|
|
if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
|
5461 |
|
|
dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
|
5462 |
|
|
ioc->name));
|
5463 |
|
|
return -EAGAIN;
|
5464 |
|
|
}
|
5465 |
|
|
|
5466 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
|
5467 |
|
|
hd->ioc->name, mf, id, requested, configuration));
|
5468 |
|
|
|
5469 |
|
|
|
5470 |
|
|
/* Set the request and the data pointers.
|
5471 |
|
|
* Request takes: 36 bytes (32 bit SGE)
|
5472 |
|
|
* SCSI Device Page 1 requires 16 bytes
|
5473 |
|
|
* 40 + 16 <= size of SCSI IO Request = 56 bytes
|
5474 |
|
|
* and MF size >= 64 bytes.
|
5475 |
|
|
* Place data at end of MF.
|
5476 |
|
|
*/
|
5477 |
|
|
pReq = (Config_t *)mf;
|
5478 |
|
|
|
5479 |
|
|
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
5480 |
|
|
frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
|
5481 |
|
|
|
5482 |
|
|
pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
|
5483 |
|
|
dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
|
5484 |
|
|
|
5485 |
|
|
/* Complete the request frame (same for all requests).
|
5486 |
|
|
*/
|
5487 |
|
|
pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
5488 |
|
|
pReq->Reserved = 0;
|
5489 |
|
|
pReq->ChainOffset = 0;
|
5490 |
|
|
pReq->Function = MPI_FUNCTION_CONFIG;
|
5491 |
|
|
pReq->Reserved1[0] = 0;
|
5492 |
|
|
pReq->Reserved1[1] = 0;
|
5493 |
|
|
pReq->Reserved1[2] = 0;
|
5494 |
|
|
pReq->MsgFlags = 0;
|
5495 |
|
|
for (ii=0; ii < 8; ii++) {
|
5496 |
|
|
pReq->Reserved2[ii] = 0;
|
5497 |
|
|
}
|
5498 |
|
|
pReq->Header.PageVersion = ioc->spi_data.sdp1version;
|
5499 |
|
|
pReq->Header.PageLength = ioc->spi_data.sdp1length;
|
5500 |
|
|
pReq->Header.PageNumber = 1;
|
5501 |
|
|
pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
|
5502 |
|
|
pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
|
5503 |
|
|
|
5504 |
|
|
/* Add a SGE to the config request.
|
5505 |
|
|
*/
|
5506 |
|
|
flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
|
5507 |
|
|
|
5508 |
|
|
mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
|
5509 |
|
|
|
5510 |
|
|
/* Set up the common data portion
|
5511 |
|
|
*/
|
5512 |
|
|
pData->Header.PageVersion = pReq->Header.PageVersion;
|
5513 |
|
|
pData->Header.PageLength = pReq->Header.PageLength;
|
5514 |
|
|
pData->Header.PageNumber = pReq->Header.PageNumber;
|
5515 |
|
|
pData->Header.PageType = pReq->Header.PageType;
|
5516 |
|
|
pData->RequestedParameters = cpu_to_le32(requested);
|
5517 |
|
|
pData->Reserved = 0;
|
5518 |
|
|
pData->Configuration = cpu_to_le32(configuration);
|
5519 |
|
|
|
5520 |
|
|
dprintk((MYIOC_s_INFO_FMT
|
5521 |
|
|
"write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
|
5522 |
|
|
ioc->name, id, (id | (bus<<8)),
|
5523 |
|
|
requested, configuration));
|
5524 |
|
|
|
5525 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
|
5526 |
|
|
}
|
5527 |
|
|
|
5528 |
|
|
return 0;
|
5529 |
|
|
}
|
5530 |
|
|
|
5531 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5532 |
|
|
/* mptscsih_writeIOCPage4 - write IOC Page 4
|
5533 |
|
|
* @hd: Pointer to a SCSI Host Structure
|
5534 |
|
|
* @target_id: write IOC Page4 for this ID & Bus
|
5535 |
|
|
*
|
5536 |
|
|
* Return: -EAGAIN if unable to obtain a Message Frame
|
5537 |
|
|
* or 0 if success.
|
5538 |
|
|
*
|
5539 |
|
|
* Remark: We do not wait for a return, write pages sequentially.
|
5540 |
|
|
*/
|
5541 |
|
|
static int
|
5542 |
|
|
mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
|
5543 |
|
|
{
|
5544 |
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
5545 |
|
|
Config_t *pReq;
|
5546 |
|
|
IOCPage4_t *IOCPage4Ptr;
|
5547 |
|
|
MPT_FRAME_HDR *mf;
|
5548 |
|
|
dma_addr_t dataDma;
|
5549 |
|
|
u16 req_idx;
|
5550 |
|
|
u32 frameOffset;
|
5551 |
|
|
u32 flagsLength;
|
5552 |
|
|
int ii;
|
5553 |
|
|
|
5554 |
|
|
/* Get a MF for this command.
|
5555 |
|
|
*/
|
5556 |
|
|
if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
|
5557 |
|
|
dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
|
5558 |
|
|
ioc->name));
|
5559 |
|
|
return -EAGAIN;
|
5560 |
|
|
}
|
5561 |
|
|
|
5562 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n",
|
5563 |
|
|
ioc->name, mf, target_id));
|
5564 |
|
|
|
5565 |
|
|
/* Set the request and the data pointers.
|
5566 |
|
|
* Place data at end of MF.
|
5567 |
|
|
*/
|
5568 |
|
|
pReq = (Config_t *)mf;
|
5569 |
|
|
|
5570 |
|
|
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
5571 |
|
|
frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
|
5572 |
|
|
|
5573 |
|
|
/* Complete the request frame (same for all requests).
|
5574 |
|
|
*/
|
5575 |
|
|
pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
5576 |
|
|
pReq->Reserved = 0;
|
5577 |
|
|
pReq->ChainOffset = 0;
|
5578 |
|
|
pReq->Function = MPI_FUNCTION_CONFIG;
|
5579 |
|
|
pReq->Reserved1[0] = 0;
|
5580 |
|
|
pReq->Reserved1[1] = 0;
|
5581 |
|
|
pReq->Reserved1[2] = 0;
|
5582 |
|
|
pReq->MsgFlags = 0;
|
5583 |
|
|
for (ii=0; ii < 8; ii++) {
|
5584 |
|
|
pReq->Reserved2[ii] = 0;
|
5585 |
|
|
}
|
5586 |
|
|
|
5587 |
|
|
IOCPage4Ptr = ioc->spi_data.pIocPg4;
|
5588 |
|
|
dataDma = ioc->spi_data.IocPg4_dma;
|
5589 |
|
|
ii = IOCPage4Ptr->ActiveSEP++;
|
5590 |
|
|
IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
|
5591 |
|
|
IOCPage4Ptr->SEP[ii].SEPBus = bus;
|
5592 |
|
|
pReq->Header = IOCPage4Ptr->Header;
|
5593 |
|
|
pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
|
5594 |
|
|
|
5595 |
|
|
/* Add a SGE to the config request.
|
5596 |
|
|
*/
|
5597 |
|
|
flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
|
5598 |
|
|
(IOCPage4Ptr->Header.PageLength + ii) * 4;
|
5599 |
|
|
|
5600 |
|
|
mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
|
5601 |
|
|
|
5602 |
|
|
dsprintk((MYIOC_s_INFO_FMT
|
5603 |
|
|
"writeIOCPage4: pgaddr 0x%x\n",
|
5604 |
|
|
ioc->name, (target_id | (bus<<8))));
|
5605 |
|
|
|
5606 |
|
|
mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
|
5607 |
|
|
|
5608 |
|
|
return 0;
|
5609 |
|
|
}
|
5610 |
|
|
|
5611 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5612 |
|
|
/* mptscsih_taskmgmt_timeout - Call back for timeout on a
|
5613 |
|
|
* task management request.
|
5614 |
|
|
* @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
|
5615 |
|
|
*
|
5616 |
|
|
*/
|
5617 |
|
|
static void mptscsih_taskmgmt_timeout(unsigned long data)
|
5618 |
|
|
{
|
5619 |
|
|
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
|
5620 |
|
|
|
5621 |
|
|
dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_taskmgmt_timeout: "
|
5622 |
|
|
"TM request timed out!\n", hd->ioc->name));
|
5623 |
|
|
|
5624 |
|
|
/* Delete the timer that triggered this callback.
|
5625 |
|
|
* Remark: del_timer checks to make sure timer is active
|
5626 |
|
|
* before deleting.
|
5627 |
|
|
*/
|
5628 |
|
|
del_timer(&hd->TMtimer);
|
5629 |
|
|
|
5630 |
|
|
/* Call the reset handler. Already had a TM request
|
5631 |
|
|
* timeout - so issue a diagnostic reset
|
5632 |
|
|
*/
|
5633 |
|
|
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
|
5634 |
|
|
printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
|
5635 |
|
|
}
|
5636 |
|
|
#ifdef MPT_SCSI_USE_NEW_EH
|
5637 |
|
|
else {
|
5638 |
|
|
/* Because we have reset the IOC, no TM requests can be
|
5639 |
|
|
* pending. So let's make sure the tmPending flag is reset.
|
5640 |
|
|
*/
|
5641 |
|
|
nehprintk((KERN_WARNING MYNAM
|
5642 |
|
|
": %s: mptscsih_taskmgmt_timeout\n",
|
5643 |
|
|
hd->ioc->name));
|
5644 |
|
|
hd->tmPending = 0;
|
5645 |
|
|
}
|
5646 |
|
|
#endif
|
5647 |
|
|
|
5648 |
|
|
return;
|
5649 |
|
|
}
|
5650 |
|
|
|
5651 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5652 |
|
|
/*
|
5653 |
|
|
* Bus Scan and Domain Validation functionality ...
|
5654 |
|
|
*/
|
5655 |
|
|
|
5656 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5657 |
|
|
/*
|
5658 |
|
|
* mptscsih_scandv_complete - Scan and DV callback routine registered
|
5659 |
|
|
* to Fustion MPT (base) driver.
|
5660 |
|
|
*
|
5661 |
|
|
* @ioc: Pointer to MPT_ADAPTER structure
|
5662 |
|
|
* @mf: Pointer to original MPT request frame
|
5663 |
|
|
* @mr: Pointer to MPT reply frame (NULL if TurboReply)
|
5664 |
|
|
*
|
5665 |
|
|
* This routine is called from mpt.c::mpt_interrupt() at the completion
|
5666 |
|
|
* of any SCSI IO request.
|
5667 |
|
|
* This routine is registered with the Fusion MPT (base) driver at driver
|
5668 |
|
|
* load/init time via the mpt_register() API call.
|
5669 |
|
|
*
|
5670 |
|
|
* Returns 1 indicating alloc'd request frame ptr should be freed.
|
5671 |
|
|
*
|
5672 |
|
|
* Remark: Sets a completion code and (possibly) saves sense data
|
5673 |
|
|
* in the IOC member localReply structure.
|
5674 |
|
|
* Used ONLY for DV and other internal commands.
|
5675 |
|
|
*/
|
5676 |
|
|
static int
|
5677 |
|
|
mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
5678 |
|
|
{
|
5679 |
|
|
MPT_SCSI_HOST *hd;
|
5680 |
|
|
SCSIIORequest_t *pReq;
|
5681 |
|
|
int completionCode;
|
5682 |
|
|
u16 req_idx;
|
5683 |
|
|
|
5684 |
|
|
if ((mf == NULL) ||
|
5685 |
|
|
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
|
5686 |
|
|
printk(MYIOC_s_ERR_FMT
|
5687 |
|
|
"ScanDvComplete, %s req frame ptr! (=%p)\n",
|
5688 |
|
|
ioc->name, mf?"BAD":"NULL", (void *) mf);
|
5689 |
|
|
goto wakeup;
|
5690 |
|
|
}
|
5691 |
|
|
|
5692 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
5693 |
|
|
del_timer(&hd->timer);
|
5694 |
|
|
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
5695 |
|
|
hd->ScsiLookup[req_idx] = NULL;
|
5696 |
|
|
pReq = (SCSIIORequest_t *) mf;
|
5697 |
|
|
|
5698 |
|
|
if (mf != hd->cmdPtr) {
|
5699 |
|
|
printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
|
5700 |
|
|
hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
|
5701 |
|
|
}
|
5702 |
|
|
hd->cmdPtr = NULL;
|
5703 |
|
|
|
5704 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
|
5705 |
|
|
hd->ioc->name, mf, mr, req_idx));
|
5706 |
|
|
|
5707 |
|
|
atomic_dec(&queue_depth);
|
5708 |
|
|
|
5709 |
|
|
hd->pLocal = &hd->localReply;
|
5710 |
|
|
hd->pLocal->scsiStatus = 0;
|
5711 |
|
|
|
5712 |
|
|
/* If target struct exists, clear sense valid flag.
|
5713 |
|
|
*/
|
5714 |
|
|
if (mr == NULL) {
|
5715 |
|
|
completionCode = MPT_SCANDV_GOOD;
|
5716 |
|
|
} else {
|
5717 |
|
|
SCSIIOReply_t *pReply;
|
5718 |
|
|
u16 status;
|
5719 |
|
|
|
5720 |
|
|
pReply = (SCSIIOReply_t *) mr;
|
5721 |
|
|
|
5722 |
|
|
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
5723 |
|
|
|
5724 |
|
|
ddvtprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
|
5725 |
|
|
status, pReply->SCSIState, pReply->SCSIStatus,
|
5726 |
|
|
le32_to_cpu(pReply->IOCLogInfo)));
|
5727 |
|
|
|
5728 |
|
|
switch(status) {
|
5729 |
|
|
|
5730 |
|
|
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
|
5731 |
|
|
completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
|
5732 |
|
|
break;
|
5733 |
|
|
|
5734 |
|
|
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
|
5735 |
|
|
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
|
5736 |
|
|
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
|
5737 |
|
|
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
|
5738 |
|
|
completionCode = MPT_SCANDV_DID_RESET;
|
5739 |
|
|
break;
|
5740 |
|
|
|
5741 |
|
|
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
|
5742 |
|
|
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
|
5743 |
|
|
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
|
5744 |
|
|
if (pReply->Function == MPI_FUNCTION_CONFIG) {
|
5745 |
|
|
ConfigReply_t *pr = (ConfigReply_t *)mr;
|
5746 |
|
|
completionCode = MPT_SCANDV_GOOD;
|
5747 |
|
|
hd->pLocal->header.PageVersion = pr->Header.PageVersion;
|
5748 |
|
|
hd->pLocal->header.PageLength = pr->Header.PageLength;
|
5749 |
|
|
hd->pLocal->header.PageNumber = pr->Header.PageNumber;
|
5750 |
|
|
hd->pLocal->header.PageType = pr->Header.PageType;
|
5751 |
|
|
|
5752 |
|
|
} else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
|
5753 |
|
|
/* If the RAID Volume request is successful,
|
5754 |
|
|
* return GOOD, else indicate that
|
5755 |
|
|
* some type of error occurred.
|
5756 |
|
|
*/
|
5757 |
|
|
MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr;
|
5758 |
|
|
if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
|
5759 |
|
|
completionCode = MPT_SCANDV_GOOD;
|
5760 |
|
|
else
|
5761 |
|
|
completionCode = MPT_SCANDV_SOME_ERROR;
|
5762 |
|
|
|
5763 |
|
|
} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
|
5764 |
|
|
u8 *sense_data;
|
5765 |
|
|
int sz;
|
5766 |
|
|
|
5767 |
|
|
/* save sense data in global structure
|
5768 |
|
|
*/
|
5769 |
|
|
completionCode = MPT_SCANDV_SENSE;
|
5770 |
|
|
hd->pLocal->scsiStatus = pReply->SCSIStatus;
|
5771 |
|
|
sense_data = ((u8 *)hd->ioc->sense_buf_pool +
|
5772 |
|
|
(req_idx * MPT_SENSE_BUFFER_ALLOC));
|
5773 |
|
|
|
5774 |
|
|
sz = MIN (pReq->SenseBufferLength,
|
5775 |
|
|
SCSI_STD_SENSE_BYTES);
|
5776 |
|
|
memcpy(hd->pLocal->sense, sense_data, sz);
|
5777 |
|
|
|
5778 |
|
|
ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n",
|
5779 |
|
|
sense_data));
|
5780 |
|
|
} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
|
5781 |
|
|
if (pReq->CDB[0] == CMD_Inquiry)
|
5782 |
|
|
completionCode = MPT_SCANDV_ISSUE_SENSE;
|
5783 |
|
|
else
|
5784 |
|
|
completionCode = MPT_SCANDV_DID_RESET;
|
5785 |
|
|
}
|
5786 |
|
|
else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
|
5787 |
|
|
completionCode = MPT_SCANDV_DID_RESET;
|
5788 |
|
|
else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
|
5789 |
|
|
completionCode = MPT_SCANDV_DID_RESET;
|
5790 |
|
|
else {
|
5791 |
|
|
/* If no error, this will be equivalent
|
5792 |
|
|
* to MPT_SCANDV_GOOD
|
5793 |
|
|
*/
|
5794 |
|
|
completionCode = MPT_SCANDV_GOOD;
|
5795 |
|
|
hd->pLocal->scsiStatus = pReply->SCSIStatus;
|
5796 |
|
|
}
|
5797 |
|
|
break;
|
5798 |
|
|
|
5799 |
|
|
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
|
5800 |
|
|
if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
|
5801 |
|
|
completionCode = MPT_SCANDV_DID_RESET;
|
5802 |
|
|
else
|
5803 |
|
|
completionCode = MPT_SCANDV_SOME_ERROR;
|
5804 |
|
|
break;
|
5805 |
|
|
|
5806 |
|
|
default:
|
5807 |
|
|
completionCode = MPT_SCANDV_SOME_ERROR;
|
5808 |
|
|
break;
|
5809 |
|
|
|
5810 |
|
|
} /* switch(status) */
|
5811 |
|
|
|
5812 |
|
|
ddvtprintk((KERN_NOTICE " completionCode set to %08xh\n",
|
5813 |
|
|
completionCode));
|
5814 |
|
|
} /* end of address reply case */
|
5815 |
|
|
|
5816 |
|
|
hd->pLocal->completion = completionCode;
|
5817 |
|
|
|
5818 |
|
|
/* MF and RF are freed in mpt_interrupt
|
5819 |
|
|
*/
|
5820 |
|
|
wakeup:
|
5821 |
|
|
/* Free Chain buffers (will never chain) in scan or dv */
|
5822 |
|
|
//mptscsih_freeChainBuffers(hd, req_idx);
|
5823 |
|
|
|
5824 |
|
|
/*
|
5825 |
|
|
* Wake up the original calling thread
|
5826 |
|
|
*/
|
5827 |
|
|
scandv_wait_done = 1;
|
5828 |
|
|
wake_up(&scandv_waitq);
|
5829 |
|
|
|
5830 |
|
|
return 1;
|
5831 |
|
|
}
|
5832 |
|
|
|
5833 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5834 |
|
|
/* mptscsih_timer_expired - Call back for timer process.
|
5835 |
|
|
* Used only for dv functionality.
|
5836 |
|
|
* @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
|
5837 |
|
|
*
|
5838 |
|
|
*/
|
5839 |
|
|
static void mptscsih_timer_expired(unsigned long data)
|
5840 |
|
|
{
|
5841 |
|
|
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
|
5842 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
5843 |
|
|
unsigned long flags;
|
5844 |
|
|
#endif
|
5845 |
|
|
|
5846 |
|
|
|
5847 |
|
|
ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
|
5848 |
|
|
|
5849 |
|
|
if (hd->cmdPtr) {
|
5850 |
|
|
MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
|
5851 |
|
|
|
5852 |
|
|
if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
|
5853 |
|
|
/* Desire to issue a task management request here.
|
5854 |
|
|
* TM requests MUST be single threaded.
|
5855 |
|
|
* If old eh code and no TM current, issue request.
|
5856 |
|
|
* If new eh code, do nothing. Wait for OS cmd timeout
|
5857 |
|
|
* for bus reset.
|
5858 |
|
|
*/
|
5859 |
|
|
#ifndef MPT_SCSI_USE_NEW_EH
|
5860 |
|
|
SCSIIORequest_t *pReq = (SCSIIORequest_t *) hd->cmdPtr;
|
5861 |
|
|
|
5862 |
|
|
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
|
5863 |
|
|
if (hd->tmPending) {
|
5864 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
5865 |
|
|
return;
|
5866 |
|
|
} else
|
5867 |
|
|
hd->tmPending = 1;
|
5868 |
|
|
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
|
5869 |
|
|
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
5870 |
|
|
pReq->Bus, 0, 0, 0, NO_SLEEP) < 0) {
|
5871 |
|
|
printk(MYIOC_s_WARN_FMT "TM FAILED!\n", hd->ioc->name);
|
5872 |
|
|
}
|
5873 |
|
|
#else
|
5874 |
|
|
ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
|
5875 |
|
|
#endif
|
5876 |
|
|
} else {
|
5877 |
|
|
/* Perform a FW reload */
|
5878 |
|
|
if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
|
5879 |
|
|
printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
|
5880 |
|
|
}
|
5881 |
|
|
}
|
5882 |
|
|
} else {
|
5883 |
|
|
/* This should NEVER happen */
|
5884 |
|
|
printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
|
5885 |
|
|
}
|
5886 |
|
|
|
5887 |
|
|
/* No more processing.
|
5888 |
|
|
* TM call will generate an interrupt for SCSI TM Management.
|
5889 |
|
|
* The FW will reply to all outstanding commands, callback will finish cleanup.
|
5890 |
|
|
* Hard reset clean-up will free all resources.
|
5891 |
|
|
*/
|
5892 |
|
|
ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
|
5893 |
|
|
|
5894 |
|
|
return;
|
5895 |
|
|
}
|
5896 |
|
|
|
5897 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
5898 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5899 |
|
|
/* mptscsih_do_raid - Format and Issue a RAID volume request message.
|
5900 |
|
|
* @hd: Pointer to scsi host structure
|
5901 |
|
|
* @action: What do be done.
|
5902 |
|
|
* @id: Logical target id.
|
5903 |
|
|
* @bus: Target locations bus.
|
5904 |
|
|
*
|
5905 |
|
|
* Returns: < 0 on a fatal error
|
5906 |
|
|
* 0 on success
|
5907 |
|
|
*
|
5908 |
|
|
* Remark: Wait to return until reply processed by the ISR.
|
5909 |
|
|
*/
|
5910 |
|
|
static int
|
5911 |
|
|
mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
|
5912 |
|
|
{
|
5913 |
|
|
MpiRaidActionRequest_t *pReq;
|
5914 |
|
|
MPT_FRAME_HDR *mf;
|
5915 |
|
|
int in_isr;
|
5916 |
|
|
|
5917 |
|
|
in_isr = in_interrupt();
|
5918 |
|
|
if (in_isr) {
|
5919 |
|
|
dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
|
5920 |
|
|
hd->ioc->name));
|
5921 |
|
|
return -EPERM;
|
5922 |
|
|
}
|
5923 |
|
|
|
5924 |
|
|
/* Get and Populate a free Frame
|
5925 |
|
|
*/
|
5926 |
|
|
if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
|
5927 |
|
|
ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
|
5928 |
|
|
hd->ioc->name));
|
5929 |
|
|
return -EAGAIN;
|
5930 |
|
|
}
|
5931 |
|
|
pReq = (MpiRaidActionRequest_t *)mf;
|
5932 |
|
|
pReq->Action = action;
|
5933 |
|
|
pReq->Reserved1 = 0;
|
5934 |
|
|
pReq->ChainOffset = 0;
|
5935 |
|
|
pReq->Function = MPI_FUNCTION_RAID_ACTION;
|
5936 |
|
|
pReq->VolumeID = io->id;
|
5937 |
|
|
pReq->VolumeBus = io->bus;
|
5938 |
|
|
pReq->PhysDiskNum = io->physDiskNum;
|
5939 |
|
|
pReq->MsgFlags = 0;
|
5940 |
|
|
pReq->Reserved2 = 0;
|
5941 |
|
|
pReq->ActionDataWord = 0; /* Reserved for this action */
|
5942 |
|
|
//pReq->ActionDataSGE = 0;
|
5943 |
|
|
|
5944 |
|
|
mpt_add_sge((char *)&pReq->ActionDataSGE,
|
5945 |
|
|
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
|
5946 |
|
|
|
5947 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
|
5948 |
|
|
hd->ioc->name, action, io->id));
|
5949 |
|
|
|
5950 |
|
|
hd->pLocal = NULL;
|
5951 |
|
|
hd->timer.expires = jiffies + HZ*2; /* 2 second timeout */
|
5952 |
|
|
scandv_wait_done = 0;
|
5953 |
|
|
|
5954 |
|
|
/* Save cmd pointer, for resource free if timeout or
|
5955 |
|
|
* FW reload occurs
|
5956 |
|
|
*/
|
5957 |
|
|
hd->cmdPtr = mf;
|
5958 |
|
|
|
5959 |
|
|
add_timer(&hd->timer);
|
5960 |
|
|
mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
|
5961 |
|
|
wait_event(scandv_waitq, scandv_wait_done);
|
5962 |
|
|
|
5963 |
|
|
if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
|
5964 |
|
|
return -1;
|
5965 |
|
|
|
5966 |
|
|
return 0;
|
5967 |
|
|
}
|
5968 |
|
|
#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
|
5969 |
|
|
|
5970 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
5971 |
|
|
/**
|
5972 |
|
|
* mptscsih_do_cmd - Do internal command.
|
5973 |
|
|
* @hd: MPT_SCSI_HOST pointer
|
5974 |
|
|
* @io: INTERNAL_CMD pointer.
|
5975 |
|
|
*
|
5976 |
|
|
* Issue the specified internally generated command and do command
|
5977 |
|
|
* specific cleanup. For bus scan / DV only.
|
5978 |
|
|
* NOTES: If command is Inquiry and status is good,
|
5979 |
|
|
* initialize a target structure, save the data
|
5980 |
|
|
*
|
5981 |
|
|
* Remark: Single threaded access only.
|
5982 |
|
|
*
|
5983 |
|
|
* Return:
|
5984 |
|
|
* < 0 if an illegal command or no resources
|
5985 |
|
|
*
|
5986 |
|
|
* 0 if good
|
5987 |
|
|
*
|
5988 |
|
|
* > 0 if command complete but some type of completion error.
|
5989 |
|
|
*/
|
5990 |
|
|
static int
|
5991 |
|
|
mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
|
5992 |
|
|
{
|
5993 |
|
|
MPT_FRAME_HDR *mf;
|
5994 |
|
|
SCSIIORequest_t *pScsiReq;
|
5995 |
|
|
SCSIIORequest_t ReqCopy;
|
5996 |
|
|
int my_idx, ii, dir;
|
5997 |
|
|
int rc, cmdTimeout;
|
5998 |
|
|
int in_isr;
|
5999 |
|
|
char cmdLen;
|
6000 |
|
|
char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
6001 |
|
|
char cmd = io->cmd;
|
6002 |
|
|
|
6003 |
|
|
in_isr = in_interrupt();
|
6004 |
|
|
if (in_isr) {
|
6005 |
|
|
dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
|
6006 |
|
|
hd->ioc->name));
|
6007 |
|
|
return -EPERM;
|
6008 |
|
|
}
|
6009 |
|
|
|
6010 |
|
|
|
6011 |
|
|
/* Set command specific information
|
6012 |
|
|
*/
|
6013 |
|
|
switch (cmd) {
|
6014 |
|
|
case CMD_Inquiry:
|
6015 |
|
|
cmdLen = 6;
|
6016 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6017 |
|
|
CDB[0] = cmd;
|
6018 |
|
|
CDB[4] = io->size;
|
6019 |
|
|
cmdTimeout = 10;
|
6020 |
|
|
break;
|
6021 |
|
|
|
6022 |
|
|
case CMD_TestUnitReady:
|
6023 |
|
|
cmdLen = 6;
|
6024 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6025 |
|
|
cmdTimeout = 10;
|
6026 |
|
|
break;
|
6027 |
|
|
|
6028 |
|
|
case CMD_StartStopUnit:
|
6029 |
|
|
cmdLen = 6;
|
6030 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6031 |
|
|
CDB[0] = cmd;
|
6032 |
|
|
CDB[4] = 1; /*Spin up the disk */
|
6033 |
|
|
cmdTimeout = 15;
|
6034 |
|
|
break;
|
6035 |
|
|
|
6036 |
|
|
case CMD_RequestSense:
|
6037 |
|
|
cmdLen = 6;
|
6038 |
|
|
CDB[0] = cmd;
|
6039 |
|
|
CDB[4] = io->size;
|
6040 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6041 |
|
|
cmdTimeout = 10;
|
6042 |
|
|
break;
|
6043 |
|
|
|
6044 |
|
|
case CMD_ReadBuffer:
|
6045 |
|
|
cmdLen = 10;
|
6046 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6047 |
|
|
CDB[0] = cmd;
|
6048 |
|
|
if (io->flags & MPT_ICFLAG_ECHO) {
|
6049 |
|
|
CDB[1] = 0x0A;
|
6050 |
|
|
} else {
|
6051 |
|
|
CDB[1] = 0x02;
|
6052 |
|
|
}
|
6053 |
|
|
|
6054 |
|
|
if (io->flags & MPT_ICFLAG_BUF_CAP) {
|
6055 |
|
|
CDB[1] |= 0x01;
|
6056 |
|
|
}
|
6057 |
|
|
CDB[6] = (io->size >> 16) & 0xFF;
|
6058 |
|
|
CDB[7] = (io->size >> 8) & 0xFF;
|
6059 |
|
|
CDB[8] = io->size & 0xFF;
|
6060 |
|
|
cmdTimeout = 10;
|
6061 |
|
|
break;
|
6062 |
|
|
|
6063 |
|
|
case CMD_WriteBuffer:
|
6064 |
|
|
cmdLen = 10;
|
6065 |
|
|
dir = MPI_SCSIIO_CONTROL_WRITE;
|
6066 |
|
|
CDB[0] = cmd;
|
6067 |
|
|
if (io->flags & MPT_ICFLAG_ECHO) {
|
6068 |
|
|
CDB[1] = 0x0A;
|
6069 |
|
|
} else {
|
6070 |
|
|
CDB[1] = 0x02;
|
6071 |
|
|
}
|
6072 |
|
|
CDB[6] = (io->size >> 16) & 0xFF;
|
6073 |
|
|
CDB[7] = (io->size >> 8) & 0xFF;
|
6074 |
|
|
CDB[8] = io->size & 0xFF;
|
6075 |
|
|
cmdTimeout = 10;
|
6076 |
|
|
break;
|
6077 |
|
|
|
6078 |
|
|
case CMD_Reserve6:
|
6079 |
|
|
cmdLen = 6;
|
6080 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6081 |
|
|
CDB[0] = cmd;
|
6082 |
|
|
cmdTimeout = 10;
|
6083 |
|
|
break;
|
6084 |
|
|
|
6085 |
|
|
case CMD_Release6:
|
6086 |
|
|
cmdLen = 6;
|
6087 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6088 |
|
|
CDB[0] = cmd;
|
6089 |
|
|
cmdTimeout = 10;
|
6090 |
|
|
break;
|
6091 |
|
|
|
6092 |
|
|
case CMD_SynchronizeCache:
|
6093 |
|
|
cmdLen = 10;
|
6094 |
|
|
dir = MPI_SCSIIO_CONTROL_READ;
|
6095 |
|
|
CDB[0] = cmd;
|
6096 |
|
|
// CDB[1] = 0x02; /* set immediate bit */
|
6097 |
|
|
cmdTimeout = 10;
|
6098 |
|
|
break;
|
6099 |
|
|
|
6100 |
|
|
default:
|
6101 |
|
|
/* Error Case */
|
6102 |
|
|
return -EFAULT;
|
6103 |
|
|
}
|
6104 |
|
|
|
6105 |
|
|
/* Get and Populate a free Frame
|
6106 |
|
|
*/
|
6107 |
|
|
if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
|
6108 |
|
|
ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
|
6109 |
|
|
hd->ioc->name));
|
6110 |
|
|
return -EBUSY;
|
6111 |
|
|
}
|
6112 |
|
|
|
6113 |
|
|
pScsiReq = (SCSIIORequest_t *) mf;
|
6114 |
|
|
|
6115 |
|
|
/* Get the request index */
|
6116 |
|
|
my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
|
6117 |
|
|
ADD_INDEX_LOG(my_idx); /* for debug */
|
6118 |
|
|
|
6119 |
|
|
if (io->flags & MPT_ICFLAG_PHYS_DISK) {
|
6120 |
|
|
pScsiReq->TargetID = io->physDiskNum;
|
6121 |
|
|
pScsiReq->Bus = 0;
|
6122 |
|
|
pScsiReq->ChainOffset = 0;
|
6123 |
|
|
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
|
6124 |
|
|
} else {
|
6125 |
|
|
pScsiReq->TargetID = io->id;
|
6126 |
|
|
pScsiReq->Bus = io->bus;
|
6127 |
|
|
pScsiReq->ChainOffset = 0;
|
6128 |
|
|
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
|
6129 |
|
|
}
|
6130 |
|
|
|
6131 |
|
|
pScsiReq->CDBLength = cmdLen;
|
6132 |
|
|
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
|
6133 |
|
|
|
6134 |
|
|
pScsiReq->Reserved = 0;
|
6135 |
|
|
|
6136 |
|
|
pScsiReq->MsgFlags = mpt_msg_flags();
|
6137 |
|
|
/* MsgContext set in mpt_get_msg_fram call */
|
6138 |
|
|
|
6139 |
|
|
for (ii=0; ii < 8; ii++)
|
6140 |
|
|
pScsiReq->LUN[ii] = 0;
|
6141 |
|
|
pScsiReq->LUN[1] = io->lun;
|
6142 |
|
|
|
6143 |
|
|
if (io->flags & MPT_ICFLAG_TAGGED_CMD)
|
6144 |
|
|
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
|
6145 |
|
|
else
|
6146 |
|
|
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
|
6147 |
|
|
|
6148 |
|
|
if (cmd == CMD_RequestSense) {
|
6149 |
|
|
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
|
6150 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
|
6151 |
|
|
hd->ioc->name, cmd));
|
6152 |
|
|
}
|
6153 |
|
|
|
6154 |
|
|
for (ii=0; ii < 16; ii++)
|
6155 |
|
|
pScsiReq->CDB[ii] = CDB[ii];
|
6156 |
|
|
|
6157 |
|
|
pScsiReq->DataLength = cpu_to_le32(io->size);
|
6158 |
|
|
pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
|
6159 |
|
|
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
|
6160 |
|
|
|
6161 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
|
6162 |
|
|
hd->ioc->name, cmd, io->bus, io->id, io->lun));
|
6163 |
|
|
|
6164 |
|
|
if (dir == MPI_SCSIIO_CONTROL_READ) {
|
6165 |
|
|
mpt_add_sge((char *) &pScsiReq->SGL,
|
6166 |
|
|
MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
|
6167 |
|
|
io->data_dma);
|
6168 |
|
|
} else {
|
6169 |
|
|
mpt_add_sge((char *) &pScsiReq->SGL,
|
6170 |
|
|
MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
|
6171 |
|
|
io->data_dma);
|
6172 |
|
|
}
|
6173 |
|
|
|
6174 |
|
|
/* The ISR will free the request frame, but we need
|
6175 |
|
|
* the information to initialize the target. Duplicate.
|
6176 |
|
|
*/
|
6177 |
|
|
memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
|
6178 |
|
|
|
6179 |
|
|
/* Issue this command after:
|
6180 |
|
|
* finish init
|
6181 |
|
|
* add timer
|
6182 |
|
|
* Wait until the reply has been received
|
6183 |
|
|
* ScsiScanDvCtx callback function will
|
6184 |
|
|
* set hd->pLocal;
|
6185 |
|
|
* set scandv_wait_done and call wake_up
|
6186 |
|
|
*/
|
6187 |
|
|
hd->pLocal = NULL;
|
6188 |
|
|
hd->timer.expires = jiffies + HZ*cmdTimeout;
|
6189 |
|
|
scandv_wait_done = 0;
|
6190 |
|
|
|
6191 |
|
|
/* Save cmd pointer, for resource free if timeout or
|
6192 |
|
|
* FW reload occurs
|
6193 |
|
|
*/
|
6194 |
|
|
hd->cmdPtr = mf;
|
6195 |
|
|
|
6196 |
|
|
add_timer(&hd->timer);
|
6197 |
|
|
mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
|
6198 |
|
|
wait_event(scandv_waitq, scandv_wait_done);
|
6199 |
|
|
|
6200 |
|
|
if (hd->pLocal) {
|
6201 |
|
|
rc = hd->pLocal->completion;
|
6202 |
|
|
hd->pLocal->skip = 0;
|
6203 |
|
|
|
6204 |
|
|
/* Always set fatal error codes in some cases.
|
6205 |
|
|
*/
|
6206 |
|
|
if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
|
6207 |
|
|
rc = -ENXIO;
|
6208 |
|
|
else if (rc == MPT_SCANDV_SOME_ERROR)
|
6209 |
|
|
rc = -rc;
|
6210 |
|
|
} else {
|
6211 |
|
|
rc = -EFAULT;
|
6212 |
|
|
/* This should never happen. */
|
6213 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
|
6214 |
|
|
hd->ioc->name));
|
6215 |
|
|
}
|
6216 |
|
|
|
6217 |
|
|
return rc;
|
6218 |
|
|
}
|
6219 |
|
|
|
6220 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
6221 |
|
|
/**
|
6222 |
|
|
* mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
|
6223 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure
|
6224 |
|
|
* @portnum: IOC port number
|
6225 |
|
|
*
|
6226 |
|
|
* Uses the ISR, but with special processing.
|
6227 |
|
|
* MUST be single-threaded.
|
6228 |
|
|
*
|
6229 |
|
|
* Return: 0 on completion
|
6230 |
|
|
*/
|
6231 |
|
|
static int
|
6232 |
|
|
mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
|
6233 |
|
|
{
|
6234 |
|
|
MPT_ADAPTER *ioc= hd->ioc;
|
6235 |
|
|
VirtDevice *pTarget;
|
6236 |
|
|
SCSIDevicePage1_t *pcfg1Data = NULL;
|
6237 |
|
|
INTERNAL_CMD iocmd;
|
6238 |
|
|
CONFIGPARMS cfg;
|
6239 |
|
|
dma_addr_t cfg1_dma_addr = -1;
|
6240 |
|
|
ConfigPageHeader_t header1;
|
6241 |
|
|
int bus = 0;
|
6242 |
|
|
int id = 0;
|
6243 |
|
|
int lun;
|
6244 |
|
|
int indexed_lun, lun_index;
|
6245 |
|
|
int hostId = ioc->pfacts[portnum].PortSCSIID;
|
6246 |
|
|
int max_id;
|
6247 |
|
|
int requested, configuration, data;
|
6248 |
|
|
int doConfig = 0;
|
6249 |
|
|
u8 flags, factor;
|
6250 |
|
|
|
6251 |
|
|
max_id = ioc->sh->max_id - 1;
|
6252 |
|
|
|
6253 |
|
|
/* Following parameters will not change
|
6254 |
|
|
* in this routine.
|
6255 |
|
|
*/
|
6256 |
|
|
iocmd.cmd = CMD_SynchronizeCache;
|
6257 |
|
|
iocmd.flags = 0;
|
6258 |
|
|
iocmd.physDiskNum = -1;
|
6259 |
|
|
iocmd.data = NULL;
|
6260 |
|
|
iocmd.data_dma = -1;
|
6261 |
|
|
iocmd.size = 0;
|
6262 |
|
|
iocmd.rsvd = iocmd.rsvd2 = 0;
|
6263 |
|
|
|
6264 |
|
|
/* No SCSI hosts
|
6265 |
|
|
*/
|
6266 |
|
|
if (hd->Targets == NULL)
|
6267 |
|
|
return 0;
|
6268 |
|
|
|
6269 |
|
|
/* Skip the host
|
6270 |
|
|
*/
|
6271 |
|
|
if (id == hostId)
|
6272 |
|
|
id++;
|
6273 |
|
|
|
6274 |
|
|
/* Write SDP1 for all SCSI devices
|
6275 |
|
|
* Alloc memory and set up config buffer
|
6276 |
|
|
*/
|
6277 |
|
|
if (hd->is_spi) {
|
6278 |
|
|
if (ioc->spi_data.sdp1length > 0) {
|
6279 |
|
|
pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
|
6280 |
|
|
ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
|
6281 |
|
|
|
6282 |
|
|
if (pcfg1Data != NULL) {
|
6283 |
|
|
doConfig = 1;
|
6284 |
|
|
header1.PageVersion = ioc->spi_data.sdp1version;
|
6285 |
|
|
header1.PageLength = ioc->spi_data.sdp1length;
|
6286 |
|
|
header1.PageNumber = 1;
|
6287 |
|
|
header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
|
6288 |
|
|
cfg.hdr = &header1;
|
6289 |
|
|
cfg.physAddr = cfg1_dma_addr;
|
6290 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
6291 |
|
|
cfg.dir = 1;
|
6292 |
|
|
cfg.timeout = 0;
|
6293 |
|
|
}
|
6294 |
|
|
}
|
6295 |
|
|
}
|
6296 |
|
|
|
6297 |
|
|
/* loop through all devices on this port
|
6298 |
|
|
*/
|
6299 |
|
|
while (bus < MPT_MAX_BUS) {
|
6300 |
|
|
iocmd.bus = bus;
|
6301 |
|
|
iocmd.id = id;
|
6302 |
|
|
pTarget = hd->Targets[(int)id];
|
6303 |
|
|
|
6304 |
|
|
if (doConfig) {
|
6305 |
|
|
|
6306 |
|
|
/* Set the negotiation flags */
|
6307 |
|
|
if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
|
6308 |
|
|
flags = pTarget->negoFlags;
|
6309 |
|
|
} else {
|
6310 |
|
|
flags = hd->ioc->spi_data.noQas;
|
6311 |
|
|
if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
6312 |
|
|
data = hd->ioc->spi_data.nvram[id];
|
6313 |
|
|
|
6314 |
|
|
if (data & MPT_NVRAM_WIDE_DISABLE)
|
6315 |
|
|
flags |= MPT_TARGET_NO_NEGO_WIDE;
|
6316 |
|
|
|
6317 |
|
|
factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
|
6318 |
|
|
if ((factor == 0) || (factor == MPT_ASYNC))
|
6319 |
|
|
flags |= MPT_TARGET_NO_NEGO_SYNC;
|
6320 |
|
|
}
|
6321 |
|
|
}
|
6322 |
|
|
|
6323 |
|
|
/* Force to async, narrow */
|
6324 |
|
|
mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
|
6325 |
|
|
&configuration, flags);
|
6326 |
|
|
pcfg1Data->RequestedParameters = le32_to_cpu(requested);
|
6327 |
|
|
pcfg1Data->Reserved = 0;
|
6328 |
|
|
pcfg1Data->Configuration = le32_to_cpu(configuration);
|
6329 |
|
|
cfg.pageAddr = (bus<<8) | id;
|
6330 |
|
|
mpt_config(hd->ioc, &cfg);
|
6331 |
|
|
}
|
6332 |
|
|
|
6333 |
|
|
/* If target Ptr NULL or if this target is NOT a disk, skip.
|
6334 |
|
|
*/
|
6335 |
|
|
if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
|
6336 |
|
|
for (lun=0; lun <= MPT_LAST_LUN; lun++) {
|
6337 |
|
|
/* If LUN present, issue the command
|
6338 |
|
|
*/
|
6339 |
|
|
lun_index = (lun >> 5); /* 32 luns per lun_index */
|
6340 |
|
|
indexed_lun = (lun % 32);
|
6341 |
|
|
if (pTarget->luns[lun_index] & (1<<indexed_lun)) {
|
6342 |
|
|
iocmd.lun = lun;
|
6343 |
|
|
(void) mptscsih_do_cmd(hd, &iocmd);
|
6344 |
|
|
}
|
6345 |
|
|
}
|
6346 |
|
|
}
|
6347 |
|
|
|
6348 |
|
|
/* get next relevant device */
|
6349 |
|
|
id++;
|
6350 |
|
|
|
6351 |
|
|
if (id == hostId)
|
6352 |
|
|
id++;
|
6353 |
|
|
|
6354 |
|
|
if (id > max_id) {
|
6355 |
|
|
id = 0;
|
6356 |
|
|
bus++;
|
6357 |
|
|
}
|
6358 |
|
|
}
|
6359 |
|
|
|
6360 |
|
|
if (pcfg1Data) {
|
6361 |
|
|
pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
|
6362 |
|
|
}
|
6363 |
|
|
|
6364 |
|
|
return 0;
|
6365 |
|
|
}
|
6366 |
|
|
|
6367 |
|
|
#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
|
6368 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
6369 |
|
|
/**
|
6370 |
|
|
* mptscsih_domainValidation - Top level handler for domain validation.
|
6371 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure.
|
6372 |
|
|
*
|
6373 |
|
|
* Uses the ISR, but with special processing.
|
6374 |
|
|
* Called from schedule, should not be in interrupt mode.
|
6375 |
|
|
* While thread alive, do dv for all devices needing dv
|
6376 |
|
|
*
|
6377 |
|
|
* Return: None.
|
6378 |
|
|
*/
|
6379 |
|
|
static void
|
6380 |
|
|
mptscsih_domainValidation(void *arg)
|
6381 |
|
|
{
|
6382 |
|
|
MPT_SCSI_HOST *hd;
|
6383 |
|
|
MPT_ADAPTER *ioc;
|
6384 |
|
|
unsigned long flags;
|
6385 |
|
|
int id, maxid, dvStatus, did;
|
6386 |
|
|
int ii, isPhysDisk;
|
6387 |
|
|
|
6388 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, flags);
|
6389 |
|
|
dvtaskQ_active = 1;
|
6390 |
|
|
if (dvtaskQ_release) {
|
6391 |
|
|
dvtaskQ_active = 0;
|
6392 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6393 |
|
|
return;
|
6394 |
|
|
}
|
6395 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6396 |
|
|
|
6397 |
|
|
/* For this ioc, loop through all devices and do dv to each device.
|
6398 |
|
|
* When complete with this ioc, search through the ioc list, and
|
6399 |
|
|
* for each scsi ioc found, do dv for all devices. Exit when no
|
6400 |
|
|
* device needs dv.
|
6401 |
|
|
*/
|
6402 |
|
|
did = 1;
|
6403 |
|
|
while (did) {
|
6404 |
|
|
did = 0;
|
6405 |
|
|
for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
|
6406 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, flags);
|
6407 |
|
|
if (dvtaskQ_release) {
|
6408 |
|
|
dvtaskQ_active = 0;
|
6409 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6410 |
|
|
return;
|
6411 |
|
|
}
|
6412 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6413 |
|
|
|
6414 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
6415 |
|
|
schedule_timeout(HZ/4);
|
6416 |
|
|
|
6417 |
|
|
/* DV only to SCSI adapters */
|
6418 |
|
|
if ((int)ioc->chip_type <= (int)FC929)
|
6419 |
|
|
continue;
|
6420 |
|
|
|
6421 |
|
|
/* Make sure everything looks ok */
|
6422 |
|
|
if (ioc->sh == NULL)
|
6423 |
|
|
continue;
|
6424 |
|
|
|
6425 |
|
|
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
6426 |
|
|
if (hd == NULL)
|
6427 |
|
|
continue;
|
6428 |
|
|
|
6429 |
|
|
if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
|
6430 |
|
|
mpt_read_ioc_pg_3(ioc);
|
6431 |
|
|
if (ioc->spi_data.pIocPg3) {
|
6432 |
|
|
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
|
6433 |
|
|
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
|
6434 |
|
|
|
6435 |
|
|
while (numPDisk) {
|
6436 |
|
|
if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
|
6437 |
|
|
ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
|
6438 |
|
|
|
6439 |
|
|
pPDisk++;
|
6440 |
|
|
numPDisk--;
|
6441 |
|
|
}
|
6442 |
|
|
}
|
6443 |
|
|
ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
|
6444 |
|
|
}
|
6445 |
|
|
|
6446 |
|
|
maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
|
6447 |
|
|
|
6448 |
|
|
for (id = 0; id < maxid; id++) {
|
6449 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, flags);
|
6450 |
|
|
if (dvtaskQ_release) {
|
6451 |
|
|
dvtaskQ_active = 0;
|
6452 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6453 |
|
|
return;
|
6454 |
|
|
}
|
6455 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6456 |
|
|
dvStatus = hd->ioc->spi_data.dvStatus[id];
|
6457 |
|
|
|
6458 |
|
|
if (dvStatus & MPT_SCSICFG_NEED_DV) {
|
6459 |
|
|
did++;
|
6460 |
|
|
hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
|
6461 |
|
|
hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
|
6462 |
|
|
|
6463 |
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
6464 |
|
|
schedule_timeout(HZ/4);
|
6465 |
|
|
|
6466 |
|
|
/* If hidden phys disk, block IO's to all
|
6467 |
|
|
* raid volumes
|
6468 |
|
|
* else, process normally
|
6469 |
|
|
*/
|
6470 |
|
|
isPhysDisk = mptscsih_is_phys_disk(ioc, id);
|
6471 |
|
|
if (isPhysDisk) {
|
6472 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
6473 |
|
|
if (hd->ioc->spi_data.isRaid & (1 << ii)) {
|
6474 |
|
|
hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
|
6475 |
|
|
}
|
6476 |
|
|
}
|
6477 |
|
|
}
|
6478 |
|
|
|
6479 |
|
|
if (mptscsih_doDv(hd, 0, id) == 1) {
|
6480 |
|
|
/* Untagged device was busy, try again
|
6481 |
|
|
*/
|
6482 |
|
|
hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
|
6483 |
|
|
hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
|
6484 |
|
|
} else {
|
6485 |
|
|
/* DV is complete. Clear flags.
|
6486 |
|
|
*/
|
6487 |
|
|
hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
|
6488 |
|
|
}
|
6489 |
|
|
|
6490 |
|
|
if (isPhysDisk) {
|
6491 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
6492 |
|
|
if (hd->ioc->spi_data.isRaid & (1 << ii)) {
|
6493 |
|
|
hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
|
6494 |
|
|
}
|
6495 |
|
|
}
|
6496 |
|
|
}
|
6497 |
|
|
|
6498 |
|
|
/* Post OS IOs that were pended while
|
6499 |
|
|
* DV running.
|
6500 |
|
|
*/
|
6501 |
|
|
post_pendingQ_commands(hd);
|
6502 |
|
|
|
6503 |
|
|
if (hd->ioc->spi_data.noQas)
|
6504 |
|
|
mptscsih_qas_check(hd, id);
|
6505 |
|
|
}
|
6506 |
|
|
}
|
6507 |
|
|
}
|
6508 |
|
|
}
|
6509 |
|
|
|
6510 |
|
|
spin_lock_irqsave(&dvtaskQ_lock, flags);
|
6511 |
|
|
dvtaskQ_active = 0;
|
6512 |
|
|
spin_unlock_irqrestore(&dvtaskQ_lock, flags);
|
6513 |
|
|
|
6514 |
|
|
return;
|
6515 |
|
|
}
|
6516 |
|
|
|
6517 |
|
|
/* Search IOC page 3 to determine if this is hidden physical disk
|
6518 |
|
|
*/
|
6519 |
|
|
static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
|
6520 |
|
|
{
|
6521 |
|
|
if (ioc->spi_data.pIocPg3) {
|
6522 |
|
|
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
|
6523 |
|
|
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
|
6524 |
|
|
|
6525 |
|
|
while (numPDisk) {
|
6526 |
|
|
if (pPDisk->PhysDiskID == id) {
|
6527 |
|
|
return 1;
|
6528 |
|
|
}
|
6529 |
|
|
pPDisk++;
|
6530 |
|
|
numPDisk--;
|
6531 |
|
|
}
|
6532 |
|
|
}
|
6533 |
|
|
return 0;
|
6534 |
|
|
}
|
6535 |
|
|
|
6536 |
|
|
/* Write SDP1 if no QAS has been enabled
|
6537 |
|
|
*/
|
6538 |
|
|
static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
|
6539 |
|
|
{
|
6540 |
|
|
VirtDevice *pTarget;
|
6541 |
|
|
int ii;
|
6542 |
|
|
|
6543 |
|
|
if (hd->Targets == NULL)
|
6544 |
|
|
return;
|
6545 |
|
|
|
6546 |
|
|
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
6547 |
|
|
if (ii == id)
|
6548 |
|
|
continue;
|
6549 |
|
|
|
6550 |
|
|
if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
|
6551 |
|
|
continue;
|
6552 |
|
|
|
6553 |
|
|
pTarget = hd->Targets[ii];
|
6554 |
|
|
|
6555 |
|
|
if ((pTarget != NULL) && (!pTarget->raidVolume)) {
|
6556 |
|
|
if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
|
6557 |
|
|
pTarget->negoFlags |= hd->ioc->spi_data.noQas;
|
6558 |
|
|
mptscsih_writeSDP1(hd, 0, ii, 0);
|
6559 |
|
|
}
|
6560 |
|
|
} else {
|
6561 |
|
|
if (mptscsih_is_phys_disk(hd->ioc, ii) == 1)
|
6562 |
|
|
mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
|
6563 |
|
|
}
|
6564 |
|
|
}
|
6565 |
|
|
return;
|
6566 |
|
|
}
|
6567 |
|
|
|
6568 |
|
|
|
6569 |
|
|
|
6570 |
|
|
#define MPT_GET_NVRAM_VALS 0x01
|
6571 |
|
|
#define MPT_UPDATE_MAX 0x02
|
6572 |
|
|
#define MPT_SET_MAX 0x04
|
6573 |
|
|
#define MPT_SET_MIN 0x08
|
6574 |
|
|
#define MPT_FALLBACK 0x10
|
6575 |
|
|
#define MPT_SAVE 0x20
|
6576 |
|
|
|
6577 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
6578 |
|
|
/**
|
6579 |
|
|
* mptscsih_doDv - Perform domain validation to a target.
|
6580 |
|
|
* @hd: Pointer to MPT_SCSI_HOST structure.
|
6581 |
|
|
* @portnum: IOC port number.
|
6582 |
|
|
* @target: Physical ID of this target
|
6583 |
|
|
*
|
6584 |
|
|
* Uses the ISR, but with special processing.
|
6585 |
|
|
* MUST be single-threaded.
|
6586 |
|
|
* Test will exit if target is at async & narrow.
|
6587 |
|
|
*
|
6588 |
|
|
* Return: None.
|
6589 |
|
|
*/
|
6590 |
|
|
static int
|
6591 |
|
|
mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
6592 |
|
|
{
|
6593 |
|
|
MPT_ADAPTER *ioc = hd->ioc;
|
6594 |
|
|
VirtDevice *pTarget;
|
6595 |
|
|
SCSIDevicePage1_t *pcfg1Data;
|
6596 |
|
|
SCSIDevicePage0_t *pcfg0Data;
|
6597 |
|
|
u8 *pbuf1;
|
6598 |
|
|
u8 *pbuf2;
|
6599 |
|
|
u8 *pDvBuf;
|
6600 |
|
|
dma_addr_t dvbuf_dma = -1;
|
6601 |
|
|
dma_addr_t buf1_dma = -1;
|
6602 |
|
|
dma_addr_t buf2_dma = -1;
|
6603 |
|
|
dma_addr_t cfg1_dma_addr = -1;
|
6604 |
|
|
dma_addr_t cfg0_dma_addr = -1;
|
6605 |
|
|
ConfigPageHeader_t header1;
|
6606 |
|
|
ConfigPageHeader_t header0;
|
6607 |
|
|
DVPARAMETERS dv;
|
6608 |
|
|
INTERNAL_CMD iocmd;
|
6609 |
|
|
CONFIGPARMS cfg;
|
6610 |
|
|
int dv_alloc = 0;
|
6611 |
|
|
int rc, sz = 0;
|
6612 |
|
|
int bufsize = 0;
|
6613 |
|
|
int dataBufSize = 0;
|
6614 |
|
|
int echoBufSize = 0;
|
6615 |
|
|
int notDone;
|
6616 |
|
|
int patt;
|
6617 |
|
|
int repeat;
|
6618 |
|
|
int retcode = 0;
|
6619 |
|
|
int nfactor = MPT_ULTRA320;
|
6620 |
|
|
char firstPass = 1;
|
6621 |
|
|
char doFallback = 0;
|
6622 |
|
|
char readPage0;
|
6623 |
|
|
char bus, lun;
|
6624 |
|
|
char inq0 = 0;
|
6625 |
|
|
|
6626 |
|
|
if (ioc->spi_data.sdp1length == 0)
|
6627 |
|
|
return 0;
|
6628 |
|
|
|
6629 |
|
|
if (ioc->spi_data.sdp0length == 0)
|
6630 |
|
|
return 0;
|
6631 |
|
|
|
6632 |
|
|
/* If multiple buses are used, require that the initiator
|
6633 |
|
|
* id be the same on all buses.
|
6634 |
|
|
*/
|
6635 |
|
|
if (id == ioc->pfacts[0].PortSCSIID)
|
6636 |
|
|
return 0;
|
6637 |
|
|
|
6638 |
|
|
lun = 0;
|
6639 |
|
|
bus = (u8) bus_number;
|
6640 |
|
|
ddvtprintk((MYIOC_s_NOTE_FMT
|
6641 |
|
|
"DV started: numIOs %d bus=%d, id %d dv @ %p\n",
|
6642 |
|
|
ioc->name, atomic_read(&queue_depth), bus, id, &dv));
|
6643 |
|
|
|
6644 |
|
|
/* Prep DV structure
|
6645 |
|
|
*/
|
6646 |
|
|
memset (&dv, 0, sizeof(DVPARAMETERS));
|
6647 |
|
|
dv.id = id;
|
6648 |
|
|
|
6649 |
|
|
/* Populate tmax with the current maximum
|
6650 |
|
|
* transfer parameters for this target.
|
6651 |
|
|
* Exit if narrow and async.
|
6652 |
|
|
*/
|
6653 |
|
|
dv.cmd = MPT_GET_NVRAM_VALS;
|
6654 |
|
|
mptscsih_dv_parms(hd, &dv, NULL);
|
6655 |
|
|
if ((!dv.max.width) && (!dv.max.offset))
|
6656 |
|
|
return 0;
|
6657 |
|
|
|
6658 |
|
|
/* Prep SCSI IO structure
|
6659 |
|
|
*/
|
6660 |
|
|
iocmd.id = id;
|
6661 |
|
|
iocmd.bus = bus;
|
6662 |
|
|
iocmd.lun = lun;
|
6663 |
|
|
iocmd.flags = 0;
|
6664 |
|
|
iocmd.physDiskNum = -1;
|
6665 |
|
|
iocmd.rsvd = iocmd.rsvd2 = 0;
|
6666 |
|
|
|
6667 |
|
|
pTarget = hd->Targets[id];
|
6668 |
|
|
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
|
6669 |
|
|
/* Another GEM workaround. Check peripheral device type,
|
6670 |
|
|
* if PROCESSOR, quit DV.
|
6671 |
|
|
*/
|
6672 |
|
|
if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
|
6673 |
|
|
pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
|
6674 |
|
|
return 0;
|
6675 |
|
|
}
|
6676 |
|
|
}
|
6677 |
|
|
|
6678 |
|
|
/* Use tagged commands if possible.
|
6679 |
|
|
*/
|
6680 |
|
|
if (pTarget) {
|
6681 |
|
|
if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
|
6682 |
|
|
iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
|
6683 |
|
|
else {
|
6684 |
|
|
if (hd->ioc->facts.FWVersion.Word < 0x01000600)
|
6685 |
|
|
return 0;
|
6686 |
|
|
|
6687 |
|
|
if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
|
6688 |
|
|
(hd->ioc->facts.FWVersion.Word < 0x01010B00))
|
6689 |
|
|
return 0;
|
6690 |
|
|
}
|
6691 |
|
|
}
|
6692 |
|
|
|
6693 |
|
|
/* Prep cfg structure
|
6694 |
|
|
*/
|
6695 |
|
|
cfg.pageAddr = (bus<<8) | id;
|
6696 |
|
|
cfg.hdr = NULL;
|
6697 |
|
|
|
6698 |
|
|
/* Prep SDP0 header
|
6699 |
|
|
*/
|
6700 |
|
|
header0.PageVersion = ioc->spi_data.sdp0version;
|
6701 |
|
|
header0.PageLength = ioc->spi_data.sdp0length;
|
6702 |
|
|
header0.PageNumber = 0;
|
6703 |
|
|
header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
|
6704 |
|
|
|
6705 |
|
|
/* Prep SDP1 header
|
6706 |
|
|
*/
|
6707 |
|
|
header1.PageVersion = ioc->spi_data.sdp1version;
|
6708 |
|
|
header1.PageLength = ioc->spi_data.sdp1length;
|
6709 |
|
|
header1.PageNumber = 1;
|
6710 |
|
|
header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
|
6711 |
|
|
|
6712 |
|
|
if (header0.PageLength & 1)
|
6713 |
|
|
dv_alloc = (header0.PageLength * 4) + 4;
|
6714 |
|
|
|
6715 |
|
|
dv_alloc += (2048 + (header1.PageLength * 4));
|
6716 |
|
|
|
6717 |
|
|
pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
|
6718 |
|
|
if (pDvBuf == NULL)
|
6719 |
|
|
return 0;
|
6720 |
|
|
|
6721 |
|
|
sz = 0;
|
6722 |
|
|
pbuf1 = (u8 *)pDvBuf;
|
6723 |
|
|
buf1_dma = dvbuf_dma;
|
6724 |
|
|
sz +=1024;
|
6725 |
|
|
|
6726 |
|
|
pbuf2 = (u8 *) (pDvBuf + sz);
|
6727 |
|
|
buf2_dma = dvbuf_dma + sz;
|
6728 |
|
|
sz +=1024;
|
6729 |
|
|
|
6730 |
|
|
pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
|
6731 |
|
|
cfg0_dma_addr = dvbuf_dma + sz;
|
6732 |
|
|
sz += header0.PageLength * 4;
|
6733 |
|
|
|
6734 |
|
|
/* 8-byte alignment
|
6735 |
|
|
*/
|
6736 |
|
|
if (header0.PageLength & 1)
|
6737 |
|
|
sz += 4;
|
6738 |
|
|
|
6739 |
|
|
pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
|
6740 |
|
|
cfg1_dma_addr = dvbuf_dma + sz;
|
6741 |
|
|
|
6742 |
|
|
/* Skip this ID? Set cfg.hdr to force config page write
|
6743 |
|
|
*/
|
6744 |
|
|
{
|
6745 |
|
|
ScsiCfgData *pspi_data = &hd->ioc->spi_data;
|
6746 |
|
|
if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
6747 |
|
|
/* Set the factor from nvram */
|
6748 |
|
|
nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
|
6749 |
|
|
if (nfactor < pspi_data->minSyncFactor )
|
6750 |
|
|
nfactor = pspi_data->minSyncFactor;
|
6751 |
|
|
|
6752 |
|
|
if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
|
6753 |
|
|
(pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
|
6754 |
|
|
|
6755 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
|
6756 |
|
|
ioc->name, bus, id, lun));
|
6757 |
|
|
|
6758 |
|
|
dv.cmd = MPT_SET_MAX;
|
6759 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
6760 |
|
|
cfg.hdr = &header1;
|
6761 |
|
|
|
6762 |
|
|
/* Save the final negotiated settings to
|
6763 |
|
|
* SCSI device page 1.
|
6764 |
|
|
*/
|
6765 |
|
|
cfg.physAddr = cfg1_dma_addr;
|
6766 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
6767 |
|
|
cfg.dir = 1;
|
6768 |
|
|
mpt_config(hd->ioc, &cfg);
|
6769 |
|
|
goto target_done;
|
6770 |
|
|
}
|
6771 |
|
|
}
|
6772 |
|
|
}
|
6773 |
|
|
|
6774 |
|
|
/* Finish iocmd inititialization - hidden or visible disk? */
|
6775 |
|
|
if (ioc->spi_data.pIocPg3) {
|
6776 |
|
|
/* Searc IOC page 3 for matching id
|
6777 |
|
|
*/
|
6778 |
|
|
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
|
6779 |
|
|
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
|
6780 |
|
|
|
6781 |
|
|
while (numPDisk) {
|
6782 |
|
|
if (pPDisk->PhysDiskID == id) {
|
6783 |
|
|
/* match */
|
6784 |
|
|
iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
|
6785 |
|
|
iocmd.physDiskNum = pPDisk->PhysDiskNum;
|
6786 |
|
|
|
6787 |
|
|
/* Quiesce the IM
|
6788 |
|
|
*/
|
6789 |
|
|
if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
|
6790 |
|
|
ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
|
6791 |
|
|
goto target_done;
|
6792 |
|
|
}
|
6793 |
|
|
break;
|
6794 |
|
|
}
|
6795 |
|
|
pPDisk++;
|
6796 |
|
|
numPDisk--;
|
6797 |
|
|
}
|
6798 |
|
|
}
|
6799 |
|
|
|
6800 |
|
|
/* RAID Volume ID's may double for a physical device. If RAID but
|
6801 |
|
|
* not a physical ID as well, skip DV.
|
6802 |
|
|
*/
|
6803 |
|
|
if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
|
6804 |
|
|
goto target_done;
|
6805 |
|
|
|
6806 |
|
|
|
6807 |
|
|
/* Basic Test.
|
6808 |
|
|
* Async & Narrow - Inquiry
|
6809 |
|
|
* Async & Narrow - Inquiry
|
6810 |
|
|
* Maximum transfer rate - Inquiry
|
6811 |
|
|
* Compare buffers:
|
6812 |
|
|
* If compare, test complete.
|
6813 |
|
|
* If miscompare and first pass, repeat
|
6814 |
|
|
* If miscompare and not first pass, fall back and repeat
|
6815 |
|
|
*/
|
6816 |
|
|
hd->pLocal = NULL;
|
6817 |
|
|
readPage0 = 0;
|
6818 |
|
|
sz = SCSI_STD_INQUIRY_BYTES;
|
6819 |
|
|
rc = MPT_SCANDV_GOOD;
|
6820 |
|
|
while (1) {
|
6821 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
|
6822 |
|
|
retcode = 0;
|
6823 |
|
|
dv.cmd = MPT_SET_MIN;
|
6824 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
6825 |
|
|
|
6826 |
|
|
cfg.hdr = &header1;
|
6827 |
|
|
cfg.physAddr = cfg1_dma_addr;
|
6828 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
6829 |
|
|
cfg.dir = 1;
|
6830 |
|
|
if (mpt_config(hd->ioc, &cfg) != 0)
|
6831 |
|
|
goto target_done;
|
6832 |
|
|
|
6833 |
|
|
/* Wide - narrow - wide workaround case
|
6834 |
|
|
*/
|
6835 |
|
|
if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
|
6836 |
|
|
/* Send an untagged command to reset disk Qs corrupted
|
6837 |
|
|
* when a parity error occurs on a Request Sense.
|
6838 |
|
|
*/
|
6839 |
|
|
if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
|
6840 |
|
|
((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
|
6841 |
|
|
(hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
|
6842 |
|
|
|
6843 |
|
|
iocmd.cmd = CMD_RequestSense;
|
6844 |
|
|
iocmd.data_dma = buf1_dma;
|
6845 |
|
|
iocmd.data = pbuf1;
|
6846 |
|
|
iocmd.size = 0x12;
|
6847 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
6848 |
|
|
goto target_done;
|
6849 |
|
|
else {
|
6850 |
|
|
if (hd->pLocal == NULL)
|
6851 |
|
|
goto target_done;
|
6852 |
|
|
rc = hd->pLocal->completion;
|
6853 |
|
|
if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
|
6854 |
|
|
dv.max.width = 0;
|
6855 |
|
|
doFallback = 0;
|
6856 |
|
|
} else
|
6857 |
|
|
goto target_done;
|
6858 |
|
|
}
|
6859 |
|
|
} else
|
6860 |
|
|
goto target_done;
|
6861 |
|
|
}
|
6862 |
|
|
|
6863 |
|
|
iocmd.cmd = CMD_Inquiry;
|
6864 |
|
|
iocmd.data_dma = buf1_dma;
|
6865 |
|
|
iocmd.data = pbuf1;
|
6866 |
|
|
iocmd.size = sz;
|
6867 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
6868 |
|
|
goto target_done;
|
6869 |
|
|
else {
|
6870 |
|
|
if (hd->pLocal == NULL)
|
6871 |
|
|
goto target_done;
|
6872 |
|
|
rc = hd->pLocal->completion;
|
6873 |
|
|
if (rc == MPT_SCANDV_GOOD) {
|
6874 |
|
|
if (hd->pLocal->scsiStatus == STS_BUSY) {
|
6875 |
|
|
if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
|
6876 |
|
|
retcode = 1;
|
6877 |
|
|
else
|
6878 |
|
|
retcode = 0;
|
6879 |
|
|
|
6880 |
|
|
goto target_done;
|
6881 |
|
|
}
|
6882 |
|
|
} else if (rc == MPT_SCANDV_SENSE) {
|
6883 |
|
|
;
|
6884 |
|
|
} else {
|
6885 |
|
|
/* If first command doesn't complete
|
6886 |
|
|
* with a good status or with a check condition,
|
6887 |
|
|
* exit.
|
6888 |
|
|
*/
|
6889 |
|
|
goto target_done;
|
6890 |
|
|
}
|
6891 |
|
|
}
|
6892 |
|
|
|
6893 |
|
|
/* Reset the size for disks
|
6894 |
|
|
*/
|
6895 |
|
|
inq0 = (*pbuf1) & 0x1F;
|
6896 |
|
|
if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
|
6897 |
|
|
sz = 0x40;
|
6898 |
|
|
iocmd.size = sz;
|
6899 |
|
|
}
|
6900 |
|
|
|
6901 |
|
|
/* Another GEM workaround. Check peripheral device type,
|
6902 |
|
|
* if PROCESSOR, quit DV.
|
6903 |
|
|
*/
|
6904 |
|
|
if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08))
|
6905 |
|
|
goto target_done;
|
6906 |
|
|
|
6907 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
6908 |
|
|
goto target_done;
|
6909 |
|
|
|
6910 |
|
|
if (sz == 0x40) {
|
6911 |
|
|
if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
|
6912 |
|
|
&& (pTarget->minSyncFactor > 0x09)) {
|
6913 |
|
|
if ((pbuf1[56] & 0x04) == 0)
|
6914 |
|
|
;
|
6915 |
|
|
else if ((pbuf1[56] & 0x01) == 1) {
|
6916 |
|
|
pTarget->minSyncFactor = nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
|
6917 |
|
|
} else {
|
6918 |
|
|
pTarget->minSyncFactor = nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
|
6919 |
|
|
}
|
6920 |
|
|
|
6921 |
|
|
dv.max.factor = pTarget->minSyncFactor;
|
6922 |
|
|
|
6923 |
|
|
if ((pbuf1[56] & 0x02) == 0) {
|
6924 |
|
|
pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
|
6925 |
|
|
hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
|
6926 |
|
|
}
|
6927 |
|
|
}
|
6928 |
|
|
}
|
6929 |
|
|
|
6930 |
|
|
if (doFallback)
|
6931 |
|
|
dv.cmd = MPT_FALLBACK;
|
6932 |
|
|
else
|
6933 |
|
|
dv.cmd = MPT_SET_MAX;
|
6934 |
|
|
|
6935 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
6936 |
|
|
if (mpt_config(hd->ioc, &cfg) != 0)
|
6937 |
|
|
goto target_done;
|
6938 |
|
|
|
6939 |
|
|
if ((!dv.now.width) && (!dv.now.offset))
|
6940 |
|
|
goto target_done;
|
6941 |
|
|
|
6942 |
|
|
iocmd.cmd = CMD_Inquiry;
|
6943 |
|
|
iocmd.data_dma = buf2_dma;
|
6944 |
|
|
iocmd.data = pbuf2;
|
6945 |
|
|
iocmd.size = sz;
|
6946 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
6947 |
|
|
goto target_done;
|
6948 |
|
|
else if (hd->pLocal == NULL)
|
6949 |
|
|
goto target_done;
|
6950 |
|
|
else {
|
6951 |
|
|
/* Save the return code.
|
6952 |
|
|
* If this is the first pass,
|
6953 |
|
|
* read SCSI Device Page 0
|
6954 |
|
|
* and update the target max parameters.
|
6955 |
|
|
*/
|
6956 |
|
|
rc = hd->pLocal->completion;
|
6957 |
|
|
doFallback = 0;
|
6958 |
|
|
if (rc == MPT_SCANDV_GOOD) {
|
6959 |
|
|
if (!readPage0) {
|
6960 |
|
|
u32 sdp0_info;
|
6961 |
|
|
u32 sdp0_nego;
|
6962 |
|
|
|
6963 |
|
|
cfg.hdr = &header0;
|
6964 |
|
|
cfg.physAddr = cfg0_dma_addr;
|
6965 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
6966 |
|
|
cfg.dir = 0;
|
6967 |
|
|
|
6968 |
|
|
if (mpt_config(hd->ioc, &cfg) != 0)
|
6969 |
|
|
goto target_done;
|
6970 |
|
|
|
6971 |
|
|
sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
|
6972 |
|
|
sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
|
6973 |
|
|
|
6974 |
|
|
/* Quantum and Fujitsu workarounds.
|
6975 |
|
|
* Quantum: PPR U320 -> PPR reply with Ultra2 and wide
|
6976 |
|
|
* Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
|
6977 |
|
|
* Resetart with a request for U160.
|
6978 |
|
|
*/
|
6979 |
|
|
if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
|
6980 |
|
|
doFallback = 1;
|
6981 |
|
|
} else {
|
6982 |
|
|
dv.cmd = MPT_UPDATE_MAX;
|
6983 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
|
6984 |
|
|
/* Update the SCSI device page 1 area
|
6985 |
|
|
*/
|
6986 |
|
|
pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
|
6987 |
|
|
readPage0 = 1;
|
6988 |
|
|
}
|
6989 |
|
|
}
|
6990 |
|
|
|
6991 |
|
|
/* Quantum workaround. Restart this test will the fallback
|
6992 |
|
|
* flag set.
|
6993 |
|
|
*/
|
6994 |
|
|
if (doFallback == 0) {
|
6995 |
|
|
if (memcmp(pbuf1, pbuf2, sz) != 0) {
|
6996 |
|
|
if (!firstPass)
|
6997 |
|
|
doFallback = 1;
|
6998 |
|
|
} else
|
6999 |
|
|
break; /* test complete */
|
7000 |
|
|
}
|
7001 |
|
|
|
7002 |
|
|
|
7003 |
|
|
} else if (rc == MPT_SCANDV_ISSUE_SENSE)
|
7004 |
|
|
doFallback = 1; /* set fallback flag */
|
7005 |
|
|
else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
|
7006 |
|
|
doFallback = 1; /* set fallback flag */
|
7007 |
|
|
else
|
7008 |
|
|
goto target_done;
|
7009 |
|
|
|
7010 |
|
|
firstPass = 0;
|
7011 |
|
|
}
|
7012 |
|
|
}
|
7013 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name));
|
7014 |
|
|
inq0 = (*pbuf1) & 0x1F;
|
7015 |
|
|
|
7016 |
|
|
/* Continue only for disks
|
7017 |
|
|
*/
|
7018 |
|
|
if (inq0 != 0)
|
7019 |
|
|
goto target_done;
|
7020 |
|
|
|
7021 |
|
|
if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
|
7022 |
|
|
goto target_done;
|
7023 |
|
|
|
7024 |
|
|
/* Start the Enhanced Test.
|
7025 |
|
|
* 0) issue TUR to clear out check conditions
|
7026 |
|
|
* 1) read capacity of echo (regular) buffer
|
7027 |
|
|
* 2) reserve device
|
7028 |
|
|
* 3) do write-read-compare data pattern test
|
7029 |
|
|
* 4) release
|
7030 |
|
|
* 5) update nego parms to target struct
|
7031 |
|
|
*/
|
7032 |
|
|
cfg.hdr = &header1;
|
7033 |
|
|
cfg.physAddr = cfg1_dma_addr;
|
7034 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
7035 |
|
|
cfg.dir = 1;
|
7036 |
|
|
|
7037 |
|
|
iocmd.cmd = CMD_TestUnitReady;
|
7038 |
|
|
iocmd.data_dma = -1;
|
7039 |
|
|
iocmd.data = NULL;
|
7040 |
|
|
iocmd.size = 0;
|
7041 |
|
|
notDone = 1;
|
7042 |
|
|
while (notDone) {
|
7043 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7044 |
|
|
goto target_done;
|
7045 |
|
|
|
7046 |
|
|
if (hd->pLocal == NULL)
|
7047 |
|
|
goto target_done;
|
7048 |
|
|
|
7049 |
|
|
rc = hd->pLocal->completion;
|
7050 |
|
|
if (rc == MPT_SCANDV_GOOD)
|
7051 |
|
|
notDone = 0;
|
7052 |
|
|
else if (rc == MPT_SCANDV_SENSE) {
|
7053 |
|
|
u8 skey = hd->pLocal->sense[2] & 0x0F;
|
7054 |
|
|
u8 asc = hd->pLocal->sense[12];
|
7055 |
|
|
u8 ascq = hd->pLocal->sense[13];
|
7056 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
7057 |
|
|
"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
|
7058 |
|
|
ioc->name, skey, asc, ascq));
|
7059 |
|
|
|
7060 |
|
|
if (skey == SK_UNIT_ATTENTION)
|
7061 |
|
|
notDone++; /* repeat */
|
7062 |
|
|
else if ((skey == SK_NOT_READY) &&
|
7063 |
|
|
(asc == 0x04)&&(ascq == 0x01)) {
|
7064 |
|
|
/* wait then repeat */
|
7065 |
|
|
mdelay (2000);
|
7066 |
|
|
notDone++;
|
7067 |
|
|
} else if ((skey == SK_NOT_READY) && (asc == 0x3A)) {
|
7068 |
|
|
/* no medium, try read test anyway */
|
7069 |
|
|
notDone = 0;
|
7070 |
|
|
} else {
|
7071 |
|
|
/* All other errors are fatal.
|
7072 |
|
|
*/
|
7073 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
|
7074 |
|
|
ioc->name));
|
7075 |
|
|
goto target_done;
|
7076 |
|
|
}
|
7077 |
|
|
} else
|
7078 |
|
|
goto target_done;
|
7079 |
|
|
}
|
7080 |
|
|
|
7081 |
|
|
iocmd.cmd = CMD_ReadBuffer;
|
7082 |
|
|
iocmd.data_dma = buf1_dma;
|
7083 |
|
|
iocmd.data = pbuf1;
|
7084 |
|
|
iocmd.size = 4;
|
7085 |
|
|
iocmd.flags |= MPT_ICFLAG_BUF_CAP;
|
7086 |
|
|
|
7087 |
|
|
dataBufSize = 0;
|
7088 |
|
|
echoBufSize = 0;
|
7089 |
|
|
for (patt = 0; patt < 2; patt++) {
|
7090 |
|
|
if (patt == 0)
|
7091 |
|
|
iocmd.flags |= MPT_ICFLAG_ECHO;
|
7092 |
|
|
else
|
7093 |
|
|
iocmd.flags &= ~MPT_ICFLAG_ECHO;
|
7094 |
|
|
|
7095 |
|
|
notDone = 1;
|
7096 |
|
|
while (notDone) {
|
7097 |
|
|
bufsize = 0;
|
7098 |
|
|
|
7099 |
|
|
/* If not ready after 8 trials,
|
7100 |
|
|
* give up on this device.
|
7101 |
|
|
*/
|
7102 |
|
|
if (notDone > 8)
|
7103 |
|
|
goto target_done;
|
7104 |
|
|
|
7105 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7106 |
|
|
goto target_done;
|
7107 |
|
|
else if (hd->pLocal == NULL)
|
7108 |
|
|
goto target_done;
|
7109 |
|
|
else {
|
7110 |
|
|
rc = hd->pLocal->completion;
|
7111 |
|
|
ddvprintk(("ReadBuffer Comp Code %d", rc));
|
7112 |
|
|
ddvprintk((" buff: %0x %0x %0x %0x\n",
|
7113 |
|
|
pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
|
7114 |
|
|
|
7115 |
|
|
if (rc == MPT_SCANDV_GOOD) {
|
7116 |
|
|
notDone = 0;
|
7117 |
|
|
if (iocmd.flags & MPT_ICFLAG_ECHO) {
|
7118 |
|
|
bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
|
7119 |
|
|
} else {
|
7120 |
|
|
bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
|
7121 |
|
|
}
|
7122 |
|
|
} else if (rc == MPT_SCANDV_SENSE) {
|
7123 |
|
|
u8 skey = hd->pLocal->sense[2] & 0x0F;
|
7124 |
|
|
u8 asc = hd->pLocal->sense[12];
|
7125 |
|
|
u8 ascq = hd->pLocal->sense[13];
|
7126 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
7127 |
|
|
"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
|
7128 |
|
|
ioc->name, skey, asc, ascq));
|
7129 |
|
|
if (skey == SK_ILLEGAL_REQUEST) {
|
7130 |
|
|
notDone = 0;
|
7131 |
|
|
} else if (skey == SK_UNIT_ATTENTION) {
|
7132 |
|
|
notDone++; /* repeat */
|
7133 |
|
|
} else if ((skey == SK_NOT_READY) &&
|
7134 |
|
|
(asc == 0x04)&&(ascq == 0x01)) {
|
7135 |
|
|
/* wait then repeat */
|
7136 |
|
|
mdelay (2000);
|
7137 |
|
|
notDone++;
|
7138 |
|
|
} else {
|
7139 |
|
|
/* All other errors are fatal.
|
7140 |
|
|
*/
|
7141 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
|
7142 |
|
|
ioc->name));
|
7143 |
|
|
goto target_done;
|
7144 |
|
|
}
|
7145 |
|
|
} else {
|
7146 |
|
|
/* All other errors are fatal
|
7147 |
|
|
*/
|
7148 |
|
|
goto target_done;
|
7149 |
|
|
}
|
7150 |
|
|
}
|
7151 |
|
|
}
|
7152 |
|
|
|
7153 |
|
|
if (iocmd.flags & MPT_ICFLAG_ECHO)
|
7154 |
|
|
echoBufSize = bufsize;
|
7155 |
|
|
else
|
7156 |
|
|
dataBufSize = bufsize;
|
7157 |
|
|
}
|
7158 |
|
|
sz = 0;
|
7159 |
|
|
iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
|
7160 |
|
|
|
7161 |
|
|
/* Use echo buffers if possible,
|
7162 |
|
|
* Exit if both buffers are 0.
|
7163 |
|
|
*/
|
7164 |
|
|
if (echoBufSize > 0) {
|
7165 |
|
|
iocmd.flags |= MPT_ICFLAG_ECHO;
|
7166 |
|
|
if (dataBufSize > 0)
|
7167 |
|
|
bufsize = MIN(echoBufSize, dataBufSize);
|
7168 |
|
|
else
|
7169 |
|
|
bufsize = echoBufSize;
|
7170 |
|
|
} else if (dataBufSize == 0)
|
7171 |
|
|
goto target_done;
|
7172 |
|
|
|
7173 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
|
7174 |
|
|
(iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
|
7175 |
|
|
|
7176 |
|
|
/* Data buffers for write-read-compare test max 1K.
|
7177 |
|
|
*/
|
7178 |
|
|
sz = MIN(bufsize, 1024);
|
7179 |
|
|
|
7180 |
|
|
/* --- loop ----
|
7181 |
|
|
* On first pass, always issue a reserve.
|
7182 |
|
|
* On additional loops, only if a reset has occurred.
|
7183 |
|
|
* iocmd.flags indicates if echo or regular buffer
|
7184 |
|
|
*/
|
7185 |
|
|
for (patt = 0; patt < 4; patt++) {
|
7186 |
|
|
ddvprintk(("Pattern %d\n", patt));
|
7187 |
|
|
if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
|
7188 |
|
|
iocmd.cmd = CMD_TestUnitReady;
|
7189 |
|
|
iocmd.data_dma = -1;
|
7190 |
|
|
iocmd.data = NULL;
|
7191 |
|
|
iocmd.size = 0;
|
7192 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7193 |
|
|
goto target_done;
|
7194 |
|
|
|
7195 |
|
|
iocmd.cmd = CMD_Release6;
|
7196 |
|
|
iocmd.data_dma = -1;
|
7197 |
|
|
iocmd.data = NULL;
|
7198 |
|
|
iocmd.size = 0;
|
7199 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7200 |
|
|
goto target_done;
|
7201 |
|
|
else if (hd->pLocal == NULL)
|
7202 |
|
|
goto target_done;
|
7203 |
|
|
else {
|
7204 |
|
|
rc = hd->pLocal->completion;
|
7205 |
|
|
ddvprintk(("Release rc %d\n", rc));
|
7206 |
|
|
if (rc == MPT_SCANDV_GOOD)
|
7207 |
|
|
iocmd.flags &= ~MPT_ICFLAG_RESERVED;
|
7208 |
|
|
else
|
7209 |
|
|
goto target_done;
|
7210 |
|
|
}
|
7211 |
|
|
iocmd.flags &= ~MPT_ICFLAG_RESERVED;
|
7212 |
|
|
}
|
7213 |
|
|
iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
|
7214 |
|
|
|
7215 |
|
|
repeat = 5;
|
7216 |
|
|
while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
|
7217 |
|
|
iocmd.cmd = CMD_Reserve6;
|
7218 |
|
|
iocmd.data_dma = -1;
|
7219 |
|
|
iocmd.data = NULL;
|
7220 |
|
|
iocmd.size = 0;
|
7221 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7222 |
|
|
goto target_done;
|
7223 |
|
|
else if (hd->pLocal == NULL)
|
7224 |
|
|
goto target_done;
|
7225 |
|
|
else {
|
7226 |
|
|
rc = hd->pLocal->completion;
|
7227 |
|
|
if (rc == MPT_SCANDV_GOOD) {
|
7228 |
|
|
iocmd.flags |= MPT_ICFLAG_RESERVED;
|
7229 |
|
|
} else if (rc == MPT_SCANDV_SENSE) {
|
7230 |
|
|
/* Wait if coming ready
|
7231 |
|
|
*/
|
7232 |
|
|
u8 skey = hd->pLocal->sense[2] & 0x0F;
|
7233 |
|
|
u8 asc = hd->pLocal->sense[12];
|
7234 |
|
|
u8 ascq = hd->pLocal->sense[13];
|
7235 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
7236 |
|
|
"DV: Reserve Failed: ", ioc->name));
|
7237 |
|
|
ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
|
7238 |
|
|
skey, asc, ascq));
|
7239 |
|
|
|
7240 |
|
|
if ((skey == SK_NOT_READY) && (asc == 0x04)&&
|
7241 |
|
|
(ascq == 0x01)) {
|
7242 |
|
|
/* wait then repeat */
|
7243 |
|
|
mdelay (2000);
|
7244 |
|
|
notDone++;
|
7245 |
|
|
} else {
|
7246 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
7247 |
|
|
"DV: Reserved Failed.", ioc->name));
|
7248 |
|
|
goto target_done;
|
7249 |
|
|
}
|
7250 |
|
|
} else {
|
7251 |
|
|
ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
|
7252 |
|
|
ioc->name));
|
7253 |
|
|
goto target_done;
|
7254 |
|
|
}
|
7255 |
|
|
}
|
7256 |
|
|
}
|
7257 |
|
|
|
7258 |
|
|
mptscsih_fillbuf(pbuf1, sz, patt, 1);
|
7259 |
|
|
iocmd.cmd = CMD_WriteBuffer;
|
7260 |
|
|
iocmd.data_dma = buf1_dma;
|
7261 |
|
|
iocmd.data = pbuf1;
|
7262 |
|
|
iocmd.size = sz;
|
7263 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7264 |
|
|
goto target_done;
|
7265 |
|
|
else if (hd->pLocal == NULL)
|
7266 |
|
|
goto target_done;
|
7267 |
|
|
else {
|
7268 |
|
|
rc = hd->pLocal->completion;
|
7269 |
|
|
if (rc == MPT_SCANDV_GOOD)
|
7270 |
|
|
; /* Issue read buffer */
|
7271 |
|
|
else if (rc == MPT_SCANDV_DID_RESET) {
|
7272 |
|
|
/* If using echo buffers, reset to data buffers.
|
7273 |
|
|
* Else do Fallback and restart
|
7274 |
|
|
* this test (re-issue reserve
|
7275 |
|
|
* because of bus reset).
|
7276 |
|
|
*/
|
7277 |
|
|
if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
|
7278 |
|
|
iocmd.flags &= ~MPT_ICFLAG_ECHO;
|
7279 |
|
|
} else {
|
7280 |
|
|
dv.cmd = MPT_FALLBACK;
|
7281 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
7282 |
|
|
|
7283 |
|
|
if (mpt_config(hd->ioc, &cfg) != 0)
|
7284 |
|
|
goto target_done;
|
7285 |
|
|
|
7286 |
|
|
if ((!dv.now.width) && (!dv.now.offset))
|
7287 |
|
|
goto target_done;
|
7288 |
|
|
}
|
7289 |
|
|
|
7290 |
|
|
iocmd.flags |= MPT_ICFLAG_DID_RESET;
|
7291 |
|
|
patt = -1;
|
7292 |
|
|
continue;
|
7293 |
|
|
} else if (rc == MPT_SCANDV_SENSE) {
|
7294 |
|
|
/* Restart data test if UA, else quit.
|
7295 |
|
|
*/
|
7296 |
|
|
u8 skey = hd->pLocal->sense[2] & 0x0F;
|
7297 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
7298 |
|
|
"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
|
7299 |
|
|
hd->pLocal->sense[12], hd->pLocal->sense[13]));
|
7300 |
|
|
if (skey == SK_UNIT_ATTENTION) {
|
7301 |
|
|
patt = -1;
|
7302 |
|
|
continue;
|
7303 |
|
|
} else if (skey == SK_ILLEGAL_REQUEST) {
|
7304 |
|
|
if (iocmd.flags & MPT_ICFLAG_ECHO) {
|
7305 |
|
|
if (dataBufSize >= bufsize) {
|
7306 |
|
|
iocmd.flags &= ~MPT_ICFLAG_ECHO;
|
7307 |
|
|
patt = -1;
|
7308 |
|
|
continue;
|
7309 |
|
|
}
|
7310 |
|
|
}
|
7311 |
|
|
goto target_done;
|
7312 |
|
|
}
|
7313 |
|
|
else
|
7314 |
|
|
goto target_done;
|
7315 |
|
|
} else {
|
7316 |
|
|
/* fatal error */
|
7317 |
|
|
goto target_done;
|
7318 |
|
|
}
|
7319 |
|
|
}
|
7320 |
|
|
|
7321 |
|
|
iocmd.cmd = CMD_ReadBuffer;
|
7322 |
|
|
iocmd.data_dma = buf2_dma;
|
7323 |
|
|
iocmd.data = pbuf2;
|
7324 |
|
|
iocmd.size = sz;
|
7325 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7326 |
|
|
goto target_done;
|
7327 |
|
|
else if (hd->pLocal == NULL)
|
7328 |
|
|
goto target_done;
|
7329 |
|
|
else {
|
7330 |
|
|
rc = hd->pLocal->completion;
|
7331 |
|
|
if (rc == MPT_SCANDV_GOOD) {
|
7332 |
|
|
/* If buffers compare,
|
7333 |
|
|
* go to next pattern,
|
7334 |
|
|
* else, do a fallback and restart
|
7335 |
|
|
* data transfer test.
|
7336 |
|
|
*/
|
7337 |
|
|
if (memcmp (pbuf1, pbuf2, sz) == 0) {
|
7338 |
|
|
; /* goto next pattern */
|
7339 |
|
|
} else {
|
7340 |
|
|
/* Miscompare with Echo buffer, go to data buffer,
|
7341 |
|
|
* if that buffer exists.
|
7342 |
|
|
* Miscompare with Data buffer, check first 4 bytes,
|
7343 |
|
|
* some devices return capacity. Exit in this case.
|
7344 |
|
|
*/
|
7345 |
|
|
if (iocmd.flags & MPT_ICFLAG_ECHO) {
|
7346 |
|
|
if (dataBufSize >= bufsize)
|
7347 |
|
|
iocmd.flags &= ~MPT_ICFLAG_ECHO;
|
7348 |
|
|
else
|
7349 |
|
|
goto target_done;
|
7350 |
|
|
} else {
|
7351 |
|
|
if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
|
7352 |
|
|
/* Argh. Device returning wrong data.
|
7353 |
|
|
* Quit DV for this device.
|
7354 |
|
|
*/
|
7355 |
|
|
goto target_done;
|
7356 |
|
|
}
|
7357 |
|
|
|
7358 |
|
|
/* Had an actual miscompare. Slow down.*/
|
7359 |
|
|
dv.cmd = MPT_FALLBACK;
|
7360 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
7361 |
|
|
|
7362 |
|
|
if (mpt_config(hd->ioc, &cfg) != 0)
|
7363 |
|
|
goto target_done;
|
7364 |
|
|
|
7365 |
|
|
if ((!dv.now.width) && (!dv.now.offset))
|
7366 |
|
|
goto target_done;
|
7367 |
|
|
}
|
7368 |
|
|
|
7369 |
|
|
patt = -1;
|
7370 |
|
|
continue;
|
7371 |
|
|
}
|
7372 |
|
|
} else if (rc == MPT_SCANDV_DID_RESET) {
|
7373 |
|
|
/* Do Fallback and restart
|
7374 |
|
|
* this test (re-issue reserve
|
7375 |
|
|
* because of bus reset).
|
7376 |
|
|
*/
|
7377 |
|
|
dv.cmd = MPT_FALLBACK;
|
7378 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
7379 |
|
|
|
7380 |
|
|
if (mpt_config(hd->ioc, &cfg) != 0)
|
7381 |
|
|
goto target_done;
|
7382 |
|
|
|
7383 |
|
|
if ((!dv.now.width) && (!dv.now.offset))
|
7384 |
|
|
goto target_done;
|
7385 |
|
|
|
7386 |
|
|
iocmd.flags |= MPT_ICFLAG_DID_RESET;
|
7387 |
|
|
patt = -1;
|
7388 |
|
|
continue;
|
7389 |
|
|
} else if (rc == MPT_SCANDV_SENSE) {
|
7390 |
|
|
/* Restart data test if UA, else quit.
|
7391 |
|
|
*/
|
7392 |
|
|
u8 skey = hd->pLocal->sense[2] & 0x0F;
|
7393 |
|
|
ddvprintk((MYIOC_s_INFO_FMT
|
7394 |
|
|
"SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
|
7395 |
|
|
hd->pLocal->sense[12], hd->pLocal->sense[13]));
|
7396 |
|
|
if (skey == SK_UNIT_ATTENTION) {
|
7397 |
|
|
patt = -1;
|
7398 |
|
|
continue;
|
7399 |
|
|
}
|
7400 |
|
|
else
|
7401 |
|
|
goto target_done;
|
7402 |
|
|
} else {
|
7403 |
|
|
/* fatal error */
|
7404 |
|
|
goto target_done;
|
7405 |
|
|
}
|
7406 |
|
|
}
|
7407 |
|
|
|
7408 |
|
|
} /* --- end of patt loop ---- */
|
7409 |
|
|
|
7410 |
|
|
target_done:
|
7411 |
|
|
if (iocmd.flags & MPT_ICFLAG_RESERVED) {
|
7412 |
|
|
iocmd.cmd = CMD_Release6;
|
7413 |
|
|
iocmd.data_dma = -1;
|
7414 |
|
|
iocmd.data = NULL;
|
7415 |
|
|
iocmd.size = 0;
|
7416 |
|
|
if (mptscsih_do_cmd(hd, &iocmd) < 0)
|
7417 |
|
|
printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
|
7418 |
|
|
ioc->name, id);
|
7419 |
|
|
else if (hd->pLocal) {
|
7420 |
|
|
if (hd->pLocal->completion == MPT_SCANDV_GOOD)
|
7421 |
|
|
iocmd.flags &= ~MPT_ICFLAG_RESERVED;
|
7422 |
|
|
} else {
|
7423 |
|
|
printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
|
7424 |
|
|
ioc->name, id);
|
7425 |
|
|
}
|
7426 |
|
|
}
|
7427 |
|
|
|
7428 |
|
|
|
7429 |
|
|
/* Set if cfg1_dma_addr contents is valid
|
7430 |
|
|
*/
|
7431 |
|
|
if ((cfg.hdr != NULL) && (retcode == 0)){
|
7432 |
|
|
/* If disk, not U320, disable QAS
|
7433 |
|
|
*/
|
7434 |
|
|
if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
|
7435 |
|
|
hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
|
7436 |
|
|
|
7437 |
|
|
dv.cmd = MPT_SAVE;
|
7438 |
|
|
mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
|
7439 |
|
|
|
7440 |
|
|
/* Double writes to SDP1 can cause problems,
|
7441 |
|
|
* skip save of the final negotiated settings to
|
7442 |
|
|
* SCSI device page 1.
|
7443 |
|
|
*
|
7444 |
|
|
cfg.hdr = &header1;
|
7445 |
|
|
cfg.physAddr = cfg1_dma_addr;
|
7446 |
|
|
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
7447 |
|
|
cfg.dir = 1;
|
7448 |
|
|
mpt_config(hd->ioc, &cfg);
|
7449 |
|
|
*/
|
7450 |
|
|
}
|
7451 |
|
|
|
7452 |
|
|
/* If this is a RAID Passthrough, enable internal IOs
|
7453 |
|
|
*/
|
7454 |
|
|
if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
|
7455 |
|
|
if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
|
7456 |
|
|
ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
|
7457 |
|
|
}
|
7458 |
|
|
|
7459 |
|
|
/* Done with the DV scan of the current target
|
7460 |
|
|
*/
|
7461 |
|
|
if (pDvBuf)
|
7462 |
|
|
pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
|
7463 |
|
|
|
7464 |
|
|
ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
|
7465 |
|
|
ioc->name, atomic_read(&queue_depth)));
|
7466 |
|
|
|
7467 |
|
|
return retcode;
|
7468 |
|
|
}
|
7469 |
|
|
|
7470 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
7471 |
|
|
/* mptscsih_dv_parms - perform a variety of operations on the
|
7472 |
|
|
* parameters used for negotiation.
|
7473 |
|
|
* @hd: Pointer to a SCSI host.
|
7474 |
|
|
* @dv: Pointer to a structure that contains the maximum and current
|
7475 |
|
|
* negotiated parameters.
|
7476 |
|
|
*/
|
7477 |
|
|
static void
|
7478 |
|
|
mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
|
7479 |
|
|
{
|
7480 |
|
|
VirtDevice *pTarget;
|
7481 |
|
|
SCSIDevicePage0_t *pPage0;
|
7482 |
|
|
SCSIDevicePage1_t *pPage1;
|
7483 |
|
|
int val = 0, data, configuration;
|
7484 |
|
|
u8 width = 0;
|
7485 |
|
|
u8 offset = 0;
|
7486 |
|
|
u8 factor = 0;
|
7487 |
|
|
u8 negoFlags = 0;
|
7488 |
|
|
u8 cmd = dv->cmd;
|
7489 |
|
|
u8 id = dv->id;
|
7490 |
|
|
|
7491 |
|
|
switch (cmd) {
|
7492 |
|
|
case MPT_GET_NVRAM_VALS:
|
7493 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
|
7494 |
|
|
hd->ioc->name));
|
7495 |
|
|
/* Get the NVRAM values and save in tmax
|
7496 |
|
|
* If not an LVD bus, the adapter minSyncFactor has been
|
7497 |
|
|
* already throttled back.
|
7498 |
|
|
*/
|
7499 |
|
|
if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
|
7500 |
|
|
width = pTarget->maxWidth;
|
7501 |
|
|
offset = pTarget->maxOffset;
|
7502 |
|
|
factor = pTarget->minSyncFactor;
|
7503 |
|
|
negoFlags = pTarget->negoFlags;
|
7504 |
|
|
} else {
|
7505 |
|
|
if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
7506 |
|
|
data = hd->ioc->spi_data.nvram[id];
|
7507 |
|
|
width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
|
7508 |
|
|
if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
|
7509 |
|
|
factor = MPT_ASYNC;
|
7510 |
|
|
else {
|
7511 |
|
|
factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
|
7512 |
|
|
if ((factor == 0) || (factor == MPT_ASYNC)){
|
7513 |
|
|
factor = MPT_ASYNC;
|
7514 |
|
|
offset = 0;
|
7515 |
|
|
}
|
7516 |
|
|
}
|
7517 |
|
|
} else {
|
7518 |
|
|
width = MPT_NARROW;
|
7519 |
|
|
offset = 0;
|
7520 |
|
|
factor = MPT_ASYNC;
|
7521 |
|
|
}
|
7522 |
|
|
|
7523 |
|
|
/* Set the negotiation flags */
|
7524 |
|
|
negoFlags = hd->ioc->spi_data.noQas;
|
7525 |
|
|
if (!width)
|
7526 |
|
|
negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
|
7527 |
|
|
|
7528 |
|
|
if (!offset)
|
7529 |
|
|
negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
|
7530 |
|
|
}
|
7531 |
|
|
|
7532 |
|
|
/* limit by adapter capabilities */
|
7533 |
|
|
width = MIN(width, hd->ioc->spi_data.maxBusWidth);
|
7534 |
|
|
offset = MIN(offset, hd->ioc->spi_data.maxSyncOffset);
|
7535 |
|
|
factor = MAX(factor, hd->ioc->spi_data.minSyncFactor);
|
7536 |
|
|
|
7537 |
|
|
/* Check Consistency */
|
7538 |
|
|
if (offset && (factor < MPT_ULTRA2) && !width)
|
7539 |
|
|
factor = MPT_ULTRA2;
|
7540 |
|
|
|
7541 |
|
|
dv->max.width = width;
|
7542 |
|
|
dv->max.offset = offset;
|
7543 |
|
|
dv->max.factor = factor;
|
7544 |
|
|
dv->max.flags = negoFlags;
|
7545 |
|
|
ddvprintk((" width %d, factor %x, offset %x flags %x\n",
|
7546 |
|
|
width, factor, offset, negoFlags));
|
7547 |
|
|
break;
|
7548 |
|
|
|
7549 |
|
|
case MPT_UPDATE_MAX:
|
7550 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT
|
7551 |
|
|
"Updating with SDP0 Data: ", hd->ioc->name));
|
7552 |
|
|
/* Update tmax values with those from Device Page 0.*/
|
7553 |
|
|
pPage0 = (SCSIDevicePage0_t *) pPage;
|
7554 |
|
|
if (pPage0) {
|
7555 |
|
|
val = cpu_to_le32(pPage0->NegotiatedParameters);
|
7556 |
|
|
dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
|
7557 |
|
|
dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
|
7558 |
|
|
dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
|
7559 |
|
|
}
|
7560 |
|
|
|
7561 |
|
|
dv->now.width = dv->max.width;
|
7562 |
|
|
dv->now.offset = dv->max.offset;
|
7563 |
|
|
dv->now.factor = dv->max.factor;
|
7564 |
|
|
ddvprintk(("width %d, factor %x, offset %x, flags %x\n",
|
7565 |
|
|
dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
|
7566 |
|
|
break;
|
7567 |
|
|
|
7568 |
|
|
case MPT_SET_MAX:
|
7569 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
|
7570 |
|
|
hd->ioc->name));
|
7571 |
|
|
/* Set current to the max values. Update the config page.*/
|
7572 |
|
|
dv->now.width = dv->max.width;
|
7573 |
|
|
dv->now.offset = dv->max.offset;
|
7574 |
|
|
dv->now.factor = dv->max.factor;
|
7575 |
|
|
dv->now.flags = dv->max.flags;
|
7576 |
|
|
|
7577 |
|
|
pPage1 = (SCSIDevicePage1_t *)pPage;
|
7578 |
|
|
if (pPage1) {
|
7579 |
|
|
mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
|
7580 |
|
|
dv->now.offset, &val, &configuration, dv->now.flags);
|
7581 |
|
|
pPage1->RequestedParameters = le32_to_cpu(val);
|
7582 |
|
|
pPage1->Reserved = 0;
|
7583 |
|
|
pPage1->Configuration = le32_to_cpu(configuration);
|
7584 |
|
|
|
7585 |
|
|
}
|
7586 |
|
|
|
7587 |
|
|
ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n",
|
7588 |
|
|
dv->now.width, dv->now.factor, dv->now.offset, val, configuration));
|
7589 |
|
|
break;
|
7590 |
|
|
|
7591 |
|
|
case MPT_SET_MIN:
|
7592 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
|
7593 |
|
|
hd->ioc->name));
|
7594 |
|
|
/* Set page to asynchronous and narrow
|
7595 |
|
|
* Do not update now, breaks fallback routine. */
|
7596 |
|
|
width = MPT_NARROW;
|
7597 |
|
|
offset = 0;
|
7598 |
|
|
factor = MPT_ASYNC;
|
7599 |
|
|
negoFlags = dv->max.flags;
|
7600 |
|
|
|
7601 |
|
|
pPage1 = (SCSIDevicePage1_t *)pPage;
|
7602 |
|
|
if (pPage1) {
|
7603 |
|
|
mptscsih_setDevicePage1Flags (width, factor,
|
7604 |
|
|
offset, &val, &configuration, negoFlags);
|
7605 |
|
|
pPage1->RequestedParameters = le32_to_cpu(val);
|
7606 |
|
|
pPage1->Reserved = 0;
|
7607 |
|
|
pPage1->Configuration = le32_to_cpu(configuration);
|
7608 |
|
|
}
|
7609 |
|
|
ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
|
7610 |
|
|
width, factor, offset, val, configuration));
|
7611 |
|
|
break;
|
7612 |
|
|
|
7613 |
|
|
case MPT_FALLBACK:
|
7614 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT
|
7615 |
|
|
"Fallback: Start: offset %d, factor %x, width %d \n",
|
7616 |
|
|
hd->ioc->name, dv->now.offset,
|
7617 |
|
|
dv->now.factor, dv->now.width));
|
7618 |
|
|
width = dv->now.width;
|
7619 |
|
|
offset = dv->now.offset;
|
7620 |
|
|
factor = dv->now.factor;
|
7621 |
|
|
if ((offset) && (dv->max.width)) {
|
7622 |
|
|
if (factor < MPT_ULTRA160)
|
7623 |
|
|
factor = MPT_ULTRA160;
|
7624 |
|
|
else if (factor < MPT_ULTRA2) {
|
7625 |
|
|
factor = MPT_ULTRA2;
|
7626 |
|
|
width = MPT_WIDE;
|
7627 |
|
|
} else if ((factor == MPT_ULTRA2) && width) {
|
7628 |
|
|
factor = MPT_ULTRA2;
|
7629 |
|
|
width = MPT_NARROW;
|
7630 |
|
|
} else if (factor < MPT_ULTRA) {
|
7631 |
|
|
factor = MPT_ULTRA;
|
7632 |
|
|
width = MPT_WIDE;
|
7633 |
|
|
} else if ((factor == MPT_ULTRA) && width) {
|
7634 |
|
|
factor = MPT_ULTRA;
|
7635 |
|
|
width = MPT_NARROW;
|
7636 |
|
|
} else if (factor < MPT_FAST) {
|
7637 |
|
|
factor = MPT_FAST;
|
7638 |
|
|
width = MPT_WIDE;
|
7639 |
|
|
} else if ((factor == MPT_FAST) && width) {
|
7640 |
|
|
factor = MPT_FAST;
|
7641 |
|
|
width = MPT_NARROW;
|
7642 |
|
|
} else if (factor < MPT_SCSI) {
|
7643 |
|
|
factor = MPT_SCSI;
|
7644 |
|
|
width = MPT_WIDE;
|
7645 |
|
|
} else if ((factor == MPT_SCSI) && width) {
|
7646 |
|
|
factor = MPT_SCSI;
|
7647 |
|
|
width = MPT_NARROW;
|
7648 |
|
|
} else {
|
7649 |
|
|
factor = MPT_ASYNC;
|
7650 |
|
|
offset = 0;
|
7651 |
|
|
}
|
7652 |
|
|
|
7653 |
|
|
} else if (offset) {
|
7654 |
|
|
width = MPT_NARROW;
|
7655 |
|
|
if (factor < MPT_ULTRA)
|
7656 |
|
|
factor = MPT_ULTRA;
|
7657 |
|
|
else if (factor < MPT_FAST)
|
7658 |
|
|
factor = MPT_FAST;
|
7659 |
|
|
else if (factor < MPT_SCSI)
|
7660 |
|
|
factor = MPT_SCSI;
|
7661 |
|
|
else {
|
7662 |
|
|
factor = MPT_ASYNC;
|
7663 |
|
|
offset = 0;
|
7664 |
|
|
}
|
7665 |
|
|
|
7666 |
|
|
} else {
|
7667 |
|
|
width = MPT_NARROW;
|
7668 |
|
|
factor = MPT_ASYNC;
|
7669 |
|
|
}
|
7670 |
|
|
dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
|
7671 |
|
|
|
7672 |
|
|
dv->now.width = width;
|
7673 |
|
|
dv->now.offset = offset;
|
7674 |
|
|
dv->now.factor = factor;
|
7675 |
|
|
dv->now.flags = dv->max.flags;
|
7676 |
|
|
|
7677 |
|
|
pPage1 = (SCSIDevicePage1_t *)pPage;
|
7678 |
|
|
if (pPage1) {
|
7679 |
|
|
mptscsih_setDevicePage1Flags (width, factor, offset, &val,
|
7680 |
|
|
&configuration, dv->now.flags);
|
7681 |
|
|
|
7682 |
|
|
pPage1->RequestedParameters = le32_to_cpu(val);
|
7683 |
|
|
pPage1->Reserved = 0;
|
7684 |
|
|
pPage1->Configuration = le32_to_cpu(configuration);
|
7685 |
|
|
}
|
7686 |
|
|
|
7687 |
|
|
ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n",
|
7688 |
|
|
dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
|
7689 |
|
|
break;
|
7690 |
|
|
|
7691 |
|
|
case MPT_SAVE:
|
7692 |
|
|
ddvprintk((MYIOC_s_NOTE_FMT
|
7693 |
|
|
"Saving to Target structure: ", hd->ioc->name));
|
7694 |
|
|
ddvprintk(("offset %d, factor %x, width %d \n",
|
7695 |
|
|
dv->now.offset, dv->now.factor, dv->now.width));
|
7696 |
|
|
|
7697 |
|
|
/* Save these values to target structures
|
7698 |
|
|
* or overwrite nvram (phys disks only).
|
7699 |
|
|
*/
|
7700 |
|
|
|
7701 |
|
|
if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
|
7702 |
|
|
pTarget->maxWidth = dv->now.width;
|
7703 |
|
|
pTarget->maxOffset = dv->now.offset;
|
7704 |
|
|
pTarget->minSyncFactor = dv->now.factor;
|
7705 |
|
|
pTarget->negoFlags = dv->now.flags;
|
7706 |
|
|
} else {
|
7707 |
|
|
/* Preserv all flags, use
|
7708 |
|
|
* read-modify-write algorithm
|
7709 |
|
|
*/
|
7710 |
|
|
if (hd->ioc->spi_data.nvram) {
|
7711 |
|
|
data = hd->ioc->spi_data.nvram[id];
|
7712 |
|
|
|
7713 |
|
|
if (dv->now.width)
|
7714 |
|
|
data &= ~MPT_NVRAM_WIDE_DISABLE;
|
7715 |
|
|
else
|
7716 |
|
|
data |= MPT_NVRAM_WIDE_DISABLE;
|
7717 |
|
|
|
7718 |
|
|
if (!dv->now.offset)
|
7719 |
|
|
factor = MPT_ASYNC;
|
7720 |
|
|
|
7721 |
|
|
data &= ~MPT_NVRAM_SYNC_MASK;
|
7722 |
|
|
data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
|
7723 |
|
|
|
7724 |
|
|
hd->ioc->spi_data.nvram[id] = data;
|
7725 |
|
|
}
|
7726 |
|
|
}
|
7727 |
|
|
break;
|
7728 |
|
|
}
|
7729 |
|
|
}
|
7730 |
|
|
|
7731 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
7732 |
|
|
/* mptscsih_fillbuf - fill a buffer with a special data pattern
|
7733 |
|
|
* cleanup. For bus scan only.
|
7734 |
|
|
*
|
7735 |
|
|
* @buffer: Pointer to data buffer to be filled.
|
7736 |
|
|
* @size: Number of bytes to fill
|
7737 |
|
|
* @index: Pattern index
|
7738 |
|
|
* @width: bus width, 0 (8 bits) or 1 (16 bits)
|
7739 |
|
|
*/
|
7740 |
|
|
static void
|
7741 |
|
|
mptscsih_fillbuf(char *buffer, int size, int index, int width)
|
7742 |
|
|
{
|
7743 |
|
|
char *ptr = buffer;
|
7744 |
|
|
int ii;
|
7745 |
|
|
char byte;
|
7746 |
|
|
short val;
|
7747 |
|
|
|
7748 |
|
|
switch (index) {
|
7749 |
|
|
case 0:
|
7750 |
|
|
|
7751 |
|
|
if (width) {
|
7752 |
|
|
/* Pattern: 0000 FFFF 0000 FFFF
|
7753 |
|
|
*/
|
7754 |
|
|
for (ii=0; ii < size; ii++, ptr++) {
|
7755 |
|
|
if (ii & 0x02)
|
7756 |
|
|
*ptr = 0xFF;
|
7757 |
|
|
else
|
7758 |
|
|
*ptr = 0x00;
|
7759 |
|
|
}
|
7760 |
|
|
} else {
|
7761 |
|
|
/* Pattern: 00 FF 00 FF
|
7762 |
|
|
*/
|
7763 |
|
|
for (ii=0; ii < size; ii++, ptr++) {
|
7764 |
|
|
if (ii & 0x01)
|
7765 |
|
|
*ptr = 0xFF;
|
7766 |
|
|
else
|
7767 |
|
|
*ptr = 0x00;
|
7768 |
|
|
}
|
7769 |
|
|
}
|
7770 |
|
|
break;
|
7771 |
|
|
|
7772 |
|
|
case 1:
|
7773 |
|
|
if (width) {
|
7774 |
|
|
/* Pattern: 5555 AAAA 5555 AAAA 5555
|
7775 |
|
|
*/
|
7776 |
|
|
for (ii=0; ii < size; ii++, ptr++) {
|
7777 |
|
|
if (ii & 0x02)
|
7778 |
|
|
*ptr = 0xAA;
|
7779 |
|
|
else
|
7780 |
|
|
*ptr = 0x55;
|
7781 |
|
|
}
|
7782 |
|
|
} else {
|
7783 |
|
|
/* Pattern: 55 AA 55 AA 55
|
7784 |
|
|
*/
|
7785 |
|
|
for (ii=0; ii < size; ii++, ptr++) {
|
7786 |
|
|
if (ii & 0x01)
|
7787 |
|
|
*ptr = 0xAA;
|
7788 |
|
|
else
|
7789 |
|
|
*ptr = 0x55;
|
7790 |
|
|
}
|
7791 |
|
|
}
|
7792 |
|
|
break;
|
7793 |
|
|
|
7794 |
|
|
case 2:
|
7795 |
|
|
/* Pattern: 00 01 02 03 04 05
|
7796 |
|
|
* ... FE FF 00 01..
|
7797 |
|
|
*/
|
7798 |
|
|
for (ii=0; ii < size; ii++, ptr++)
|
7799 |
|
|
*ptr = (char) ii;
|
7800 |
|
|
break;
|
7801 |
|
|
|
7802 |
|
|
case 3:
|
7803 |
|
|
if (width) {
|
7804 |
|
|
/* Wide Pattern: FFFE 0001 FFFD 0002
|
7805 |
|
|
* ... 4000 DFFF 8000 EFFF
|
7806 |
|
|
*/
|
7807 |
|
|
byte = 0;
|
7808 |
|
|
for (ii=0; ii < size/2; ii++) {
|
7809 |
|
|
/* Create the base pattern
|
7810 |
|
|
*/
|
7811 |
|
|
val = (1 << byte);
|
7812 |
|
|
/* every 64 (0x40) bytes flip the pattern
|
7813 |
|
|
* since we fill 2 bytes / iteration,
|
7814 |
|
|
* test for ii = 0x20
|
7815 |
|
|
*/
|
7816 |
|
|
if (ii & 0x20)
|
7817 |
|
|
val = ~(val);
|
7818 |
|
|
|
7819 |
|
|
if (ii & 0x01) {
|
7820 |
|
|
*ptr = (char)( (val & 0xFF00) >> 8);
|
7821 |
|
|
ptr++;
|
7822 |
|
|
*ptr = (char)(val & 0xFF);
|
7823 |
|
|
byte++;
|
7824 |
|
|
byte &= 0x0F;
|
7825 |
|
|
} else {
|
7826 |
|
|
val = ~val;
|
7827 |
|
|
*ptr = (char)( (val & 0xFF00) >> 8);
|
7828 |
|
|
ptr++;
|
7829 |
|
|
*ptr = (char)(val & 0xFF);
|
7830 |
|
|
}
|
7831 |
|
|
|
7832 |
|
|
ptr++;
|
7833 |
|
|
}
|
7834 |
|
|
} else {
|
7835 |
|
|
/* Narrow Pattern: FE 01 FD 02 FB 04
|
7836 |
|
|
* .. 7F 80 01 FE 02 FD ... 80 7F
|
7837 |
|
|
*/
|
7838 |
|
|
byte = 0;
|
7839 |
|
|
for (ii=0; ii < size; ii++, ptr++) {
|
7840 |
|
|
/* Base pattern - first 32 bytes
|
7841 |
|
|
*/
|
7842 |
|
|
if (ii & 0x01) {
|
7843 |
|
|
*ptr = (1 << byte);
|
7844 |
|
|
byte++;
|
7845 |
|
|
byte &= 0x07;
|
7846 |
|
|
} else {
|
7847 |
|
|
*ptr = (char) (~(1 << byte));
|
7848 |
|
|
}
|
7849 |
|
|
|
7850 |
|
|
/* Flip the pattern every 32 bytes
|
7851 |
|
|
*/
|
7852 |
|
|
if (ii & 0x20)
|
7853 |
|
|
*ptr = ~(*ptr);
|
7854 |
|
|
}
|
7855 |
|
|
}
|
7856 |
|
|
break;
|
7857 |
|
|
}
|
7858 |
|
|
}
|
7859 |
|
|
#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
|
7860 |
|
|
|
7861 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
7862 |
|
|
/* Commandline Parsing routines and defines.
|
7863 |
|
|
*
|
7864 |
|
|
* insmod format:
|
7865 |
|
|
* insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1"
|
7866 |
|
|
* boot format:
|
7867 |
|
|
* mptscsih=width:1,dv:n,factor:0x8,saf-te:1
|
7868 |
|
|
*
|
7869 |
|
|
*/
|
7870 |
|
|
#ifdef MODULE
|
7871 |
|
|
#define ARG_SEP ' '
|
7872 |
|
|
#else
|
7873 |
|
|
#define ARG_SEP ','
|
7874 |
|
|
#endif
|
7875 |
|
|
|
7876 |
|
|
static char setup_token[] __initdata =
|
7877 |
|
|
"dv:"
|
7878 |
|
|
"width:"
|
7879 |
|
|
"factor:"
|
7880 |
|
|
"saf-te:"
|
7881 |
|
|
; /* DO NOT REMOVE THIS ';' */
|
7882 |
|
|
|
7883 |
|
|
#define OPT_DV 1
|
7884 |
|
|
#define OPT_MAX_WIDTH 2
|
7885 |
|
|
#define OPT_MIN_SYNC_FACTOR 3
|
7886 |
|
|
#define OPT_SAF_TE 4
|
7887 |
|
|
|
7888 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
7889 |
|
|
static int
|
7890 |
|
|
__init get_setup_token(char *p)
|
7891 |
|
|
{
|
7892 |
|
|
char *cur = setup_token;
|
7893 |
|
|
char *pc;
|
7894 |
|
|
int i = 0;
|
7895 |
|
|
|
7896 |
|
|
while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
|
7897 |
|
|
++pc;
|
7898 |
|
|
++i;
|
7899 |
|
|
if (!strncmp(p, cur, pc - cur))
|
7900 |
|
|
return i;
|
7901 |
|
|
cur = pc;
|
7902 |
|
|
}
|
7903 |
|
|
return 0;
|
7904 |
|
|
}
|
7905 |
|
|
|
7906 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
7907 |
|
|
static int
|
7908 |
|
|
__init mptscsih_setup(char *str)
|
7909 |
|
|
{
|
7910 |
|
|
char *cur = str;
|
7911 |
|
|
char *pc, *pv;
|
7912 |
|
|
unsigned long val;
|
7913 |
|
|
int c;
|
7914 |
|
|
|
7915 |
|
|
while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
|
7916 |
|
|
char *pe;
|
7917 |
|
|
|
7918 |
|
|
val = 0;
|
7919 |
|
|
pv = pc;
|
7920 |
|
|
c = *++pv;
|
7921 |
|
|
|
7922 |
|
|
if (c == 'n')
|
7923 |
|
|
val = 0;
|
7924 |
|
|
else if (c == 'y')
|
7925 |
|
|
val = 1;
|
7926 |
|
|
else
|
7927 |
|
|
val = (int) simple_strtoul(pv, &pe, 0);
|
7928 |
|
|
|
7929 |
|
|
printk("Found Token: %s, value %x\n", cur, (int)val);
|
7930 |
|
|
switch (get_setup_token(cur)) {
|
7931 |
|
|
case OPT_DV:
|
7932 |
|
|
driver_setup.dv = val;
|
7933 |
|
|
break;
|
7934 |
|
|
|
7935 |
|
|
case OPT_MAX_WIDTH:
|
7936 |
|
|
driver_setup.max_width = val;
|
7937 |
|
|
break;
|
7938 |
|
|
|
7939 |
|
|
case OPT_MIN_SYNC_FACTOR:
|
7940 |
|
|
driver_setup.min_sync_fac = val;
|
7941 |
|
|
break;
|
7942 |
|
|
|
7943 |
|
|
case OPT_SAF_TE:
|
7944 |
|
|
driver_setup.saf_te = val;
|
7945 |
|
|
break;
|
7946 |
|
|
|
7947 |
|
|
default:
|
7948 |
|
|
printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
|
7949 |
|
|
break;
|
7950 |
|
|
}
|
7951 |
|
|
|
7952 |
|
|
if ((cur = strchr(cur, ARG_SEP)) != NULL)
|
7953 |
|
|
++cur;
|
7954 |
|
|
}
|
7955 |
|
|
return 1;
|
7956 |
|
|
}
|
7957 |
|
|
|
7958 |
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
7959 |
|
|
|