blob: 1bb774becf251583bc13ffbfeb62281d3b55bb0a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
3
adam radford4deedd82010-03-08 12:37:46 -08004 Written By: Adam Radford <linuxraid@lsi.com>
5 Modifications By: Tom Couch <linuxraid@lsi.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
adam radford7a252fe2009-03-09 12:15:01 -08007 Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
adam radford4deedd82010-03-08 12:37:46 -08008 Copyright (C) 2010 LSI Corporation.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; version 2 of the License.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 NO WARRANTY
20 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
21 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
22 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
23 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
24 solely responsible for determining the appropriateness of using and
25 distributing the Program and assumes all risks associated with its
26 exercise of rights under this Agreement, including but not limited to
27 the risks and costs of program errors, damage to or loss of data,
28 programs or equipment, and unavailability or interruption of operations.
29
30 DISCLAIMER OF LIABILITY
31 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
32 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
34 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
35 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
37 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
38
39 You should have received a copy of the GNU General Public License
40 along with this program; if not, write to the Free Software
41 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42
43 Bugs/Comments/Suggestions should be mailed to:
adam radford4deedd82010-03-08 12:37:46 -080044 linuxraid@lsi.com
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 For more information, goto:
adam radford4deedd82010-03-08 12:37:46 -080047 http://www.lsi.com
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49 Note: This version of the driver does not contain a bundled firmware
50 image.
51
52 History
53 -------
54 2.26.02.000 - Driver cleanup for kernel submission.
55 2.26.02.001 - Replace schedule_timeout() calls with msleep().
56 2.26.02.002 - Add support for PAE mode.
57 Add lun support.
58 Fix twa_remove() to free irq handler/unregister_chrdev()
59 before shutting down card.
60 Change to new 'change_queue_depth' api.
61 Fix 'handled=1' ISR usage, remove bogus IRQ check.
62 Remove un-needed eh_abort handler.
63 Add support for embedded firmware error strings.
adam radfordd327d082005-09-09 15:55:13 -070064 2.26.02.003 - Correctly handle single sgl's with use_sg=1.
adam radford49bfd8d2005-09-21 17:20:14 -070065 2.26.02.004 - Add support for 9550SX controllers.
adam radford62288f12006-02-05 14:51:43 -080066 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher.
adam radford75913d92006-03-15 12:43:19 -080067 2.26.02.006 - Fix 9550SX pchip reset timeout.
68 Add big endian support.
adam radford1e08dcb2006-04-11 11:25:09 -070069 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic().
adam radford4039c302006-10-26 18:01:06 -070070 2.26.02.008 - Free irq handler in __twa_shutdown().
71 Serialize reset code.
72 Add support for 9650SE controllers.
adam radford0e78d152007-07-20 15:28:28 -070073 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
74 2.26.02.010 - Add support for 9690SA controllers.
adam radford3dabec72008-07-22 16:47:40 -070075 2.26.02.011 - Increase max AENs drained to 256.
76 Add MSI support and "use_msi" module parameter.
77 Fix bug in twa_get_param() on 4GB+.
78 Use pci_resource_len() for ioremap().
adam radford7a252fe2009-03-09 12:15:01 -080079 2.26.02.012 - Add power management support.
adam radford53ca3532009-12-10 11:53:31 -080080 2.26.02.013 - Fix bug in twa_load_sgl().
adam radford4deedd82010-03-08 12:37:46 -080081 2.26.02.014 - Force 60 second timeout default.
Linus Torvalds1da177e2005-04-16 15:20:36 -070082*/
83
84#include <linux/module.h>
85#include <linux/reboot.h>
86#include <linux/spinlock.h>
87#include <linux/interrupt.h>
88#include <linux/moduleparam.h>
89#include <linux/errno.h>
90#include <linux/types.h>
91#include <linux/delay.h>
92#include <linux/pci.h>
93#include <linux/time.h>
Jes Sorensena12e25bd2006-01-11 08:39:45 -050094#include <linux/mutex.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -060095#include <linux/smp_lock.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090096#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070097#include <asm/io.h>
98#include <asm/irq.h>
99#include <asm/uaccess.h>
100#include <scsi/scsi.h>
101#include <scsi/scsi_host.h>
102#include <scsi/scsi_tcq.h>
103#include <scsi/scsi_cmnd.h>
104#include "3w-9xxx.h"
105
106/* Globals */
adam radford4deedd82010-03-08 12:37:46 -0800107#define TW_DRIVER_VERSION "2.26.02.014"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
109static unsigned int twa_device_extension_count;
110static int twa_major = -1;
111extern struct timezone sys_tz;
112
113/* Module parameters */
adam radford4deedd82010-03-08 12:37:46 -0800114MODULE_AUTHOR ("LSI");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
116MODULE_LICENSE("GPL");
117MODULE_VERSION(TW_DRIVER_VERSION);
118
adam radford3dabec72008-07-22 16:47:40 -0700119static int use_msi = 0;
120module_param(use_msi, int, S_IRUGO);
121MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/* Function prototypes */
124static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
125static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
126static char *twa_aen_severity_lookup(unsigned char severity_code);
127static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
128static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
129static int twa_chrdev_open(struct inode *inode, struct file *file);
130static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
131static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
132static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
133static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
134 u32 set_features, unsigned short current_fw_srl,
135 unsigned short current_fw_arch_id,
136 unsigned short current_fw_branch,
137 unsigned short current_fw_build,
138 unsigned short *fw_on_ctlr_srl,
139 unsigned short *fw_on_ctlr_arch_id,
140 unsigned short *fw_on_ctlr_branch,
141 unsigned short *fw_on_ctlr_build,
142 u32 *init_connect_result);
adam radford0e78d152007-07-20 15:28:28 -0700143static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
145static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
146static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
adam radford0e78d152007-07-20 15:28:28 -0700147static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
149static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
150static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
151static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
152static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
153
154/* Functions */
155
156/* Show some statistics about the card */
Tony Jonesee959b02008-02-22 00:13:36 +0100157static ssize_t twa_show_stats(struct device *dev,
158 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Tony Jonesee959b02008-02-22 00:13:36 +0100160 struct Scsi_Host *host = class_to_shost(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
162 unsigned long flags = 0;
163 ssize_t len;
164
165 spin_lock_irqsave(tw_dev->host->host_lock, flags);
166 len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
167 "Current commands posted: %4d\n"
168 "Max commands posted: %4d\n"
169 "Current pending commands: %4d\n"
170 "Max pending commands: %4d\n"
171 "Last sgl length: %4d\n"
172 "Max sgl length: %4d\n"
173 "Last sector count: %4d\n"
174 "Max sector count: %4d\n"
175 "SCSI Host Resets: %4d\n"
176 "AEN's: %4d\n",
177 TW_DRIVER_VERSION,
178 tw_dev->posted_request_count,
179 tw_dev->max_posted_request_count,
180 tw_dev->pending_request_count,
181 tw_dev->max_pending_request_count,
182 tw_dev->sgl_entries,
183 tw_dev->max_sgl_entries,
184 tw_dev->sector_count,
185 tw_dev->max_sector_count,
186 tw_dev->num_resets,
187 tw_dev->aen_count);
188 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
189 return len;
190} /* End twa_show_stats() */
191
192/* This function will set a devices queue depth */
Mike Christiee881a172009-10-15 17:46:39 -0700193static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
194 int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
Mike Christiee881a172009-10-15 17:46:39 -0700196 if (reason != SCSI_QDEPTH_DEFAULT)
197 return -EOPNOTSUPP;
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 if (queue_depth > TW_Q_LENGTH-2)
200 queue_depth = TW_Q_LENGTH-2;
201 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
202 return queue_depth;
203} /* End twa_change_queue_depth() */
204
205/* Create sysfs 'stats' entry */
Tony Jonesee959b02008-02-22 00:13:36 +0100206static struct device_attribute twa_host_stats_attr = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 .attr = {
208 .name = "stats",
209 .mode = S_IRUGO,
210 },
211 .show = twa_show_stats
212};
213
214/* Host attributes initializer */
Tony Jonesee959b02008-02-22 00:13:36 +0100215static struct device_attribute *twa_host_attrs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 &twa_host_stats_attr,
217 NULL,
218};
219
220/* File operations struct for character device */
Arjan van de Ven00977a52007-02-12 00:55:34 -0800221static const struct file_operations twa_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 .owner = THIS_MODULE,
223 .ioctl = twa_chrdev_ioctl,
224 .open = twa_chrdev_open,
225 .release = NULL
226};
227
228/* This function will complete an aen request from the isr */
229static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
230{
231 TW_Command_Full *full_command_packet;
232 TW_Command *command_packet;
233 TW_Command_Apache_Header *header;
234 unsigned short aen;
235 int retval = 1;
236
237 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
238 tw_dev->posted_request_count--;
adam radford75913d92006-03-15 12:43:19 -0800239 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 full_command_packet = tw_dev->command_packet_virt[request_id];
241 command_packet = &full_command_packet->command.oldcommand;
242
243 /* First check for internal completion of set param for time sync */
244 if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
245 /* Keep reading the queue in case there are more aen's */
246 if (twa_aen_read_queue(tw_dev, request_id))
247 goto out2;
248 else {
249 retval = 0;
250 goto out;
251 }
252 }
253
254 switch (aen) {
255 case TW_AEN_QUEUE_EMPTY:
256 /* Quit reading the queue if this is the last one */
257 break;
258 case TW_AEN_SYNC_TIME_WITH_HOST:
259 twa_aen_sync_time(tw_dev, request_id);
260 retval = 0;
261 goto out;
262 default:
263 twa_aen_queue_event(tw_dev, header);
264
265 /* If there are more aen's, keep reading the queue */
266 if (twa_aen_read_queue(tw_dev, request_id))
267 goto out2;
268 else {
269 retval = 0;
270 goto out;
271 }
272 }
273 retval = 0;
274out2:
275 tw_dev->state[request_id] = TW_S_COMPLETED;
276 twa_free_request_id(tw_dev, request_id);
277 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
278out:
279 return retval;
280} /* End twa_aen_complete() */
281
282/* This function will drain aen queue */
283static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
284{
285 int request_id = 0;
286 char cdb[TW_MAX_CDB_LEN];
287 TW_SG_Entry sglist[1];
288 int finished = 0, count = 0;
289 TW_Command_Full *full_command_packet;
290 TW_Command_Apache_Header *header;
291 unsigned short aen;
292 int first_reset = 0, queue = 0, retval = 1;
293
294 if (no_check_reset)
295 first_reset = 0;
296 else
297 first_reset = 1;
298
299 full_command_packet = tw_dev->command_packet_virt[request_id];
300 memset(full_command_packet, 0, sizeof(TW_Command_Full));
301
302 /* Initialize cdb */
303 memset(&cdb, 0, TW_MAX_CDB_LEN);
304 cdb[0] = REQUEST_SENSE; /* opcode */
305 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
306
307 /* Initialize sglist */
308 memset(&sglist, 0, sizeof(TW_SG_Entry));
309 sglist[0].length = TW_SECTOR_SIZE;
310 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
311
312 if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
313 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
314 goto out;
315 }
316
317 /* Mark internal command */
318 tw_dev->srb[request_id] = NULL;
319
320 do {
321 /* Send command to the board */
322 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
323 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
324 goto out;
325 }
326
327 /* Now poll for completion */
328 if (twa_poll_response(tw_dev, request_id, 30)) {
329 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
330 tw_dev->posted_request_count--;
331 goto out;
332 }
333
334 tw_dev->posted_request_count--;
335 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
adam radford75913d92006-03-15 12:43:19 -0800336 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 queue = 0;
338 count++;
339
340 switch (aen) {
341 case TW_AEN_QUEUE_EMPTY:
342 if (first_reset != 1)
343 goto out;
344 else
345 finished = 1;
346 break;
347 case TW_AEN_SOFT_RESET:
348 if (first_reset == 0)
349 first_reset = 1;
350 else
351 queue = 1;
352 break;
353 case TW_AEN_SYNC_TIME_WITH_HOST:
354 break;
355 default:
356 queue = 1;
357 }
358
359 /* Now queue an event info */
360 if (queue)
361 twa_aen_queue_event(tw_dev, header);
362 } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
363
364 if (count == TW_MAX_AEN_DRAIN)
365 goto out;
366
367 retval = 0;
368out:
369 tw_dev->state[request_id] = TW_S_INITIAL;
370 return retval;
371} /* End twa_aen_drain_queue() */
372
373/* This function will queue an event */
374static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
375{
376 u32 local_time;
377 struct timeval time;
378 TW_Event *event;
379 unsigned short aen;
380 char host[16];
381 char *error_str;
382
383 tw_dev->aen_count++;
384
385 /* Fill out event info */
386 event = tw_dev->event_queue[tw_dev->error_index];
387
388 /* Check for clobber */
389 host[0] = '\0';
390 if (tw_dev->host) {
391 sprintf(host, " scsi%d:", tw_dev->host->host_no);
392 if (event->retrieved == TW_AEN_NOT_RETRIEVED)
393 tw_dev->aen_clobber = 1;
394 }
395
adam radford75913d92006-03-15 12:43:19 -0800396 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 memset(event, 0, sizeof(TW_Event));
398
399 event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
400 do_gettimeofday(&time);
401 local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
402 event->time_stamp_sec = local_time;
403 event->aen_code = aen;
404 event->retrieved = TW_AEN_NOT_RETRIEVED;
405 event->sequence_id = tw_dev->error_sequence_id;
406 tw_dev->error_sequence_id++;
407
408 /* Check for embedded error string */
409 error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
410
411 header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
412 event->parameter_len = strlen(header->err_specific_desc);
adam radford75913d92006-03-15 12:43:19 -0800413 memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + (error_str[0] == '\0' ? 0 : (1 + strlen(error_str))));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (event->severity != TW_AEN_SEVERITY_DEBUG)
415 printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
416 host,
417 twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
418 TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
419 error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
420 header->err_specific_desc);
421 else
422 tw_dev->aen_count--;
423
424 if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
425 tw_dev->event_queue_wrapped = 1;
426 tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
427} /* End twa_aen_queue_event() */
428
429/* This function will read the aen queue from the isr */
430static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
431{
432 char cdb[TW_MAX_CDB_LEN];
433 TW_SG_Entry sglist[1];
434 TW_Command_Full *full_command_packet;
435 int retval = 1;
436
437 full_command_packet = tw_dev->command_packet_virt[request_id];
438 memset(full_command_packet, 0, sizeof(TW_Command_Full));
439
440 /* Initialize cdb */
441 memset(&cdb, 0, TW_MAX_CDB_LEN);
442 cdb[0] = REQUEST_SENSE; /* opcode */
443 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
444
445 /* Initialize sglist */
446 memset(&sglist, 0, sizeof(TW_SG_Entry));
447 sglist[0].length = TW_SECTOR_SIZE;
448 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
449
450 /* Mark internal command */
451 tw_dev->srb[request_id] = NULL;
452
453 /* Now post the command packet */
454 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
455 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
456 goto out;
457 }
458 retval = 0;
459out:
460 return retval;
461} /* End twa_aen_read_queue() */
462
463/* This function will look up an AEN severity string */
464static char *twa_aen_severity_lookup(unsigned char severity_code)
465{
466 char *retval = NULL;
467
468 if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
469 (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
470 goto out;
471
472 retval = twa_aen_severity_table[severity_code];
473out:
474 return retval;
475} /* End twa_aen_severity_lookup() */
476
477/* This function will sync firmware time with the host time */
478static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
479{
480 u32 schedulertime;
481 struct timeval utc;
482 TW_Command_Full *full_command_packet;
483 TW_Command *command_packet;
484 TW_Param_Apache *param;
485 u32 local_time;
486
487 /* Fill out the command packet */
488 full_command_packet = tw_dev->command_packet_virt[request_id];
489 memset(full_command_packet, 0, sizeof(TW_Command_Full));
490 command_packet = &full_command_packet->command.oldcommand;
491 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
492 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -0800493 command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
494 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 command_packet->size = TW_COMMAND_SIZE;
adam radford75913d92006-03-15 12:43:19 -0800496 command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 /* Setup the param */
499 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
500 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -0800501 param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */
502 param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
503 param->parameter_size_bytes = cpu_to_le16(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 /* Convert system time in UTC to local time seconds since last
506 Sunday 12:00AM */
507 do_gettimeofday(&utc);
508 local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
509 schedulertime = local_time - (3 * 86400);
adam radford75913d92006-03-15 12:43:19 -0800510 schedulertime = cpu_to_le32(schedulertime % 604800);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 memcpy(param->data, &schedulertime, sizeof(u32));
513
514 /* Mark internal command */
515 tw_dev->srb[request_id] = NULL;
516
517 /* Now post the command */
518 twa_post_command_packet(tw_dev, request_id, 1);
519} /* End twa_aen_sync_time() */
520
521/* This function will allocate memory and check if it is correctly aligned */
522static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
523{
524 int i;
525 dma_addr_t dma_handle;
526 unsigned long *cpu_addr;
527 int retval = 1;
528
529 cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
530 if (!cpu_addr) {
531 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
532 goto out;
533 }
534
535 if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
536 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
537 pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
538 goto out;
539 }
540
541 memset(cpu_addr, 0, size*TW_Q_LENGTH);
542
543 for (i = 0; i < TW_Q_LENGTH; i++) {
544 switch(which) {
545 case 0:
546 tw_dev->command_packet_phys[i] = dma_handle+(i*size);
547 tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
548 break;
549 case 1:
550 tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
551 tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
552 break;
553 }
554 }
555 retval = 0;
556out:
557 return retval;
558} /* End twa_allocate_memory() */
559
560/* This function will check the status register for unexpected bits */
561static int twa_check_bits(u32 status_reg_value)
562{
563 int retval = 1;
564
565 if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
566 goto out;
567 if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
568 goto out;
569
570 retval = 0;
571out:
572 return retval;
573} /* End twa_check_bits() */
574
575/* This function will check the srl and decide if we are compatible */
576static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
577{
578 int retval = 1;
579 unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
580 unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
581 u32 init_connect_result = 0;
582
583 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
584 TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
585 TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
586 TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
587 &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
588 &fw_on_ctlr_build, &init_connect_result)) {
589 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
590 goto out;
591 }
592
adam radford4039c302006-10-26 18:01:06 -0700593 tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl;
594 tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch;
595 tw_dev->tw_compat_info.working_build = fw_on_ctlr_build;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597 /* Try base mode compatibility */
598 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
599 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
600 TW_EXTENDED_INIT_CONNECT,
601 TW_BASE_FW_SRL, TW_9000_ARCH_ID,
602 TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
603 &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
604 &fw_on_ctlr_branch, &fw_on_ctlr_build,
605 &init_connect_result)) {
606 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
607 goto out;
608 }
609 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
610 if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
611 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
612 } else {
613 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
614 }
615 goto out;
616 }
adam radford4039c302006-10-26 18:01:06 -0700617 tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL;
618 tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH;
619 tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 }
adam radford4039c302006-10-26 18:01:06 -0700621
622 /* Load rest of compatibility struct */
623 strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
624 tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
625 tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
626 tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
627 tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
628 tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
629 tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
630 tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
631 tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
632 tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 retval = 0;
635out:
636 return retval;
637} /* End twa_check_srl() */
638
639/* This function handles ioctl for the character device */
640static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
641{
642 long timeout;
643 unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
644 dma_addr_t dma_handle;
645 int request_id = 0;
646 unsigned int sequence_id = 0;
647 unsigned char event_index, start_index;
648 TW_Ioctl_Driver_Command driver_command;
649 TW_Ioctl_Buf_Apache *tw_ioctl;
650 TW_Lock *tw_lock;
651 TW_Command_Full *full_command_packet;
652 TW_Compatibility_Info *tw_compat_info;
653 TW_Event *event;
654 struct timeval current_time;
655 u32 current_time_ms;
656 TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
657 int retval = TW_IOCTL_ERROR_OS_EFAULT;
658 void __user *argp = (void __user *)arg;
659
660 /* Only let one of these through at a time */
Jes Sorensena12e25bd2006-01-11 08:39:45 -0500661 if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 retval = TW_IOCTL_ERROR_OS_EINTR;
663 goto out;
664 }
665
666 /* First copy down the driver command */
667 if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
668 goto out2;
669
670 /* Check data buffer size */
adam radford4039c302006-10-26 18:01:06 -0700671 if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 retval = TW_IOCTL_ERROR_OS_EINVAL;
673 goto out2;
674 }
675
676 /* Hardware can only do multiple of 512 byte transfers */
677 data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
678
679 /* Now allocate ioctl buf memory */
680 cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
681 if (!cpu_addr) {
682 retval = TW_IOCTL_ERROR_OS_ENOMEM;
683 goto out2;
684 }
685
686 tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
687
688 /* Now copy down the entire ioctl */
689 if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
690 goto out3;
691
692 /* See which ioctl we are doing */
693 switch (cmd) {
694 case TW_IOCTL_FIRMWARE_PASS_THROUGH:
695 spin_lock_irqsave(tw_dev->host->host_lock, flags);
696 twa_get_request_id(tw_dev, &request_id);
697
698 /* Flag internal command */
699 tw_dev->srb[request_id] = NULL;
700
701 /* Flag chrdev ioctl */
702 tw_dev->chrdev_request_id = request_id;
703
704 full_command_packet = &tw_ioctl->firmware_command;
705
706 /* Load request id and sglist for both command types */
adam radford0e78d152007-07-20 15:28:28 -0700707 twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
710
711 /* Now post the command packet to the controller */
712 twa_post_command_packet(tw_dev, request_id, 1);
713 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
714
715 timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
716
717 /* Now wait for command to complete */
718 timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 /* We timed out, and didn't get an interrupt */
721 if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
722 /* Now we need to reset the board */
723 printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
adam radford0e78d152007-07-20 15:28:28 -0700724 tw_dev->host->host_no, TW_DRIVER, 0x37,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 cmd);
726 retval = TW_IOCTL_ERROR_OS_EIO;
adam radford0e78d152007-07-20 15:28:28 -0700727 twa_reset_device_extension(tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 goto out3;
729 }
730
731 /* Now copy in the command packet response */
732 memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
733
734 /* Now complete the io */
735 spin_lock_irqsave(tw_dev->host->host_lock, flags);
736 tw_dev->posted_request_count--;
737 tw_dev->state[request_id] = TW_S_COMPLETED;
738 twa_free_request_id(tw_dev, request_id);
739 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
740 break;
741 case TW_IOCTL_GET_COMPATIBILITY_INFO:
742 tw_ioctl->driver_command.status = 0;
Dirk Hohndel06fe9fb2009-09-28 21:43:57 -0400743 /* Copy compatibility struct into ioctl data buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
adam radford4039c302006-10-26 18:01:06 -0700745 memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 break;
747 case TW_IOCTL_GET_LAST_EVENT:
748 if (tw_dev->event_queue_wrapped) {
749 if (tw_dev->aen_clobber) {
750 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
751 tw_dev->aen_clobber = 0;
752 } else
753 tw_ioctl->driver_command.status = 0;
754 } else {
755 if (!tw_dev->error_index) {
756 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
757 break;
758 }
759 tw_ioctl->driver_command.status = 0;
760 }
761 event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
762 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
763 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
764 break;
765 case TW_IOCTL_GET_FIRST_EVENT:
766 if (tw_dev->event_queue_wrapped) {
767 if (tw_dev->aen_clobber) {
768 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
769 tw_dev->aen_clobber = 0;
770 } else
771 tw_ioctl->driver_command.status = 0;
772 event_index = tw_dev->error_index;
773 } else {
774 if (!tw_dev->error_index) {
775 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
776 break;
777 }
778 tw_ioctl->driver_command.status = 0;
779 event_index = 0;
780 }
781 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
782 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
783 break;
784 case TW_IOCTL_GET_NEXT_EVENT:
785 event = (TW_Event *)tw_ioctl->data_buffer;
786 sequence_id = event->sequence_id;
787 tw_ioctl->driver_command.status = 0;
788
789 if (tw_dev->event_queue_wrapped) {
790 if (tw_dev->aen_clobber) {
791 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
792 tw_dev->aen_clobber = 0;
793 }
794 start_index = tw_dev->error_index;
795 } else {
796 if (!tw_dev->error_index) {
797 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
798 break;
799 }
800 start_index = 0;
801 }
802 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
803
804 if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
805 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
806 tw_dev->aen_clobber = 1;
807 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
808 break;
809 }
810 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
811 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
812 break;
813 case TW_IOCTL_GET_PREVIOUS_EVENT:
814 event = (TW_Event *)tw_ioctl->data_buffer;
815 sequence_id = event->sequence_id;
816 tw_ioctl->driver_command.status = 0;
817
818 if (tw_dev->event_queue_wrapped) {
819 if (tw_dev->aen_clobber) {
820 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
821 tw_dev->aen_clobber = 0;
822 }
823 start_index = tw_dev->error_index;
824 } else {
825 if (!tw_dev->error_index) {
826 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
827 break;
828 }
829 start_index = 0;
830 }
831 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
832
833 if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
834 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
835 tw_dev->aen_clobber = 1;
836 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
837 break;
838 }
839 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
840 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
841 break;
842 case TW_IOCTL_GET_LOCK:
843 tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
844 do_gettimeofday(&current_time);
845 current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
846
847 if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
848 tw_dev->ioctl_sem_lock = 1;
849 tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
850 tw_ioctl->driver_command.status = 0;
851 tw_lock->time_remaining_msec = tw_lock->timeout_msec;
852 } else {
853 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
854 tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
855 }
856 break;
857 case TW_IOCTL_RELEASE_LOCK:
858 if (tw_dev->ioctl_sem_lock == 1) {
859 tw_dev->ioctl_sem_lock = 0;
860 tw_ioctl->driver_command.status = 0;
861 } else {
862 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
863 }
864 break;
865 default:
866 retval = TW_IOCTL_ERROR_OS_ENOTTY;
867 goto out3;
868 }
869
870 /* Now copy the entire response to userspace */
871 if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
872 retval = 0;
873out3:
874 /* Now free ioctl buf memory */
875 dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
876out2:
Jes Sorensena12e25bd2006-01-11 08:39:45 -0500877 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878out:
879 return retval;
880} /* End twa_chrdev_ioctl() */
881
882/* This function handles open for the character device */
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600883/* NOTE that this function will race with remove. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884static int twa_chrdev_open(struct inode *inode, struct file *file)
885{
886 unsigned int minor_number;
887 int retval = TW_IOCTL_ERROR_OS_ENODEV;
888
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600889 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 minor_number = iminor(inode);
891 if (minor_number >= twa_device_extension_count)
892 goto out;
893 retval = 0;
894out:
895 return retval;
896} /* End twa_chrdev_open() */
897
898/* This function will print readable messages from status register errors */
899static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
900{
901 int retval = 1;
902
903 /* Check for various error conditions and handle them appropriately */
904 if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
905 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
906 writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
907 }
908
909 if (status_reg_value & TW_STATUS_PCI_ABORT) {
910 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
911 writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
912 pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
913 }
914
915 if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
adam radford0e78d152007-07-20 15:28:28 -0700916 if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
917 (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
918 (!test_bit(TW_IN_RESET, &tw_dev->flags)))
adam radford4039c302006-10-26 18:01:06 -0700919 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
921 }
922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
924 if (tw_dev->reset_print == 0) {
925 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
926 tw_dev->reset_print = 1;
927 }
928 goto out;
929 }
930 retval = 0;
931out:
932 return retval;
933} /* End twa_decode_bits() */
934
935/* This function will empty the response queue */
936static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
937{
938 u32 status_reg_value, response_que_value;
939 int count = 0, retval = 1;
940
941 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
942
943 while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
944 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
945 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
946 count++;
947 }
948 if (count == TW_MAX_RESPONSE_DRAIN)
949 goto out;
950
951 retval = 0;
952out:
953 return retval;
954} /* End twa_empty_response_queue() */
955
adam radford49bfd8d2005-09-21 17:20:14 -0700956/* This function will clear the pchip/response queue on 9550SX */
957static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
958{
adam radford75913d92006-03-15 12:43:19 -0800959 u32 response_que_value = 0;
960 unsigned long before;
961 int retval = 1;
adam radford49bfd8d2005-09-21 17:20:14 -0700962
adam radford0e78d152007-07-20 15:28:28 -0700963 if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
adam radford75913d92006-03-15 12:43:19 -0800964 before = jiffies;
965 while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
adam radford49bfd8d2005-09-21 17:20:14 -0700966 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
adam radford4039c302006-10-26 18:01:06 -0700967 msleep(1);
adam radford75913d92006-03-15 12:43:19 -0800968 if (time_after(jiffies, before + HZ * 30))
adam radford49bfd8d2005-09-21 17:20:14 -0700969 goto out;
adam radford49bfd8d2005-09-21 17:20:14 -0700970 }
adam radford75913d92006-03-15 12:43:19 -0800971 /* P-chip settle time */
972 msleep(500);
adam radford49bfd8d2005-09-21 17:20:14 -0700973 retval = 0;
974 } else
975 retval = 0;
976out:
977 return retval;
978} /* End twa_empty_response_queue_large() */
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980/* This function passes sense keys from firmware to scsi layer */
981static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
982{
983 TW_Command_Full *full_command_packet;
984 unsigned short error;
985 int retval = 1;
986 char *error_str;
987
988 full_command_packet = tw_dev->command_packet_virt[request_id];
989
990 /* Check for embedded error string */
991 error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
992
993 /* Don't print error for Logical unit not supported during rollcall */
adam radford75913d92006-03-15 12:43:19 -0800994 error = le16_to_cpu(full_command_packet->header.status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
996 if (print_host)
997 printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
998 tw_dev->host->host_no,
999 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
1000 full_command_packet->header.status_block.error,
1001 error_str[0] == '\0' ?
1002 twa_string_lookup(twa_error_table,
1003 full_command_packet->header.status_block.error) : error_str,
1004 full_command_packet->header.err_specific_desc);
1005 else
1006 printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
1007 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
1008 full_command_packet->header.status_block.error,
1009 error_str[0] == '\0' ?
1010 twa_string_lookup(twa_error_table,
1011 full_command_packet->header.status_block.error) : error_str,
1012 full_command_packet->header.err_specific_desc);
1013 }
1014
1015 if (copy_sense) {
1016 memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
1017 tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
1018 retval = TW_ISR_DONT_RESULT;
1019 goto out;
1020 }
1021 retval = 0;
1022out:
1023 return retval;
1024} /* End twa_fill_sense() */
1025
1026/* This function will free up device extension resources */
1027static void twa_free_device_extension(TW_Device_Extension *tw_dev)
1028{
1029 if (tw_dev->command_packet_virt[0])
1030 pci_free_consistent(tw_dev->tw_pci_dev,
1031 sizeof(TW_Command_Full)*TW_Q_LENGTH,
1032 tw_dev->command_packet_virt[0],
1033 tw_dev->command_packet_phys[0]);
1034
1035 if (tw_dev->generic_buffer_virt[0])
1036 pci_free_consistent(tw_dev->tw_pci_dev,
1037 TW_SECTOR_SIZE*TW_Q_LENGTH,
1038 tw_dev->generic_buffer_virt[0],
1039 tw_dev->generic_buffer_phys[0]);
1040
Jesper Juhlc9475cb2005-11-07 01:01:26 -08001041 kfree(tw_dev->event_queue[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042} /* End twa_free_device_extension() */
1043
1044/* This function will free a request id */
1045static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
1046{
1047 tw_dev->free_queue[tw_dev->free_tail] = request_id;
1048 tw_dev->state[request_id] = TW_S_FINISHED;
1049 tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
1050} /* End twa_free_request_id() */
1051
Alexey Dobriyan7f927fc2006-03-28 01:56:53 -08001052/* This function will get parameter table entries from the firmware */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
1054{
1055 TW_Command_Full *full_command_packet;
1056 TW_Command *command_packet;
1057 TW_Param_Apache *param;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 void *retval = NULL;
1059
1060 /* Setup the command packet */
1061 full_command_packet = tw_dev->command_packet_virt[request_id];
1062 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1063 command_packet = &full_command_packet->command.oldcommand;
1064
1065 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1066 command_packet->size = TW_COMMAND_SIZE;
1067 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001068 command_packet->byte6_offset.block_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
1070 /* Now setup the param */
1071 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
1072 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001073 param->table_id = cpu_to_le16(table_id | 0x8000);
1074 param->parameter_id = cpu_to_le16(parameter_id);
1075 param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
adam radford3dabec72008-07-22 16:47:40 -07001077 command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
adam radford75913d92006-03-15 12:43:19 -08001078 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 /* Post the command packet to the board */
1081 twa_post_command_packet(tw_dev, request_id, 1);
1082
1083 /* Poll for completion */
1084 if (twa_poll_response(tw_dev, request_id, 30))
1085 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
1086 else
1087 retval = (void *)&(param->data[0]);
1088
1089 tw_dev->posted_request_count--;
1090 tw_dev->state[request_id] = TW_S_INITIAL;
1091
1092 return retval;
1093} /* End twa_get_param() */
1094
1095/* This function will assign an available request id */
1096static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
1097{
1098 *request_id = tw_dev->free_queue[tw_dev->free_head];
1099 tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
1100 tw_dev->state[*request_id] = TW_S_STARTED;
1101} /* End twa_get_request_id() */
1102
1103/* This function will send an initconnection command to controller */
1104static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
1105 u32 set_features, unsigned short current_fw_srl,
1106 unsigned short current_fw_arch_id,
1107 unsigned short current_fw_branch,
1108 unsigned short current_fw_build,
1109 unsigned short *fw_on_ctlr_srl,
1110 unsigned short *fw_on_ctlr_arch_id,
1111 unsigned short *fw_on_ctlr_branch,
1112 unsigned short *fw_on_ctlr_build,
1113 u32 *init_connect_result)
1114{
1115 TW_Command_Full *full_command_packet;
1116 TW_Initconnect *tw_initconnect;
1117 int request_id = 0, retval = 1;
1118
1119 /* Initialize InitConnection command packet */
1120 full_command_packet = tw_dev->command_packet_virt[request_id];
1121 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1122 full_command_packet->header.header_desc.size_header = 128;
1123
1124 tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
1125 tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
1126 tw_initconnect->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001127 tw_initconnect->message_credits = cpu_to_le16(message_credits);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 tw_initconnect->features = set_features;
1129
1130 /* Turn on 64-bit sgl support if we need to */
1131 tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
1132
adam radford75913d92006-03-15 12:43:19 -08001133 tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if (set_features & TW_EXTENDED_INIT_CONNECT) {
1136 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
adam radford75913d92006-03-15 12:43:19 -08001137 tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
1138 tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
1139 tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
1140 tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 } else
1142 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
1143
1144 /* Send command packet to the board */
1145 twa_post_command_packet(tw_dev, request_id, 1);
1146
1147 /* Poll for completion */
1148 if (twa_poll_response(tw_dev, request_id, 30)) {
1149 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
1150 } else {
1151 if (set_features & TW_EXTENDED_INIT_CONNECT) {
adam radford75913d92006-03-15 12:43:19 -08001152 *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
1153 *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
1154 *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
1155 *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
1156 *init_connect_result = le32_to_cpu(tw_initconnect->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 }
1158 retval = 0;
1159 }
1160
1161 tw_dev->posted_request_count--;
1162 tw_dev->state[request_id] = TW_S_INITIAL;
1163
1164 return retval;
1165} /* End twa_initconnection() */
1166
1167/* This function will initialize the fields of a device extension */
1168static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
1169{
1170 int i, retval = 1;
1171
1172 /* Initialize command packet buffers */
1173 if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
1174 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
1175 goto out;
1176 }
1177
1178 /* Initialize generic buffer */
1179 if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
1180 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
1181 goto out;
1182 }
1183
1184 /* Allocate event info space */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001185 tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 if (!tw_dev->event_queue[0]) {
1187 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
1188 goto out;
1189 }
1190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 for (i = 0; i < TW_Q_LENGTH; i++) {
1193 tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
1194 tw_dev->free_queue[i] = i;
1195 tw_dev->state[i] = TW_S_INITIAL;
1196 }
1197
1198 tw_dev->pending_head = TW_Q_START;
1199 tw_dev->pending_tail = TW_Q_START;
1200 tw_dev->free_head = TW_Q_START;
1201 tw_dev->free_tail = TW_Q_START;
1202 tw_dev->error_sequence_id = 1;
1203 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1204
Jes Sorensena12e25bd2006-01-11 08:39:45 -05001205 mutex_init(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 init_waitqueue_head(&tw_dev->ioctl_wqueue);
1207
1208 retval = 0;
1209out:
1210 return retval;
1211} /* End twa_initialize_device_extension() */
1212
1213/* This function is the interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +01001214static irqreturn_t twa_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
1216 int request_id, error = 0;
1217 u32 status_reg_value;
1218 TW_Response_Queue response_que;
1219 TW_Command_Full *full_command_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
1221 int handled = 0;
1222
1223 /* Get the per adapter lock */
1224 spin_lock(tw_dev->host->host_lock);
1225
1226 /* Read the registers */
1227 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1228
1229 /* Check if this is our interrupt, otherwise bail */
1230 if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
1231 goto twa_interrupt_bail;
1232
1233 handled = 1;
1234
adam radford4039c302006-10-26 18:01:06 -07001235 /* If we are resetting, bail */
1236 if (test_bit(TW_IN_RESET, &tw_dev->flags))
1237 goto twa_interrupt_bail;
1238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 /* Check controller for errors */
1240 if (twa_check_bits(status_reg_value)) {
1241 if (twa_decode_bits(tw_dev, status_reg_value)) {
1242 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1243 goto twa_interrupt_bail;
1244 }
1245 }
1246
1247 /* Handle host interrupt */
1248 if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
1249 TW_CLEAR_HOST_INTERRUPT(tw_dev);
1250
1251 /* Handle attention interrupt */
1252 if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
1253 TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
1254 if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
1255 twa_get_request_id(tw_dev, &request_id);
1256
1257 error = twa_aen_read_queue(tw_dev, request_id);
1258 if (error) {
1259 tw_dev->state[request_id] = TW_S_COMPLETED;
1260 twa_free_request_id(tw_dev, request_id);
1261 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
1262 }
1263 }
1264 }
1265
1266 /* Handle command interrupt */
1267 if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
1268 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1269 /* Drain as many pending commands as we can */
1270 while (tw_dev->pending_request_count > 0) {
1271 request_id = tw_dev->pending_queue[tw_dev->pending_head];
1272 if (tw_dev->state[request_id] != TW_S_PENDING) {
1273 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
1274 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1275 goto twa_interrupt_bail;
1276 }
1277 if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
1278 tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
1279 tw_dev->pending_request_count--;
1280 } else {
1281 /* If we get here, we will continue re-posting on the next command interrupt */
1282 break;
1283 }
1284 }
1285 }
1286
1287 /* Handle response interrupt */
1288 if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
1289
1290 /* Drain the response queue from the board */
1291 while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
1292 /* Complete the response */
1293 response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1294 request_id = TW_RESID_OUT(response_que.response_id);
1295 full_command_packet = tw_dev->command_packet_virt[request_id];
1296 error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 /* Check for command packet errors */
1298 if (full_command_packet->command.newcommand.status != 0) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001299 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 error = twa_fill_sense(tw_dev, request_id, 1, 1);
1301 } else {
1302 /* Skip ioctl error prints */
1303 if (request_id != tw_dev->chrdev_request_id) {
1304 error = twa_fill_sense(tw_dev, request_id, 0, 1);
1305 }
1306 }
1307 }
1308
1309 /* Check for correct state */
1310 if (tw_dev->state[request_id] != TW_S_POSTED) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001311 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
1313 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1314 goto twa_interrupt_bail;
1315 }
1316 }
1317
1318 /* Check for internal command completion */
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001319 if (tw_dev->srb[request_id] == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (request_id != tw_dev->chrdev_request_id) {
1321 if (twa_aen_complete(tw_dev, request_id))
1322 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
1323 } else {
1324 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1325 wake_up(&tw_dev->ioctl_wqueue);
1326 }
1327 } else {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001328 struct scsi_cmnd *cmd;
1329
1330 cmd = tw_dev->srb[request_id];
1331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 twa_scsiop_execute_scsi_complete(tw_dev, request_id);
1333 /* If no error command was a success */
1334 if (error == 0) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001335 cmd->result = (DID_OK << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337
1338 /* If error, command failed */
1339 if (error == 1) {
1340 /* Ask for a host reset */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001341 cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 }
1343
1344 /* Report residual bytes for single sgl */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001345 if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
1346 if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
1347 scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
1349
1350 /* Now complete the io */
1351 tw_dev->state[request_id] = TW_S_COMPLETED;
1352 twa_free_request_id(tw_dev, request_id);
1353 tw_dev->posted_request_count--;
1354 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
1355 twa_unmap_scsi_data(tw_dev, request_id);
1356 }
1357
1358 /* Check for valid status after each drain */
1359 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1360 if (twa_check_bits(status_reg_value)) {
1361 if (twa_decode_bits(tw_dev, status_reg_value)) {
1362 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1363 goto twa_interrupt_bail;
1364 }
1365 }
1366 }
1367 }
1368
1369twa_interrupt_bail:
1370 spin_unlock(tw_dev->host->host_lock);
1371 return IRQ_RETVAL(handled);
1372} /* End twa_interrupt() */
1373
1374/* This function will load the request id and various sgls for ioctls */
adam radford0e78d152007-07-20 15:28:28 -07001375static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
1377 TW_Command *oldcommand;
1378 TW_Command_Apache *newcommand;
1379 TW_SG_Entry *sgl;
adam radford0e78d152007-07-20 15:28:28 -07001380 unsigned int pae = 0;
1381
1382 if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
1383 pae = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1386 newcommand = &full_command_packet->command.newcommand;
adam radford4039c302006-10-26 18:01:06 -07001387 newcommand->request_id__lunl =
1388 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
adam radford53ca3532009-12-10 11:53:31 -08001389 if (length) {
1390 newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1391 newcommand->sg_list[0].length = cpu_to_le32(length);
1392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 newcommand->sgl_entries__lunh =
adam radford53ca3532009-12-10 11:53:31 -08001394 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 } else {
1396 oldcommand = &full_command_packet->command.oldcommand;
1397 oldcommand->request_id = request_id;
1398
1399 if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
1400 /* Load the sg list */
adam radford0e78d152007-07-20 15:28:28 -07001401 if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
1402 sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
1403 else
1404 sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
adam radford75913d92006-03-15 12:43:19 -08001405 sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1406 sgl->length = cpu_to_le32(length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
adam radford0e78d152007-07-20 15:28:28 -07001408 oldcommand->size += pae;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 }
1410 }
1411} /* End twa_load_sgl() */
1412
1413/* This function will perform a pci-dma mapping for a scatter gather list */
1414static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
1415{
1416 int use_sg;
1417 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001419 use_sg = scsi_dma_map(cmd);
1420 if (!use_sg)
1421 return 0;
1422 else if (use_sg < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001424 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 }
1426
1427 cmd->SCp.phase = TW_PHASE_SGLIST;
1428 cmd->SCp.have_data_in = use_sg;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001429
1430 return use_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431} /* End twa_map_scsi_sg_data() */
1432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433/* This function will poll for a response interrupt of a request */
1434static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
1435{
1436 int retval = 1, found = 0, response_request_id;
1437 TW_Response_Queue response_queue;
1438 TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
1439
1440 if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
1441 response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1442 response_request_id = TW_RESID_OUT(response_queue.response_id);
1443 if (request_id != response_request_id) {
1444 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
1445 goto out;
1446 }
1447 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1448 if (full_command_packet->command.newcommand.status != 0) {
1449 /* bad response */
1450 twa_fill_sense(tw_dev, request_id, 0, 0);
1451 goto out;
1452 }
1453 found = 1;
1454 } else {
1455 if (full_command_packet->command.oldcommand.status != 0) {
1456 /* bad response */
1457 twa_fill_sense(tw_dev, request_id, 0, 0);
1458 goto out;
1459 }
1460 found = 1;
1461 }
1462 }
1463
1464 if (found)
1465 retval = 0;
1466out:
1467 return retval;
1468} /* End twa_poll_response() */
1469
1470/* This function will poll the status register for a flag */
1471static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1472{
1473 u32 status_reg_value;
1474 unsigned long before;
1475 int retval = 1;
1476
1477 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1478 before = jiffies;
1479
1480 if (twa_check_bits(status_reg_value))
1481 twa_decode_bits(tw_dev, status_reg_value);
1482
1483 while ((status_reg_value & flag) != flag) {
1484 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1485
1486 if (twa_check_bits(status_reg_value))
1487 twa_decode_bits(tw_dev, status_reg_value);
1488
1489 if (time_after(jiffies, before + HZ * seconds))
1490 goto out;
1491
1492 msleep(50);
1493 }
1494 retval = 0;
1495out:
1496 return retval;
1497} /* End twa_poll_status() */
1498
1499/* This function will poll the status register for disappearance of a flag */
1500static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1501{
1502 u32 status_reg_value;
1503 unsigned long before;
1504 int retval = 1;
1505
1506 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1507 before = jiffies;
1508
1509 if (twa_check_bits(status_reg_value))
1510 twa_decode_bits(tw_dev, status_reg_value);
1511
1512 while ((status_reg_value & flag) != 0) {
1513 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1514 if (twa_check_bits(status_reg_value))
1515 twa_decode_bits(tw_dev, status_reg_value);
1516
1517 if (time_after(jiffies, before + HZ * seconds))
1518 goto out;
1519
1520 msleep(50);
1521 }
1522 retval = 0;
1523out:
1524 return retval;
1525} /* End twa_poll_status_gone() */
1526
1527/* This function will attempt to post a command packet to the board */
1528static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
1529{
1530 u32 status_reg_value;
1531 dma_addr_t command_que_value;
1532 int retval = 1;
1533
1534 command_que_value = tw_dev->command_packet_phys[request_id];
adam radford4039c302006-10-26 18:01:06 -07001535
1536 /* For 9650SE write low 4 bytes first */
adam radford0e78d152007-07-20 15:28:28 -07001537 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1538 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001539 command_que_value += TW_COMMAND_OFFSET;
1540 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
1541 }
1542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1544
1545 if (twa_check_bits(status_reg_value))
1546 twa_decode_bits(tw_dev, status_reg_value);
1547
1548 if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
1549
1550 /* Only pend internal driver commands */
1551 if (!internal) {
1552 retval = SCSI_MLQUEUE_HOST_BUSY;
1553 goto out;
1554 }
1555
1556 /* Couldn't post the command packet, so we do it later */
1557 if (tw_dev->state[request_id] != TW_S_PENDING) {
1558 tw_dev->state[request_id] = TW_S_PENDING;
1559 tw_dev->pending_request_count++;
1560 if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
1561 tw_dev->max_pending_request_count = tw_dev->pending_request_count;
1562 }
1563 tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
1564 tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
1565 }
1566 TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
1567 goto out;
1568 } else {
adam radford0e78d152007-07-20 15:28:28 -07001569 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1570 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001571 /* Now write upper 4 bytes */
1572 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 } else {
adam radford4039c302006-10-26 18:01:06 -07001574 if (sizeof(dma_addr_t) > 4) {
1575 command_que_value += TW_COMMAND_OFFSET;
1576 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1577 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
1578 } else {
1579 writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 }
1582 tw_dev->state[request_id] = TW_S_POSTED;
1583 tw_dev->posted_request_count++;
1584 if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
1585 tw_dev->max_posted_request_count = tw_dev->posted_request_count;
1586 }
1587 }
1588 retval = 0;
1589out:
1590 return retval;
1591} /* End twa_post_command_packet() */
1592
1593/* This function will reset a device extension */
adam radford0e78d152007-07-20 15:28:28 -07001594static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595{
1596 int i = 0;
1597 int retval = 1;
1598 unsigned long flags = 0;
1599
1600 set_bit(TW_IN_RESET, &tw_dev->flags);
1601 TW_DISABLE_INTERRUPTS(tw_dev);
1602 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1603 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1604
1605 /* Abort all requests that are in progress */
1606 for (i = 0; i < TW_Q_LENGTH; i++) {
1607 if ((tw_dev->state[i] != TW_S_FINISHED) &&
1608 (tw_dev->state[i] != TW_S_INITIAL) &&
1609 (tw_dev->state[i] != TW_S_COMPLETED)) {
1610 if (tw_dev->srb[i]) {
1611 tw_dev->srb[i]->result = (DID_RESET << 16);
1612 tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
1613 twa_unmap_scsi_data(tw_dev, i);
1614 }
1615 }
1616 }
1617
1618 /* Reset queues and counts */
1619 for (i = 0; i < TW_Q_LENGTH; i++) {
1620 tw_dev->free_queue[i] = i;
1621 tw_dev->state[i] = TW_S_INITIAL;
1622 }
1623 tw_dev->free_head = TW_Q_START;
1624 tw_dev->free_tail = TW_Q_START;
1625 tw_dev->posted_request_count = 0;
1626 tw_dev->pending_request_count = 0;
1627 tw_dev->pending_head = TW_Q_START;
1628 tw_dev->pending_tail = TW_Q_START;
1629 tw_dev->reset_print = 0;
1630
1631 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1632
1633 if (twa_reset_sequence(tw_dev, 1))
1634 goto out;
1635
1636 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
adam radford4039c302006-10-26 18:01:06 -07001637 clear_bit(TW_IN_RESET, &tw_dev->flags);
1638 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 retval = 0;
1641out:
1642 return retval;
1643} /* End twa_reset_device_extension() */
1644
1645/* This function will reset a controller */
1646static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
1647{
1648 int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
1649
1650 while (tries < TW_MAX_RESET_TRIES) {
adam radford49bfd8d2005-09-21 17:20:14 -07001651 if (do_soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 TW_SOFT_RESET(tw_dev);
adam radford49bfd8d2005-09-21 17:20:14 -07001653 /* Clear pchip/response queue on 9550SX */
1654 if (twa_empty_response_queue_large(tw_dev)) {
1655 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence");
1656 do_soft_reset = 1;
1657 tries++;
1658 continue;
1659 }
1660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 /* Make sure controller is in a good state */
1663 if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
1664 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
1665 do_soft_reset = 1;
1666 tries++;
1667 continue;
1668 }
1669
1670 /* Empty response queue */
1671 if (twa_empty_response_queue(tw_dev)) {
1672 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
1673 do_soft_reset = 1;
1674 tries++;
1675 continue;
1676 }
1677
1678 flashed = 0;
1679
1680 /* Check for compatibility/flash */
1681 if (twa_check_srl(tw_dev, &flashed)) {
1682 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
1683 do_soft_reset = 1;
1684 tries++;
1685 continue;
1686 } else {
1687 if (flashed) {
1688 tries++;
1689 continue;
1690 }
1691 }
1692
1693 /* Drain the AEN queue */
1694 if (twa_aen_drain_queue(tw_dev, soft_reset)) {
1695 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
1696 do_soft_reset = 1;
1697 tries++;
1698 continue;
1699 }
1700
1701 /* If we got here, controller is in a good state */
1702 retval = 0;
1703 goto out;
1704 }
1705out:
1706 return retval;
1707} /* End twa_reset_sequence() */
1708
1709/* This funciton returns unit geometry in cylinders/heads/sectors */
1710static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
1711{
1712 int heads, sectors, cylinders;
1713 TW_Device_Extension *tw_dev;
1714
1715 tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
1716
1717 if (capacity >= 0x200000) {
1718 heads = 255;
1719 sectors = 63;
1720 cylinders = sector_div(capacity, heads * sectors);
1721 } else {
1722 heads = 64;
1723 sectors = 32;
1724 cylinders = sector_div(capacity, heads * sectors);
1725 }
1726
1727 geom[0] = heads;
1728 geom[1] = sectors;
1729 geom[2] = cylinders;
1730
1731 return 0;
1732} /* End twa_scsi_biosparam() */
1733
1734/* This is the new scsi eh reset function */
1735static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
1736{
1737 TW_Device_Extension *tw_dev = NULL;
1738 int retval = FAILED;
1739
1740 tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 tw_dev->num_resets++;
1743
Jeff Garzik017560f2005-10-24 18:04:36 -04001744 sdev_printk(KERN_WARNING, SCpnt->device,
1745 "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
1746 TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
adam radford4039c302006-10-26 18:01:06 -07001748 /* Make sure we are not issuing an ioctl or resetting from ioctl */
1749 mutex_lock(&tw_dev->ioctl_lock);
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 /* Now reset the card and some of the device extension data */
adam radford0e78d152007-07-20 15:28:28 -07001752 if (twa_reset_device_extension(tw_dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
1754 goto out;
1755 }
1756
1757 retval = SUCCESS;
1758out:
adam radford4039c302006-10-26 18:01:06 -07001759 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 return retval;
1761} /* End twa_scsi_eh_reset() */
1762
1763/* This is the main scsi queue function to handle scsi opcodes */
1764static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1765{
1766 int request_id, retval;
1767 TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1768
adam radford4039c302006-10-26 18:01:06 -07001769 /* If we are resetting due to timed out ioctl, report as busy */
1770 if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
1771 retval = SCSI_MLQUEUE_HOST_BUSY;
1772 goto out;
1773 }
1774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 /* Check if this FW supports luns */
adam radford4039c302006-10-26 18:01:06 -07001776 if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 SCpnt->result = (DID_BAD_TARGET << 16);
1778 done(SCpnt);
1779 retval = 0;
1780 goto out;
1781 }
1782
1783 /* Save done function into scsi_cmnd struct */
1784 SCpnt->scsi_done = done;
1785
1786 /* Get a free request id */
1787 twa_get_request_id(tw_dev, &request_id);
1788
1789 /* Save the scsi command for use by the ISR */
1790 tw_dev->srb[request_id] = SCpnt;
1791
1792 /* Initialize phase to zero */
1793 SCpnt->SCp.phase = TW_PHASE_INITIAL;
1794
1795 retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
1796 switch (retval) {
1797 case SCSI_MLQUEUE_HOST_BUSY:
1798 twa_free_request_id(tw_dev, request_id);
1799 break;
1800 case 1:
1801 tw_dev->state[request_id] = TW_S_COMPLETED;
1802 twa_free_request_id(tw_dev, request_id);
1803 SCpnt->result = (DID_ERROR << 16);
1804 done(SCpnt);
1805 retval = 0;
1806 }
1807out:
1808 return retval;
1809} /* End twa_scsi_queue() */
1810
1811/* This function hands scsi cdb's to the firmware */
1812static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
1813{
1814 TW_Command_Full *full_command_packet;
1815 TW_Command_Apache *command_packet;
1816 u32 num_sectors = 0x0;
1817 int i, sg_count;
1818 struct scsi_cmnd *srb = NULL;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001819 struct scatterlist *sglist = NULL, *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 int retval = 1;
1821
1822 if (tw_dev->srb[request_id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 srb = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001824 if (scsi_sglist(srb))
1825 sglist = scsi_sglist(srb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 }
1827
1828 /* Initialize command packet */
1829 full_command_packet = tw_dev->command_packet_virt[request_id];
1830 full_command_packet->header.header_desc.size_header = 128;
1831 full_command_packet->header.status_block.error = 0;
1832 full_command_packet->header.status_block.severity__reserved = 0;
1833
1834 command_packet = &full_command_packet->command.newcommand;
1835 command_packet->status = 0;
1836 command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
1837
1838 /* We forced 16 byte cdb use earlier */
1839 if (!cdb)
1840 memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
1841 else
1842 memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
1843
1844 if (srb) {
1845 command_packet->unit = srb->device->id;
1846 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001847 cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 } else {
1849 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001850 cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 command_packet->unit = 0;
1852 }
1853
1854 command_packet->sgl_offset = 16;
1855
1856 if (!sglistarg) {
1857 /* Map sglist from scsi layer to cmd packet */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001859 if (scsi_sg_count(srb)) {
1860 if ((scsi_sg_count(srb) == 1) &&
1861 (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001862 if (srb->sc_data_direction == DMA_TO_DEVICE ||
1863 srb->sc_data_direction == DMA_BIDIRECTIONAL)
1864 scsi_sg_copy_to_buffer(srb,
1865 tw_dev->generic_buffer_virt[request_id],
1866 TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001867 command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
1868 command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 } else {
1870 sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
1871 if (sg_count == 0)
1872 goto out;
1873
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001874 scsi_for_each_sg(srb, sg, sg_count, i) {
1875 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
1876 command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
adam radford75913d92006-03-15 12:43:19 -08001877 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
1879 goto out;
1880 }
1881 }
1882 }
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001883 command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 }
1885 } else {
1886 /* Internal cdb post */
1887 for (i = 0; i < use_sg; i++) {
adam radford75913d92006-03-15 12:43:19 -08001888 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
1889 command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length);
1890 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
1892 goto out;
1893 }
1894 }
adam radford75913d92006-03-15 12:43:19 -08001895 command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 }
1897
1898 if (srb) {
1899 if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
1900 num_sectors = (u32)srb->cmnd[4];
1901
1902 if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
1903 num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
1904 }
1905
1906 /* Update sector statistic */
1907 tw_dev->sector_count = num_sectors;
1908 if (tw_dev->sector_count > tw_dev->max_sector_count)
1909 tw_dev->max_sector_count = tw_dev->sector_count;
1910
1911 /* Update SG statistics */
1912 if (srb) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001913 tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
1915 tw_dev->max_sgl_entries = tw_dev->sgl_entries;
1916 }
1917
1918 /* Now post the command to the board */
1919 if (srb) {
1920 retval = twa_post_command_packet(tw_dev, request_id, 0);
1921 } else {
1922 twa_post_command_packet(tw_dev, request_id, 1);
1923 retval = 0;
1924 }
1925out:
1926 return retval;
1927} /* End twa_scsiop_execute_scsi() */
1928
1929/* This function completes an execute scsi operation */
1930static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
1931{
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001932 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001933
1934 if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH &&
1935 (cmd->sc_data_direction == DMA_FROM_DEVICE ||
1936 cmd->sc_data_direction == DMA_BIDIRECTIONAL)) {
FUJITA Tomonorib1192d52007-05-31 15:24:03 +09001937 if (scsi_sg_count(cmd) == 1) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001938 void *buf = tw_dev->generic_buffer_virt[request_id];
1939
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001940 scsi_sg_copy_from_buffer(cmd, buf, TW_SECTOR_SIZE);
adam radfordd327d082005-09-09 15:55:13 -07001941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 }
1943} /* End twa_scsiop_execute_scsi_complete() */
1944
1945/* This function tells the controller to shut down */
1946static void __twa_shutdown(TW_Device_Extension *tw_dev)
1947{
1948 /* Disable interrupts */
1949 TW_DISABLE_INTERRUPTS(tw_dev);
1950
adam radford4039c302006-10-26 18:01:06 -07001951 /* Free up the IRQ */
1952 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
1953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
1955
1956 /* Tell the card we are shutting down */
1957 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
1958 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
1959 } else {
1960 printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
1961 }
1962
1963 /* Clear all interrupts just before exit */
1964 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1965} /* End __twa_shutdown() */
1966
1967/* Wrapper for __twa_shutdown */
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001968static void twa_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001970 struct Scsi_Host *host = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
1972
1973 __twa_shutdown(tw_dev);
1974} /* End twa_shutdown() */
1975
1976/* This function will look up a string */
1977static char *twa_string_lookup(twa_message_type *table, unsigned int code)
1978{
1979 int index;
1980
1981 for (index = 0; ((code != table[index].code) &&
1982 (table[index].text != (char *)0)); index++);
1983 return(table[index].text);
1984} /* End twa_string_lookup() */
1985
1986/* This function will perform a pci-dma unmap */
1987static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
1988{
1989 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
adam radford8454e982009-05-05 11:45:37 -07001991 if (cmd->SCp.phase == TW_PHASE_SGLIST)
1992 scsi_dma_unmap(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993} /* End twa_unmap_scsi_data() */
1994
adam radford4deedd82010-03-08 12:37:46 -08001995/* This function gets called when a disk is coming on-line */
1996static int twa_slave_configure(struct scsi_device *sdev)
1997{
1998 /* Force 60 second timeout */
1999 blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
2000
2001 return 0;
2002} /* End twa_slave_configure() */
2003
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004/* scsi_host_template initializer */
2005static struct scsi_host_template driver_template = {
2006 .module = THIS_MODULE,
2007 .name = "3ware 9000 Storage Controller",
2008 .queuecommand = twa_scsi_queue,
2009 .eh_host_reset_handler = twa_scsi_eh_reset,
2010 .bios_param = twa_scsi_biosparam,
2011 .change_queue_depth = twa_change_queue_depth,
2012 .can_queue = TW_Q_LENGTH-2,
adam radford4deedd82010-03-08 12:37:46 -08002013 .slave_configure = twa_slave_configure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 .this_id = -1,
2015 .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH,
2016 .max_sectors = TW_MAX_SECTORS,
2017 .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
2018 .use_clustering = ENABLE_CLUSTERING,
2019 .shost_attrs = twa_host_attrs,
2020 .emulated = 1
2021};
2022
2023/* This function will probe and initialize a card */
2024static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
2025{
2026 struct Scsi_Host *host = NULL;
2027 TW_Device_Extension *tw_dev;
adam radford3dabec72008-07-22 16:47:40 -07002028 unsigned long mem_addr, mem_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 int retval = -ENODEV;
2030
2031 retval = pci_enable_device(pdev);
2032 if (retval) {
2033 TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
2034 goto out_disable_device;
2035 }
2036
2037 pci_set_master(pdev);
Tony Battersby1e6c38c2007-11-09 13:04:35 -05002038 pci_try_set_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
Yang Hongyang6a355282009-04-06 19:01:13 -07002040 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2041 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
Yang Hongyang284901a2009-04-06 19:01:15 -07002042 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2043 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford0e78d152007-07-20 15:28:28 -07002044 TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
2045 retval = -ENODEV;
2046 goto out_disable_device;
2047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048
2049 host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
2050 if (!host) {
2051 TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
2052 retval = -ENOMEM;
2053 goto out_disable_device;
2054 }
2055 tw_dev = (TW_Device_Extension *)host->hostdata;
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 /* Save values to device extension */
2058 tw_dev->host = host;
2059 tw_dev->tw_pci_dev = pdev;
2060
2061 if (twa_initialize_device_extension(tw_dev)) {
2062 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
2063 goto out_free_device_extension;
2064 }
2065
2066 /* Request IO regions */
2067 retval = pci_request_regions(pdev, "3w-9xxx");
2068 if (retval) {
2069 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
2070 goto out_free_device_extension;
2071 }
2072
adam radford3dabec72008-07-22 16:47:40 -07002073 if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
adam radford49bfd8d2005-09-21 17:20:14 -07002074 mem_addr = pci_resource_start(pdev, 1);
adam radford3dabec72008-07-22 16:47:40 -07002075 mem_len = pci_resource_len(pdev, 1);
2076 } else {
adam radford49bfd8d2005-09-21 17:20:14 -07002077 mem_addr = pci_resource_start(pdev, 2);
adam radford3dabec72008-07-22 16:47:40 -07002078 mem_len = pci_resource_len(pdev, 2);
2079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
2081 /* Save base address */
adam radford3dabec72008-07-22 16:47:40 -07002082 tw_dev->base_addr = ioremap(mem_addr, mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 if (!tw_dev->base_addr) {
2084 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
2085 goto out_release_mem_region;
2086 }
2087
2088 /* Disable interrupts on the card */
2089 TW_DISABLE_INTERRUPTS(tw_dev);
2090
2091 /* Initialize the card */
2092 if (twa_reset_sequence(tw_dev, 0))
adam radford4039c302006-10-26 18:01:06 -07002093 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
2095 /* Set host specific parameters */
adam radford0e78d152007-07-20 15:28:28 -07002096 if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
2097 (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
adam radford4039c302006-10-26 18:01:06 -07002098 host->max_id = TW_MAX_UNITS_9650SE;
2099 else
2100 host->max_id = TW_MAX_UNITS;
2101
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 host->max_cmd_len = TW_MAX_CDB_LEN;
2103
2104 /* Channels aren't supported by adapter */
adam radford4039c302006-10-26 18:01:06 -07002105 host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 host->max_channel = 0;
2107
2108 /* Register the card with the kernel SCSI layer */
2109 retval = scsi_add_host(host, &pdev->dev);
2110 if (retval) {
2111 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
adam radford4039c302006-10-26 18:01:06 -07002112 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
2114
2115 pci_set_drvdata(pdev, host);
2116
adam radford3dabec72008-07-22 16:47:40 -07002117 printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%lx, IRQ: %d.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 host->host_no, mem_addr, pdev->irq);
2119 printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
2120 host->host_no,
2121 (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
2122 TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
2123 (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
2124 TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
adam radford75913d92006-03-15 12:43:19 -08002125 le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
2126 TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
adam radford3dabec72008-07-22 16:47:40 -07002128 /* Try to enable MSI */
2129 if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
2130 !pci_enable_msi(pdev))
2131 set_bit(TW_USING_MSI, &tw_dev->flags);
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 /* Now setup the interrupt handler */
Thomas Gleixner1d6f3592006-07-01 19:29:42 -07002134 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (retval) {
2136 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
2137 goto out_remove_host;
2138 }
2139
2140 twa_device_extension_list[twa_device_extension_count] = tw_dev;
2141 twa_device_extension_count++;
2142
2143 /* Re-enable interrupts on the card */
2144 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2145
2146 /* Finally, scan the host */
2147 scsi_scan_host(host);
2148
2149 if (twa_major == -1) {
2150 if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
2151 TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
2152 }
2153 return 0;
2154
2155out_remove_host:
adam radford3dabec72008-07-22 16:47:40 -07002156 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2157 pci_disable_msi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 scsi_remove_host(host);
adam radford4039c302006-10-26 18:01:06 -07002159out_iounmap:
2160 iounmap(tw_dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161out_release_mem_region:
2162 pci_release_regions(pdev);
2163out_free_device_extension:
2164 twa_free_device_extension(tw_dev);
2165 scsi_host_put(host);
2166out_disable_device:
2167 pci_disable_device(pdev);
2168
2169 return retval;
2170} /* End twa_probe() */
2171
2172/* This function is called to remove a device */
2173static void twa_remove(struct pci_dev *pdev)
2174{
2175 struct Scsi_Host *host = pci_get_drvdata(pdev);
2176 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2177
2178 scsi_remove_host(tw_dev->host);
2179
2180 /* Unregister character device */
2181 if (twa_major >= 0) {
2182 unregister_chrdev(twa_major, "twa");
2183 twa_major = -1;
2184 }
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 /* Shutdown the card */
2187 __twa_shutdown(tw_dev);
2188
adam radford3dabec72008-07-22 16:47:40 -07002189 /* Disable MSI if enabled */
2190 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2191 pci_disable_msi(pdev);
2192
adam radford4039c302006-10-26 18:01:06 -07002193 /* Free IO remapping */
2194 iounmap(tw_dev->base_addr);
2195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 /* Free up the mem region */
2197 pci_release_regions(pdev);
2198
2199 /* Free up device extension resources */
2200 twa_free_device_extension(tw_dev);
2201
2202 scsi_host_put(tw_dev->host);
2203 pci_disable_device(pdev);
2204 twa_device_extension_count--;
2205} /* End twa_remove() */
2206
adam radford7a252fe2009-03-09 12:15:01 -08002207#ifdef CONFIG_PM
2208/* This function is called on PCI suspend */
2209static int twa_suspend(struct pci_dev *pdev, pm_message_t state)
2210{
2211 struct Scsi_Host *host = pci_get_drvdata(pdev);
2212 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2213
2214 printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no);
2215
2216 TW_DISABLE_INTERRUPTS(tw_dev);
2217 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
2218
2219 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2220 pci_disable_msi(pdev);
2221
2222 /* Tell the card we are shutting down */
2223 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
2224 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend");
2225 } else {
2226 printk(KERN_WARNING "3w-9xxx: Suspend complete.\n");
2227 }
2228 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
2229
2230 pci_save_state(pdev);
2231 pci_disable_device(pdev);
2232 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2233
2234 return 0;
2235} /* End twa_suspend() */
2236
2237/* This function is called on PCI resume */
2238static int twa_resume(struct pci_dev *pdev)
2239{
2240 int retval = 0;
2241 struct Scsi_Host *host = pci_get_drvdata(pdev);
2242 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2243
2244 printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no);
2245 pci_set_power_state(pdev, PCI_D0);
2246 pci_enable_wake(pdev, PCI_D0, 0);
2247 pci_restore_state(pdev);
2248
2249 retval = pci_enable_device(pdev);
2250 if (retval) {
2251 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume");
2252 return retval;
2253 }
2254
2255 pci_set_master(pdev);
2256 pci_try_set_mwi(pdev);
2257
Yang Hongyange9304382009-04-13 14:40:14 -07002258 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2259 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
2260 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2261 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford7a252fe2009-03-09 12:15:01 -08002262 TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
2263 retval = -ENODEV;
2264 goto out_disable_device;
2265 }
2266
2267 /* Initialize the card */
2268 if (twa_reset_sequence(tw_dev, 0)) {
2269 retval = -ENODEV;
2270 goto out_disable_device;
2271 }
2272
2273 /* Now setup the interrupt handler */
2274 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
2275 if (retval) {
2276 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume");
2277 retval = -ENODEV;
2278 goto out_disable_device;
2279 }
2280
2281 /* Now enable MSI if enabled */
2282 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2283 pci_enable_msi(pdev);
2284
2285 /* Re-enable interrupts on the card */
2286 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2287
2288 printk(KERN_WARNING "3w-9xxx: Resume complete.\n");
2289 return 0;
2290
2291out_disable_device:
2292 scsi_remove_host(host);
2293 pci_disable_device(pdev);
2294
2295 return retval;
2296} /* End twa_resume() */
2297#endif
2298
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299/* PCI Devices supported by this driver */
2300static struct pci_device_id twa_pci_tbl[] __devinitdata = {
2301 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
2302 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford49bfd8d2005-09-21 17:20:14 -07002303 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
2304 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford4039c302006-10-26 18:01:06 -07002305 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
2306 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford0e78d152007-07-20 15:28:28 -07002307 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
2308 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 { }
2310};
2311MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
2312
2313/* pci_driver initializer */
2314static struct pci_driver twa_driver = {
2315 .name = "3w-9xxx",
2316 .id_table = twa_pci_tbl,
2317 .probe = twa_probe,
2318 .remove = twa_remove,
adam radford7a252fe2009-03-09 12:15:01 -08002319#ifdef CONFIG_PM
2320 .suspend = twa_suspend,
2321 .resume = twa_resume,
2322#endif
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002323 .shutdown = twa_shutdown
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324};
2325
2326/* This function is called on driver initialization */
2327static int __init twa_init(void)
2328{
2329 printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
2330
Henrik Kretzschmardcbccbde2006-09-25 16:58:58 -07002331 return pci_register_driver(&twa_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332} /* End twa_init() */
2333
2334/* This function is called on driver exit */
2335static void __exit twa_exit(void)
2336{
2337 pci_unregister_driver(&twa_driver);
2338} /* End twa_exit() */
2339
2340module_init(twa_init);
2341module_exit(twa_exit);
2342