blob: e9788f55ab1348050edff7025bf79fe0664cf11f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
3
4 Written By: Adam Radford <linuxraid@amcc.com>
adam radford75913d92006-03-15 12:43:19 -08005 Modifications By: Tom Couch <linuxraid@amcc.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.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 NO WARRANTY
19 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23 solely responsible for determining the appropriateness of using and
24 distributing the Program and assumes all risks associated with its
25 exercise of rights under this Agreement, including but not limited to
26 the risks and costs of program errors, damage to or loss of data,
27 programs or equipment, and unavailability or interruption of operations.
28
29 DISCLAIMER OF LIABILITY
30 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37
38 You should have received a copy of the GNU General Public License
39 along with this program; if not, write to the Free Software
40 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41
42 Bugs/Comments/Suggestions should be mailed to:
43 linuxraid@amcc.com
44
45 For more information, goto:
46 http://www.amcc.com
47
48 Note: This version of the driver does not contain a bundled firmware
49 image.
50
51 History
52 -------
53 2.26.02.000 - Driver cleanup for kernel submission.
54 2.26.02.001 - Replace schedule_timeout() calls with msleep().
55 2.26.02.002 - Add support for PAE mode.
56 Add lun support.
57 Fix twa_remove() to free irq handler/unregister_chrdev()
58 before shutting down card.
59 Change to new 'change_queue_depth' api.
60 Fix 'handled=1' ISR usage, remove bogus IRQ check.
61 Remove un-needed eh_abort handler.
62 Add support for embedded firmware error strings.
adam radfordd327d082005-09-09 15:55:13 -070063 2.26.02.003 - Correctly handle single sgl's with use_sg=1.
adam radford49bfd8d2005-09-21 17:20:14 -070064 2.26.02.004 - Add support for 9550SX controllers.
adam radford62288f12006-02-05 14:51:43 -080065 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher.
adam radford75913d92006-03-15 12:43:19 -080066 2.26.02.006 - Fix 9550SX pchip reset timeout.
67 Add big endian support.
adam radford1e08dcb2006-04-11 11:25:09 -070068 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic().
adam radford4039c302006-10-26 18:01:06 -070069 2.26.02.008 - Free irq handler in __twa_shutdown().
70 Serialize reset code.
71 Add support for 9650SE controllers.
adam radford0e78d152007-07-20 15:28:28 -070072 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
73 2.26.02.010 - Add support for 9690SA controllers.
adam radford3dabec72008-07-22 16:47:40 -070074 2.26.02.011 - Increase max AENs drained to 256.
75 Add MSI support and "use_msi" module parameter.
76 Fix bug in twa_get_param() on 4GB+.
77 Use pci_resource_len() for ioremap().
adam radford7a252fe2009-03-09 12:15:01 -080078 2.26.02.012 - Add power management support.
adam radford53ca3532009-12-10 11:53:31 -080079 2.26.02.013 - Fix bug in twa_load_sgl().
Linus Torvalds1da177e2005-04-16 15:20:36 -070080*/
81
82#include <linux/module.h>
83#include <linux/reboot.h>
84#include <linux/spinlock.h>
85#include <linux/interrupt.h>
86#include <linux/moduleparam.h>
87#include <linux/errno.h>
88#include <linux/types.h>
89#include <linux/delay.h>
90#include <linux/pci.h>
91#include <linux/time.h>
Jes Sorensena12e25bd2006-01-11 08:39:45 -050092#include <linux/mutex.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -060093#include <linux/smp_lock.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090094#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070095#include <asm/io.h>
96#include <asm/irq.h>
97#include <asm/uaccess.h>
98#include <scsi/scsi.h>
99#include <scsi/scsi_host.h>
100#include <scsi/scsi_tcq.h>
101#include <scsi/scsi_cmnd.h>
102#include "3w-9xxx.h"
103
104/* Globals */
adam radford53ca3532009-12-10 11:53:31 -0800105#define TW_DRIVER_VERSION "2.26.02.013"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
107static unsigned int twa_device_extension_count;
108static int twa_major = -1;
109extern struct timezone sys_tz;
110
111/* Module parameters */
112MODULE_AUTHOR ("AMCC");
113MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
114MODULE_LICENSE("GPL");
115MODULE_VERSION(TW_DRIVER_VERSION);
116
adam radford3dabec72008-07-22 16:47:40 -0700117static int use_msi = 0;
118module_param(use_msi, int, S_IRUGO);
119MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/* Function prototypes */
122static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
123static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
124static char *twa_aen_severity_lookup(unsigned char severity_code);
125static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
126static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
127static int twa_chrdev_open(struct inode *inode, struct file *file);
128static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
129static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
130static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
131static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
132 u32 set_features, unsigned short current_fw_srl,
133 unsigned short current_fw_arch_id,
134 unsigned short current_fw_branch,
135 unsigned short current_fw_build,
136 unsigned short *fw_on_ctlr_srl,
137 unsigned short *fw_on_ctlr_arch_id,
138 unsigned short *fw_on_ctlr_branch,
139 unsigned short *fw_on_ctlr_build,
140 u32 *init_connect_result);
adam radford0e78d152007-07-20 15:28:28 -0700141static 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 -0700142static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
143static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
144static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
adam radford0e78d152007-07-20 15:28:28 -0700145static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
147static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
148static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
149static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
150static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
151
152/* Functions */
153
154/* Show some statistics about the card */
Tony Jonesee959b02008-02-22 00:13:36 +0100155static ssize_t twa_show_stats(struct device *dev,
156 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
Tony Jonesee959b02008-02-22 00:13:36 +0100158 struct Scsi_Host *host = class_to_shost(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
160 unsigned long flags = 0;
161 ssize_t len;
162
163 spin_lock_irqsave(tw_dev->host->host_lock, flags);
164 len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
165 "Current commands posted: %4d\n"
166 "Max commands posted: %4d\n"
167 "Current pending commands: %4d\n"
168 "Max pending commands: %4d\n"
169 "Last sgl length: %4d\n"
170 "Max sgl length: %4d\n"
171 "Last sector count: %4d\n"
172 "Max sector count: %4d\n"
173 "SCSI Host Resets: %4d\n"
174 "AEN's: %4d\n",
175 TW_DRIVER_VERSION,
176 tw_dev->posted_request_count,
177 tw_dev->max_posted_request_count,
178 tw_dev->pending_request_count,
179 tw_dev->max_pending_request_count,
180 tw_dev->sgl_entries,
181 tw_dev->max_sgl_entries,
182 tw_dev->sector_count,
183 tw_dev->max_sector_count,
184 tw_dev->num_resets,
185 tw_dev->aen_count);
186 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
187 return len;
188} /* End twa_show_stats() */
189
190/* This function will set a devices queue depth */
Mike Christiee881a172009-10-15 17:46:39 -0700191static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
192 int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193{
Mike Christiee881a172009-10-15 17:46:39 -0700194 if (reason != SCSI_QDEPTH_DEFAULT)
195 return -EOPNOTSUPP;
196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 if (queue_depth > TW_Q_LENGTH-2)
198 queue_depth = TW_Q_LENGTH-2;
199 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
200 return queue_depth;
201} /* End twa_change_queue_depth() */
202
203/* Create sysfs 'stats' entry */
Tony Jonesee959b02008-02-22 00:13:36 +0100204static struct device_attribute twa_host_stats_attr = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 .attr = {
206 .name = "stats",
207 .mode = S_IRUGO,
208 },
209 .show = twa_show_stats
210};
211
212/* Host attributes initializer */
Tony Jonesee959b02008-02-22 00:13:36 +0100213static struct device_attribute *twa_host_attrs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 &twa_host_stats_attr,
215 NULL,
216};
217
218/* File operations struct for character device */
Arjan van de Ven00977a52007-02-12 00:55:34 -0800219static const struct file_operations twa_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .owner = THIS_MODULE,
221 .ioctl = twa_chrdev_ioctl,
222 .open = twa_chrdev_open,
223 .release = NULL
224};
225
226/* This function will complete an aen request from the isr */
227static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
228{
229 TW_Command_Full *full_command_packet;
230 TW_Command *command_packet;
231 TW_Command_Apache_Header *header;
232 unsigned short aen;
233 int retval = 1;
234
235 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
236 tw_dev->posted_request_count--;
adam radford75913d92006-03-15 12:43:19 -0800237 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 full_command_packet = tw_dev->command_packet_virt[request_id];
239 command_packet = &full_command_packet->command.oldcommand;
240
241 /* First check for internal completion of set param for time sync */
242 if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
243 /* Keep reading the queue in case there are more aen's */
244 if (twa_aen_read_queue(tw_dev, request_id))
245 goto out2;
246 else {
247 retval = 0;
248 goto out;
249 }
250 }
251
252 switch (aen) {
253 case TW_AEN_QUEUE_EMPTY:
254 /* Quit reading the queue if this is the last one */
255 break;
256 case TW_AEN_SYNC_TIME_WITH_HOST:
257 twa_aen_sync_time(tw_dev, request_id);
258 retval = 0;
259 goto out;
260 default:
261 twa_aen_queue_event(tw_dev, header);
262
263 /* If there are more aen's, keep reading the queue */
264 if (twa_aen_read_queue(tw_dev, request_id))
265 goto out2;
266 else {
267 retval = 0;
268 goto out;
269 }
270 }
271 retval = 0;
272out2:
273 tw_dev->state[request_id] = TW_S_COMPLETED;
274 twa_free_request_id(tw_dev, request_id);
275 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
276out:
277 return retval;
278} /* End twa_aen_complete() */
279
280/* This function will drain aen queue */
281static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
282{
283 int request_id = 0;
284 char cdb[TW_MAX_CDB_LEN];
285 TW_SG_Entry sglist[1];
286 int finished = 0, count = 0;
287 TW_Command_Full *full_command_packet;
288 TW_Command_Apache_Header *header;
289 unsigned short aen;
290 int first_reset = 0, queue = 0, retval = 1;
291
292 if (no_check_reset)
293 first_reset = 0;
294 else
295 first_reset = 1;
296
297 full_command_packet = tw_dev->command_packet_virt[request_id];
298 memset(full_command_packet, 0, sizeof(TW_Command_Full));
299
300 /* Initialize cdb */
301 memset(&cdb, 0, TW_MAX_CDB_LEN);
302 cdb[0] = REQUEST_SENSE; /* opcode */
303 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
304
305 /* Initialize sglist */
306 memset(&sglist, 0, sizeof(TW_SG_Entry));
307 sglist[0].length = TW_SECTOR_SIZE;
308 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
309
310 if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
311 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
312 goto out;
313 }
314
315 /* Mark internal command */
316 tw_dev->srb[request_id] = NULL;
317
318 do {
319 /* Send command to the board */
320 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
321 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
322 goto out;
323 }
324
325 /* Now poll for completion */
326 if (twa_poll_response(tw_dev, request_id, 30)) {
327 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
328 tw_dev->posted_request_count--;
329 goto out;
330 }
331
332 tw_dev->posted_request_count--;
333 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
adam radford75913d92006-03-15 12:43:19 -0800334 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 queue = 0;
336 count++;
337
338 switch (aen) {
339 case TW_AEN_QUEUE_EMPTY:
340 if (first_reset != 1)
341 goto out;
342 else
343 finished = 1;
344 break;
345 case TW_AEN_SOFT_RESET:
346 if (first_reset == 0)
347 first_reset = 1;
348 else
349 queue = 1;
350 break;
351 case TW_AEN_SYNC_TIME_WITH_HOST:
352 break;
353 default:
354 queue = 1;
355 }
356
357 /* Now queue an event info */
358 if (queue)
359 twa_aen_queue_event(tw_dev, header);
360 } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
361
362 if (count == TW_MAX_AEN_DRAIN)
363 goto out;
364
365 retval = 0;
366out:
367 tw_dev->state[request_id] = TW_S_INITIAL;
368 return retval;
369} /* End twa_aen_drain_queue() */
370
371/* This function will queue an event */
372static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
373{
374 u32 local_time;
375 struct timeval time;
376 TW_Event *event;
377 unsigned short aen;
378 char host[16];
379 char *error_str;
380
381 tw_dev->aen_count++;
382
383 /* Fill out event info */
384 event = tw_dev->event_queue[tw_dev->error_index];
385
386 /* Check for clobber */
387 host[0] = '\0';
388 if (tw_dev->host) {
389 sprintf(host, " scsi%d:", tw_dev->host->host_no);
390 if (event->retrieved == TW_AEN_NOT_RETRIEVED)
391 tw_dev->aen_clobber = 1;
392 }
393
adam radford75913d92006-03-15 12:43:19 -0800394 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 memset(event, 0, sizeof(TW_Event));
396
397 event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
398 do_gettimeofday(&time);
399 local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
400 event->time_stamp_sec = local_time;
401 event->aen_code = aen;
402 event->retrieved = TW_AEN_NOT_RETRIEVED;
403 event->sequence_id = tw_dev->error_sequence_id;
404 tw_dev->error_sequence_id++;
405
406 /* Check for embedded error string */
407 error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
408
409 header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
410 event->parameter_len = strlen(header->err_specific_desc);
adam radford75913d92006-03-15 12:43:19 -0800411 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 -0700412 if (event->severity != TW_AEN_SEVERITY_DEBUG)
413 printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
414 host,
415 twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
416 TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
417 error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
418 header->err_specific_desc);
419 else
420 tw_dev->aen_count--;
421
422 if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
423 tw_dev->event_queue_wrapped = 1;
424 tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
425} /* End twa_aen_queue_event() */
426
427/* This function will read the aen queue from the isr */
428static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
429{
430 char cdb[TW_MAX_CDB_LEN];
431 TW_SG_Entry sglist[1];
432 TW_Command_Full *full_command_packet;
433 int retval = 1;
434
435 full_command_packet = tw_dev->command_packet_virt[request_id];
436 memset(full_command_packet, 0, sizeof(TW_Command_Full));
437
438 /* Initialize cdb */
439 memset(&cdb, 0, TW_MAX_CDB_LEN);
440 cdb[0] = REQUEST_SENSE; /* opcode */
441 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
442
443 /* Initialize sglist */
444 memset(&sglist, 0, sizeof(TW_SG_Entry));
445 sglist[0].length = TW_SECTOR_SIZE;
446 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
447
448 /* Mark internal command */
449 tw_dev->srb[request_id] = NULL;
450
451 /* Now post the command packet */
452 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
453 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
454 goto out;
455 }
456 retval = 0;
457out:
458 return retval;
459} /* End twa_aen_read_queue() */
460
461/* This function will look up an AEN severity string */
462static char *twa_aen_severity_lookup(unsigned char severity_code)
463{
464 char *retval = NULL;
465
466 if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
467 (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
468 goto out;
469
470 retval = twa_aen_severity_table[severity_code];
471out:
472 return retval;
473} /* End twa_aen_severity_lookup() */
474
475/* This function will sync firmware time with the host time */
476static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
477{
478 u32 schedulertime;
479 struct timeval utc;
480 TW_Command_Full *full_command_packet;
481 TW_Command *command_packet;
482 TW_Param_Apache *param;
483 u32 local_time;
484
485 /* Fill out the command packet */
486 full_command_packet = tw_dev->command_packet_virt[request_id];
487 memset(full_command_packet, 0, sizeof(TW_Command_Full));
488 command_packet = &full_command_packet->command.oldcommand;
489 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
490 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -0800491 command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
492 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 command_packet->size = TW_COMMAND_SIZE;
adam radford75913d92006-03-15 12:43:19 -0800494 command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 /* Setup the param */
497 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
498 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -0800499 param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */
500 param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
501 param->parameter_size_bytes = cpu_to_le16(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 /* Convert system time in UTC to local time seconds since last
504 Sunday 12:00AM */
505 do_gettimeofday(&utc);
506 local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
507 schedulertime = local_time - (3 * 86400);
adam radford75913d92006-03-15 12:43:19 -0800508 schedulertime = cpu_to_le32(schedulertime % 604800);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 memcpy(param->data, &schedulertime, sizeof(u32));
511
512 /* Mark internal command */
513 tw_dev->srb[request_id] = NULL;
514
515 /* Now post the command */
516 twa_post_command_packet(tw_dev, request_id, 1);
517} /* End twa_aen_sync_time() */
518
519/* This function will allocate memory and check if it is correctly aligned */
520static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
521{
522 int i;
523 dma_addr_t dma_handle;
524 unsigned long *cpu_addr;
525 int retval = 1;
526
527 cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
528 if (!cpu_addr) {
529 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
530 goto out;
531 }
532
533 if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
534 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
535 pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
536 goto out;
537 }
538
539 memset(cpu_addr, 0, size*TW_Q_LENGTH);
540
541 for (i = 0; i < TW_Q_LENGTH; i++) {
542 switch(which) {
543 case 0:
544 tw_dev->command_packet_phys[i] = dma_handle+(i*size);
545 tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
546 break;
547 case 1:
548 tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
549 tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
550 break;
551 }
552 }
553 retval = 0;
554out:
555 return retval;
556} /* End twa_allocate_memory() */
557
558/* This function will check the status register for unexpected bits */
559static int twa_check_bits(u32 status_reg_value)
560{
561 int retval = 1;
562
563 if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
564 goto out;
565 if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
566 goto out;
567
568 retval = 0;
569out:
570 return retval;
571} /* End twa_check_bits() */
572
573/* This function will check the srl and decide if we are compatible */
574static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
575{
576 int retval = 1;
577 unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
578 unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
579 u32 init_connect_result = 0;
580
581 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
582 TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
583 TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
584 TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
585 &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
586 &fw_on_ctlr_build, &init_connect_result)) {
587 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
588 goto out;
589 }
590
adam radford4039c302006-10-26 18:01:06 -0700591 tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl;
592 tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch;
593 tw_dev->tw_compat_info.working_build = fw_on_ctlr_build;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 /* Try base mode compatibility */
596 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
597 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
598 TW_EXTENDED_INIT_CONNECT,
599 TW_BASE_FW_SRL, TW_9000_ARCH_ID,
600 TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
601 &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
602 &fw_on_ctlr_branch, &fw_on_ctlr_build,
603 &init_connect_result)) {
604 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
605 goto out;
606 }
607 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
608 if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
609 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
610 } else {
611 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
612 }
613 goto out;
614 }
adam radford4039c302006-10-26 18:01:06 -0700615 tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL;
616 tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH;
617 tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
adam radford4039c302006-10-26 18:01:06 -0700619
620 /* Load rest of compatibility struct */
621 strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
622 tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
623 tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
624 tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
625 tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
626 tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
627 tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
628 tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
629 tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
630 tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 retval = 0;
633out:
634 return retval;
635} /* End twa_check_srl() */
636
637/* This function handles ioctl for the character device */
638static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
639{
640 long timeout;
641 unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
642 dma_addr_t dma_handle;
643 int request_id = 0;
644 unsigned int sequence_id = 0;
645 unsigned char event_index, start_index;
646 TW_Ioctl_Driver_Command driver_command;
647 TW_Ioctl_Buf_Apache *tw_ioctl;
648 TW_Lock *tw_lock;
649 TW_Command_Full *full_command_packet;
650 TW_Compatibility_Info *tw_compat_info;
651 TW_Event *event;
652 struct timeval current_time;
653 u32 current_time_ms;
654 TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
655 int retval = TW_IOCTL_ERROR_OS_EFAULT;
656 void __user *argp = (void __user *)arg;
657
658 /* Only let one of these through at a time */
Jes Sorensena12e25bd2006-01-11 08:39:45 -0500659 if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 retval = TW_IOCTL_ERROR_OS_EINTR;
661 goto out;
662 }
663
664 /* First copy down the driver command */
665 if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
666 goto out2;
667
668 /* Check data buffer size */
adam radford4039c302006-10-26 18:01:06 -0700669 if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 retval = TW_IOCTL_ERROR_OS_EINVAL;
671 goto out2;
672 }
673
674 /* Hardware can only do multiple of 512 byte transfers */
675 data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
676
677 /* Now allocate ioctl buf memory */
678 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);
679 if (!cpu_addr) {
680 retval = TW_IOCTL_ERROR_OS_ENOMEM;
681 goto out2;
682 }
683
684 tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
685
686 /* Now copy down the entire ioctl */
687 if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
688 goto out3;
689
690 /* See which ioctl we are doing */
691 switch (cmd) {
692 case TW_IOCTL_FIRMWARE_PASS_THROUGH:
693 spin_lock_irqsave(tw_dev->host->host_lock, flags);
694 twa_get_request_id(tw_dev, &request_id);
695
696 /* Flag internal command */
697 tw_dev->srb[request_id] = NULL;
698
699 /* Flag chrdev ioctl */
700 tw_dev->chrdev_request_id = request_id;
701
702 full_command_packet = &tw_ioctl->firmware_command;
703
704 /* Load request id and sglist for both command types */
adam radford0e78d152007-07-20 15:28:28 -0700705 twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707 memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
708
709 /* Now post the command packet to the controller */
710 twa_post_command_packet(tw_dev, request_id, 1);
711 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
712
713 timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
714
715 /* Now wait for command to complete */
716 timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* We timed out, and didn't get an interrupt */
719 if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
720 /* Now we need to reset the board */
721 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 -0700722 tw_dev->host->host_no, TW_DRIVER, 0x37,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 cmd);
724 retval = TW_IOCTL_ERROR_OS_EIO;
adam radford0e78d152007-07-20 15:28:28 -0700725 twa_reset_device_extension(tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 goto out3;
727 }
728
729 /* Now copy in the command packet response */
730 memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
731
732 /* Now complete the io */
733 spin_lock_irqsave(tw_dev->host->host_lock, flags);
734 tw_dev->posted_request_count--;
735 tw_dev->state[request_id] = TW_S_COMPLETED;
736 twa_free_request_id(tw_dev, request_id);
737 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
738 break;
739 case TW_IOCTL_GET_COMPATIBILITY_INFO:
740 tw_ioctl->driver_command.status = 0;
Dirk Hohndel06fe9fb2009-09-28 21:43:57 -0400741 /* Copy compatibility struct into ioctl data buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
adam radford4039c302006-10-26 18:01:06 -0700743 memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 break;
745 case TW_IOCTL_GET_LAST_EVENT:
746 if (tw_dev->event_queue_wrapped) {
747 if (tw_dev->aen_clobber) {
748 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
749 tw_dev->aen_clobber = 0;
750 } else
751 tw_ioctl->driver_command.status = 0;
752 } else {
753 if (!tw_dev->error_index) {
754 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
755 break;
756 }
757 tw_ioctl->driver_command.status = 0;
758 }
759 event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
760 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
761 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
762 break;
763 case TW_IOCTL_GET_FIRST_EVENT:
764 if (tw_dev->event_queue_wrapped) {
765 if (tw_dev->aen_clobber) {
766 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
767 tw_dev->aen_clobber = 0;
768 } else
769 tw_ioctl->driver_command.status = 0;
770 event_index = tw_dev->error_index;
771 } else {
772 if (!tw_dev->error_index) {
773 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
774 break;
775 }
776 tw_ioctl->driver_command.status = 0;
777 event_index = 0;
778 }
779 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
780 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
781 break;
782 case TW_IOCTL_GET_NEXT_EVENT:
783 event = (TW_Event *)tw_ioctl->data_buffer;
784 sequence_id = event->sequence_id;
785 tw_ioctl->driver_command.status = 0;
786
787 if (tw_dev->event_queue_wrapped) {
788 if (tw_dev->aen_clobber) {
789 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
790 tw_dev->aen_clobber = 0;
791 }
792 start_index = tw_dev->error_index;
793 } else {
794 if (!tw_dev->error_index) {
795 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
796 break;
797 }
798 start_index = 0;
799 }
800 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
801
802 if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
803 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
804 tw_dev->aen_clobber = 1;
805 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
806 break;
807 }
808 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
809 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
810 break;
811 case TW_IOCTL_GET_PREVIOUS_EVENT:
812 event = (TW_Event *)tw_ioctl->data_buffer;
813 sequence_id = event->sequence_id;
814 tw_ioctl->driver_command.status = 0;
815
816 if (tw_dev->event_queue_wrapped) {
817 if (tw_dev->aen_clobber) {
818 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
819 tw_dev->aen_clobber = 0;
820 }
821 start_index = tw_dev->error_index;
822 } else {
823 if (!tw_dev->error_index) {
824 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
825 break;
826 }
827 start_index = 0;
828 }
829 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
830
831 if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
832 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
833 tw_dev->aen_clobber = 1;
834 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
835 break;
836 }
837 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
838 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
839 break;
840 case TW_IOCTL_GET_LOCK:
841 tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
842 do_gettimeofday(&current_time);
843 current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
844
845 if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
846 tw_dev->ioctl_sem_lock = 1;
847 tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
848 tw_ioctl->driver_command.status = 0;
849 tw_lock->time_remaining_msec = tw_lock->timeout_msec;
850 } else {
851 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
852 tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
853 }
854 break;
855 case TW_IOCTL_RELEASE_LOCK:
856 if (tw_dev->ioctl_sem_lock == 1) {
857 tw_dev->ioctl_sem_lock = 0;
858 tw_ioctl->driver_command.status = 0;
859 } else {
860 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
861 }
862 break;
863 default:
864 retval = TW_IOCTL_ERROR_OS_ENOTTY;
865 goto out3;
866 }
867
868 /* Now copy the entire response to userspace */
869 if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
870 retval = 0;
871out3:
872 /* Now free ioctl buf memory */
873 dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
874out2:
Jes Sorensena12e25bd2006-01-11 08:39:45 -0500875 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876out:
877 return retval;
878} /* End twa_chrdev_ioctl() */
879
880/* This function handles open for the character device */
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600881/* NOTE that this function will race with remove. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882static int twa_chrdev_open(struct inode *inode, struct file *file)
883{
884 unsigned int minor_number;
885 int retval = TW_IOCTL_ERROR_OS_ENODEV;
886
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600887 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 minor_number = iminor(inode);
889 if (minor_number >= twa_device_extension_count)
890 goto out;
891 retval = 0;
892out:
893 return retval;
894} /* End twa_chrdev_open() */
895
896/* This function will print readable messages from status register errors */
897static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
898{
899 int retval = 1;
900
901 /* Check for various error conditions and handle them appropriately */
902 if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
903 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
904 writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
905 }
906
907 if (status_reg_value & TW_STATUS_PCI_ABORT) {
908 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
909 writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
910 pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
911 }
912
913 if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
adam radford0e78d152007-07-20 15:28:28 -0700914 if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
915 (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
916 (!test_bit(TW_IN_RESET, &tw_dev->flags)))
adam radford4039c302006-10-26 18:01:06 -0700917 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
919 }
920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
922 if (tw_dev->reset_print == 0) {
923 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
924 tw_dev->reset_print = 1;
925 }
926 goto out;
927 }
928 retval = 0;
929out:
930 return retval;
931} /* End twa_decode_bits() */
932
933/* This function will empty the response queue */
934static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
935{
936 u32 status_reg_value, response_que_value;
937 int count = 0, retval = 1;
938
939 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
940
941 while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
942 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
943 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
944 count++;
945 }
946 if (count == TW_MAX_RESPONSE_DRAIN)
947 goto out;
948
949 retval = 0;
950out:
951 return retval;
952} /* End twa_empty_response_queue() */
953
adam radford49bfd8d2005-09-21 17:20:14 -0700954/* This function will clear the pchip/response queue on 9550SX */
955static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
956{
adam radford75913d92006-03-15 12:43:19 -0800957 u32 response_que_value = 0;
958 unsigned long before;
959 int retval = 1;
adam radford49bfd8d2005-09-21 17:20:14 -0700960
adam radford0e78d152007-07-20 15:28:28 -0700961 if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
adam radford75913d92006-03-15 12:43:19 -0800962 before = jiffies;
963 while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
adam radford49bfd8d2005-09-21 17:20:14 -0700964 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
adam radford4039c302006-10-26 18:01:06 -0700965 msleep(1);
adam radford75913d92006-03-15 12:43:19 -0800966 if (time_after(jiffies, before + HZ * 30))
adam radford49bfd8d2005-09-21 17:20:14 -0700967 goto out;
adam radford49bfd8d2005-09-21 17:20:14 -0700968 }
adam radford75913d92006-03-15 12:43:19 -0800969 /* P-chip settle time */
970 msleep(500);
adam radford49bfd8d2005-09-21 17:20:14 -0700971 retval = 0;
972 } else
973 retval = 0;
974out:
975 return retval;
976} /* End twa_empty_response_queue_large() */
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978/* This function passes sense keys from firmware to scsi layer */
979static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
980{
981 TW_Command_Full *full_command_packet;
982 unsigned short error;
983 int retval = 1;
984 char *error_str;
985
986 full_command_packet = tw_dev->command_packet_virt[request_id];
987
988 /* Check for embedded error string */
989 error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
990
991 /* Don't print error for Logical unit not supported during rollcall */
adam radford75913d92006-03-15 12:43:19 -0800992 error = le16_to_cpu(full_command_packet->header.status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
994 if (print_host)
995 printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
996 tw_dev->host->host_no,
997 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
998 full_command_packet->header.status_block.error,
999 error_str[0] == '\0' ?
1000 twa_string_lookup(twa_error_table,
1001 full_command_packet->header.status_block.error) : error_str,
1002 full_command_packet->header.err_specific_desc);
1003 else
1004 printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
1005 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
1006 full_command_packet->header.status_block.error,
1007 error_str[0] == '\0' ?
1008 twa_string_lookup(twa_error_table,
1009 full_command_packet->header.status_block.error) : error_str,
1010 full_command_packet->header.err_specific_desc);
1011 }
1012
1013 if (copy_sense) {
1014 memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
1015 tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
1016 retval = TW_ISR_DONT_RESULT;
1017 goto out;
1018 }
1019 retval = 0;
1020out:
1021 return retval;
1022} /* End twa_fill_sense() */
1023
1024/* This function will free up device extension resources */
1025static void twa_free_device_extension(TW_Device_Extension *tw_dev)
1026{
1027 if (tw_dev->command_packet_virt[0])
1028 pci_free_consistent(tw_dev->tw_pci_dev,
1029 sizeof(TW_Command_Full)*TW_Q_LENGTH,
1030 tw_dev->command_packet_virt[0],
1031 tw_dev->command_packet_phys[0]);
1032
1033 if (tw_dev->generic_buffer_virt[0])
1034 pci_free_consistent(tw_dev->tw_pci_dev,
1035 TW_SECTOR_SIZE*TW_Q_LENGTH,
1036 tw_dev->generic_buffer_virt[0],
1037 tw_dev->generic_buffer_phys[0]);
1038
Jesper Juhlc9475cb2005-11-07 01:01:26 -08001039 kfree(tw_dev->event_queue[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040} /* End twa_free_device_extension() */
1041
1042/* This function will free a request id */
1043static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
1044{
1045 tw_dev->free_queue[tw_dev->free_tail] = request_id;
1046 tw_dev->state[request_id] = TW_S_FINISHED;
1047 tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
1048} /* End twa_free_request_id() */
1049
Alexey Dobriyan7f927fc2006-03-28 01:56:53 -08001050/* This function will get parameter table entries from the firmware */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
1052{
1053 TW_Command_Full *full_command_packet;
1054 TW_Command *command_packet;
1055 TW_Param_Apache *param;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 void *retval = NULL;
1057
1058 /* Setup the command packet */
1059 full_command_packet = tw_dev->command_packet_virt[request_id];
1060 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1061 command_packet = &full_command_packet->command.oldcommand;
1062
1063 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1064 command_packet->size = TW_COMMAND_SIZE;
1065 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001066 command_packet->byte6_offset.block_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068 /* Now setup the param */
1069 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
1070 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001071 param->table_id = cpu_to_le16(table_id | 0x8000);
1072 param->parameter_id = cpu_to_le16(parameter_id);
1073 param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
adam radford3dabec72008-07-22 16:47:40 -07001075 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 -08001076 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 /* Post the command packet to the board */
1079 twa_post_command_packet(tw_dev, request_id, 1);
1080
1081 /* Poll for completion */
1082 if (twa_poll_response(tw_dev, request_id, 30))
1083 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
1084 else
1085 retval = (void *)&(param->data[0]);
1086
1087 tw_dev->posted_request_count--;
1088 tw_dev->state[request_id] = TW_S_INITIAL;
1089
1090 return retval;
1091} /* End twa_get_param() */
1092
1093/* This function will assign an available request id */
1094static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
1095{
1096 *request_id = tw_dev->free_queue[tw_dev->free_head];
1097 tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
1098 tw_dev->state[*request_id] = TW_S_STARTED;
1099} /* End twa_get_request_id() */
1100
1101/* This function will send an initconnection command to controller */
1102static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
1103 u32 set_features, unsigned short current_fw_srl,
1104 unsigned short current_fw_arch_id,
1105 unsigned short current_fw_branch,
1106 unsigned short current_fw_build,
1107 unsigned short *fw_on_ctlr_srl,
1108 unsigned short *fw_on_ctlr_arch_id,
1109 unsigned short *fw_on_ctlr_branch,
1110 unsigned short *fw_on_ctlr_build,
1111 u32 *init_connect_result)
1112{
1113 TW_Command_Full *full_command_packet;
1114 TW_Initconnect *tw_initconnect;
1115 int request_id = 0, retval = 1;
1116
1117 /* Initialize InitConnection command packet */
1118 full_command_packet = tw_dev->command_packet_virt[request_id];
1119 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1120 full_command_packet->header.header_desc.size_header = 128;
1121
1122 tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
1123 tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
1124 tw_initconnect->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001125 tw_initconnect->message_credits = cpu_to_le16(message_credits);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 tw_initconnect->features = set_features;
1127
1128 /* Turn on 64-bit sgl support if we need to */
1129 tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
1130
adam radford75913d92006-03-15 12:43:19 -08001131 tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
1132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (set_features & TW_EXTENDED_INIT_CONNECT) {
1134 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
adam radford75913d92006-03-15 12:43:19 -08001135 tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
1136 tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
1137 tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
1138 tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 } else
1140 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
1141
1142 /* Send command packet to the board */
1143 twa_post_command_packet(tw_dev, request_id, 1);
1144
1145 /* Poll for completion */
1146 if (twa_poll_response(tw_dev, request_id, 30)) {
1147 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
1148 } else {
1149 if (set_features & TW_EXTENDED_INIT_CONNECT) {
adam radford75913d92006-03-15 12:43:19 -08001150 *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
1151 *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
1152 *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
1153 *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
1154 *init_connect_result = le32_to_cpu(tw_initconnect->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
1156 retval = 0;
1157 }
1158
1159 tw_dev->posted_request_count--;
1160 tw_dev->state[request_id] = TW_S_INITIAL;
1161
1162 return retval;
1163} /* End twa_initconnection() */
1164
1165/* This function will initialize the fields of a device extension */
1166static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
1167{
1168 int i, retval = 1;
1169
1170 /* Initialize command packet buffers */
1171 if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
1172 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
1173 goto out;
1174 }
1175
1176 /* Initialize generic buffer */
1177 if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
1178 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
1179 goto out;
1180 }
1181
1182 /* Allocate event info space */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001183 tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (!tw_dev->event_queue[0]) {
1185 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
1186 goto out;
1187 }
1188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 for (i = 0; i < TW_Q_LENGTH; i++) {
1191 tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
1192 tw_dev->free_queue[i] = i;
1193 tw_dev->state[i] = TW_S_INITIAL;
1194 }
1195
1196 tw_dev->pending_head = TW_Q_START;
1197 tw_dev->pending_tail = TW_Q_START;
1198 tw_dev->free_head = TW_Q_START;
1199 tw_dev->free_tail = TW_Q_START;
1200 tw_dev->error_sequence_id = 1;
1201 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1202
Jes Sorensena12e25bd2006-01-11 08:39:45 -05001203 mutex_init(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 init_waitqueue_head(&tw_dev->ioctl_wqueue);
1205
1206 retval = 0;
1207out:
1208 return retval;
1209} /* End twa_initialize_device_extension() */
1210
1211/* This function is the interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +01001212static irqreturn_t twa_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
1214 int request_id, error = 0;
1215 u32 status_reg_value;
1216 TW_Response_Queue response_que;
1217 TW_Command_Full *full_command_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
1219 int handled = 0;
1220
1221 /* Get the per adapter lock */
1222 spin_lock(tw_dev->host->host_lock);
1223
1224 /* Read the registers */
1225 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1226
1227 /* Check if this is our interrupt, otherwise bail */
1228 if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
1229 goto twa_interrupt_bail;
1230
1231 handled = 1;
1232
adam radford4039c302006-10-26 18:01:06 -07001233 /* If we are resetting, bail */
1234 if (test_bit(TW_IN_RESET, &tw_dev->flags))
1235 goto twa_interrupt_bail;
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 /* Check controller for errors */
1238 if (twa_check_bits(status_reg_value)) {
1239 if (twa_decode_bits(tw_dev, status_reg_value)) {
1240 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1241 goto twa_interrupt_bail;
1242 }
1243 }
1244
1245 /* Handle host interrupt */
1246 if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
1247 TW_CLEAR_HOST_INTERRUPT(tw_dev);
1248
1249 /* Handle attention interrupt */
1250 if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
1251 TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
1252 if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
1253 twa_get_request_id(tw_dev, &request_id);
1254
1255 error = twa_aen_read_queue(tw_dev, request_id);
1256 if (error) {
1257 tw_dev->state[request_id] = TW_S_COMPLETED;
1258 twa_free_request_id(tw_dev, request_id);
1259 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
1260 }
1261 }
1262 }
1263
1264 /* Handle command interrupt */
1265 if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
1266 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1267 /* Drain as many pending commands as we can */
1268 while (tw_dev->pending_request_count > 0) {
1269 request_id = tw_dev->pending_queue[tw_dev->pending_head];
1270 if (tw_dev->state[request_id] != TW_S_PENDING) {
1271 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
1272 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1273 goto twa_interrupt_bail;
1274 }
1275 if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
1276 tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
1277 tw_dev->pending_request_count--;
1278 } else {
1279 /* If we get here, we will continue re-posting on the next command interrupt */
1280 break;
1281 }
1282 }
1283 }
1284
1285 /* Handle response interrupt */
1286 if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
1287
1288 /* Drain the response queue from the board */
1289 while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
1290 /* Complete the response */
1291 response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1292 request_id = TW_RESID_OUT(response_que.response_id);
1293 full_command_packet = tw_dev->command_packet_virt[request_id];
1294 error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 /* Check for command packet errors */
1296 if (full_command_packet->command.newcommand.status != 0) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001297 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 error = twa_fill_sense(tw_dev, request_id, 1, 1);
1299 } else {
1300 /* Skip ioctl error prints */
1301 if (request_id != tw_dev->chrdev_request_id) {
1302 error = twa_fill_sense(tw_dev, request_id, 0, 1);
1303 }
1304 }
1305 }
1306
1307 /* Check for correct state */
1308 if (tw_dev->state[request_id] != TW_S_POSTED) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001309 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
1311 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1312 goto twa_interrupt_bail;
1313 }
1314 }
1315
1316 /* Check for internal command completion */
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001317 if (tw_dev->srb[request_id] == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 if (request_id != tw_dev->chrdev_request_id) {
1319 if (twa_aen_complete(tw_dev, request_id))
1320 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
1321 } else {
1322 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1323 wake_up(&tw_dev->ioctl_wqueue);
1324 }
1325 } else {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001326 struct scsi_cmnd *cmd;
1327
1328 cmd = tw_dev->srb[request_id];
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 twa_scsiop_execute_scsi_complete(tw_dev, request_id);
1331 /* If no error command was a success */
1332 if (error == 0) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001333 cmd->result = (DID_OK << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
1335
1336 /* If error, command failed */
1337 if (error == 1) {
1338 /* Ask for a host reset */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001339 cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 }
1341
1342 /* Report residual bytes for single sgl */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001343 if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
1344 if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
1345 scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
1347
1348 /* Now complete the io */
1349 tw_dev->state[request_id] = TW_S_COMPLETED;
1350 twa_free_request_id(tw_dev, request_id);
1351 tw_dev->posted_request_count--;
1352 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
1353 twa_unmap_scsi_data(tw_dev, request_id);
1354 }
1355
1356 /* Check for valid status after each drain */
1357 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1358 if (twa_check_bits(status_reg_value)) {
1359 if (twa_decode_bits(tw_dev, status_reg_value)) {
1360 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1361 goto twa_interrupt_bail;
1362 }
1363 }
1364 }
1365 }
1366
1367twa_interrupt_bail:
1368 spin_unlock(tw_dev->host->host_lock);
1369 return IRQ_RETVAL(handled);
1370} /* End twa_interrupt() */
1371
1372/* This function will load the request id and various sgls for ioctls */
adam radford0e78d152007-07-20 15:28:28 -07001373static 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 -07001374{
1375 TW_Command *oldcommand;
1376 TW_Command_Apache *newcommand;
1377 TW_SG_Entry *sgl;
adam radford0e78d152007-07-20 15:28:28 -07001378 unsigned int pae = 0;
1379
1380 if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
1381 pae = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1384 newcommand = &full_command_packet->command.newcommand;
adam radford4039c302006-10-26 18:01:06 -07001385 newcommand->request_id__lunl =
1386 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
adam radford53ca3532009-12-10 11:53:31 -08001387 if (length) {
1388 newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1389 newcommand->sg_list[0].length = cpu_to_le32(length);
1390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 newcommand->sgl_entries__lunh =
adam radford53ca3532009-12-10 11:53:31 -08001392 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 } else {
1394 oldcommand = &full_command_packet->command.oldcommand;
1395 oldcommand->request_id = request_id;
1396
1397 if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
1398 /* Load the sg list */
adam radford0e78d152007-07-20 15:28:28 -07001399 if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
1400 sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
1401 else
1402 sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
adam radford75913d92006-03-15 12:43:19 -08001403 sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1404 sgl->length = cpu_to_le32(length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
adam radford0e78d152007-07-20 15:28:28 -07001406 oldcommand->size += pae;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
1408 }
1409} /* End twa_load_sgl() */
1410
1411/* This function will perform a pci-dma mapping for a scatter gather list */
1412static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
1413{
1414 int use_sg;
1415 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001417 use_sg = scsi_dma_map(cmd);
1418 if (!use_sg)
1419 return 0;
1420 else if (use_sg < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001422 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
1424
1425 cmd->SCp.phase = TW_PHASE_SGLIST;
1426 cmd->SCp.have_data_in = use_sg;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001427
1428 return use_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429} /* End twa_map_scsi_sg_data() */
1430
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431/* This function will poll for a response interrupt of a request */
1432static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
1433{
1434 int retval = 1, found = 0, response_request_id;
1435 TW_Response_Queue response_queue;
1436 TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
1437
1438 if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
1439 response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1440 response_request_id = TW_RESID_OUT(response_queue.response_id);
1441 if (request_id != response_request_id) {
1442 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
1443 goto out;
1444 }
1445 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1446 if (full_command_packet->command.newcommand.status != 0) {
1447 /* bad response */
1448 twa_fill_sense(tw_dev, request_id, 0, 0);
1449 goto out;
1450 }
1451 found = 1;
1452 } else {
1453 if (full_command_packet->command.oldcommand.status != 0) {
1454 /* bad response */
1455 twa_fill_sense(tw_dev, request_id, 0, 0);
1456 goto out;
1457 }
1458 found = 1;
1459 }
1460 }
1461
1462 if (found)
1463 retval = 0;
1464out:
1465 return retval;
1466} /* End twa_poll_response() */
1467
1468/* This function will poll the status register for a flag */
1469static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1470{
1471 u32 status_reg_value;
1472 unsigned long before;
1473 int retval = 1;
1474
1475 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1476 before = jiffies;
1477
1478 if (twa_check_bits(status_reg_value))
1479 twa_decode_bits(tw_dev, status_reg_value);
1480
1481 while ((status_reg_value & flag) != flag) {
1482 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1483
1484 if (twa_check_bits(status_reg_value))
1485 twa_decode_bits(tw_dev, status_reg_value);
1486
1487 if (time_after(jiffies, before + HZ * seconds))
1488 goto out;
1489
1490 msleep(50);
1491 }
1492 retval = 0;
1493out:
1494 return retval;
1495} /* End twa_poll_status() */
1496
1497/* This function will poll the status register for disappearance of a flag */
1498static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1499{
1500 u32 status_reg_value;
1501 unsigned long before;
1502 int retval = 1;
1503
1504 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1505 before = jiffies;
1506
1507 if (twa_check_bits(status_reg_value))
1508 twa_decode_bits(tw_dev, status_reg_value);
1509
1510 while ((status_reg_value & flag) != 0) {
1511 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1512 if (twa_check_bits(status_reg_value))
1513 twa_decode_bits(tw_dev, status_reg_value);
1514
1515 if (time_after(jiffies, before + HZ * seconds))
1516 goto out;
1517
1518 msleep(50);
1519 }
1520 retval = 0;
1521out:
1522 return retval;
1523} /* End twa_poll_status_gone() */
1524
1525/* This function will attempt to post a command packet to the board */
1526static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
1527{
1528 u32 status_reg_value;
1529 dma_addr_t command_que_value;
1530 int retval = 1;
1531
1532 command_que_value = tw_dev->command_packet_phys[request_id];
adam radford4039c302006-10-26 18:01:06 -07001533
1534 /* For 9650SE write low 4 bytes first */
adam radford0e78d152007-07-20 15:28:28 -07001535 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1536 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001537 command_que_value += TW_COMMAND_OFFSET;
1538 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
1539 }
1540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1542
1543 if (twa_check_bits(status_reg_value))
1544 twa_decode_bits(tw_dev, status_reg_value);
1545
1546 if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
1547
1548 /* Only pend internal driver commands */
1549 if (!internal) {
1550 retval = SCSI_MLQUEUE_HOST_BUSY;
1551 goto out;
1552 }
1553
1554 /* Couldn't post the command packet, so we do it later */
1555 if (tw_dev->state[request_id] != TW_S_PENDING) {
1556 tw_dev->state[request_id] = TW_S_PENDING;
1557 tw_dev->pending_request_count++;
1558 if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
1559 tw_dev->max_pending_request_count = tw_dev->pending_request_count;
1560 }
1561 tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
1562 tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
1563 }
1564 TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
1565 goto out;
1566 } else {
adam radford0e78d152007-07-20 15:28:28 -07001567 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1568 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001569 /* Now write upper 4 bytes */
1570 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 } else {
adam radford4039c302006-10-26 18:01:06 -07001572 if (sizeof(dma_addr_t) > 4) {
1573 command_que_value += TW_COMMAND_OFFSET;
1574 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1575 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
1576 } else {
1577 writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 }
1580 tw_dev->state[request_id] = TW_S_POSTED;
1581 tw_dev->posted_request_count++;
1582 if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
1583 tw_dev->max_posted_request_count = tw_dev->posted_request_count;
1584 }
1585 }
1586 retval = 0;
1587out:
1588 return retval;
1589} /* End twa_post_command_packet() */
1590
1591/* This function will reset a device extension */
adam radford0e78d152007-07-20 15:28:28 -07001592static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593{
1594 int i = 0;
1595 int retval = 1;
1596 unsigned long flags = 0;
1597
1598 set_bit(TW_IN_RESET, &tw_dev->flags);
1599 TW_DISABLE_INTERRUPTS(tw_dev);
1600 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1601 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1602
1603 /* Abort all requests that are in progress */
1604 for (i = 0; i < TW_Q_LENGTH; i++) {
1605 if ((tw_dev->state[i] != TW_S_FINISHED) &&
1606 (tw_dev->state[i] != TW_S_INITIAL) &&
1607 (tw_dev->state[i] != TW_S_COMPLETED)) {
1608 if (tw_dev->srb[i]) {
1609 tw_dev->srb[i]->result = (DID_RESET << 16);
1610 tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
1611 twa_unmap_scsi_data(tw_dev, i);
1612 }
1613 }
1614 }
1615
1616 /* Reset queues and counts */
1617 for (i = 0; i < TW_Q_LENGTH; i++) {
1618 tw_dev->free_queue[i] = i;
1619 tw_dev->state[i] = TW_S_INITIAL;
1620 }
1621 tw_dev->free_head = TW_Q_START;
1622 tw_dev->free_tail = TW_Q_START;
1623 tw_dev->posted_request_count = 0;
1624 tw_dev->pending_request_count = 0;
1625 tw_dev->pending_head = TW_Q_START;
1626 tw_dev->pending_tail = TW_Q_START;
1627 tw_dev->reset_print = 0;
1628
1629 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1630
1631 if (twa_reset_sequence(tw_dev, 1))
1632 goto out;
1633
1634 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
adam radford4039c302006-10-26 18:01:06 -07001635 clear_bit(TW_IN_RESET, &tw_dev->flags);
1636 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 retval = 0;
1639out:
1640 return retval;
1641} /* End twa_reset_device_extension() */
1642
1643/* This function will reset a controller */
1644static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
1645{
1646 int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
1647
1648 while (tries < TW_MAX_RESET_TRIES) {
adam radford49bfd8d2005-09-21 17:20:14 -07001649 if (do_soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 TW_SOFT_RESET(tw_dev);
adam radford49bfd8d2005-09-21 17:20:14 -07001651 /* Clear pchip/response queue on 9550SX */
1652 if (twa_empty_response_queue_large(tw_dev)) {
1653 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence");
1654 do_soft_reset = 1;
1655 tries++;
1656 continue;
1657 }
1658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660 /* Make sure controller is in a good state */
1661 if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
1662 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
1663 do_soft_reset = 1;
1664 tries++;
1665 continue;
1666 }
1667
1668 /* Empty response queue */
1669 if (twa_empty_response_queue(tw_dev)) {
1670 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
1671 do_soft_reset = 1;
1672 tries++;
1673 continue;
1674 }
1675
1676 flashed = 0;
1677
1678 /* Check for compatibility/flash */
1679 if (twa_check_srl(tw_dev, &flashed)) {
1680 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
1681 do_soft_reset = 1;
1682 tries++;
1683 continue;
1684 } else {
1685 if (flashed) {
1686 tries++;
1687 continue;
1688 }
1689 }
1690
1691 /* Drain the AEN queue */
1692 if (twa_aen_drain_queue(tw_dev, soft_reset)) {
1693 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
1694 do_soft_reset = 1;
1695 tries++;
1696 continue;
1697 }
1698
1699 /* If we got here, controller is in a good state */
1700 retval = 0;
1701 goto out;
1702 }
1703out:
1704 return retval;
1705} /* End twa_reset_sequence() */
1706
1707/* This funciton returns unit geometry in cylinders/heads/sectors */
1708static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
1709{
1710 int heads, sectors, cylinders;
1711 TW_Device_Extension *tw_dev;
1712
1713 tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
1714
1715 if (capacity >= 0x200000) {
1716 heads = 255;
1717 sectors = 63;
1718 cylinders = sector_div(capacity, heads * sectors);
1719 } else {
1720 heads = 64;
1721 sectors = 32;
1722 cylinders = sector_div(capacity, heads * sectors);
1723 }
1724
1725 geom[0] = heads;
1726 geom[1] = sectors;
1727 geom[2] = cylinders;
1728
1729 return 0;
1730} /* End twa_scsi_biosparam() */
1731
1732/* This is the new scsi eh reset function */
1733static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
1734{
1735 TW_Device_Extension *tw_dev = NULL;
1736 int retval = FAILED;
1737
1738 tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 tw_dev->num_resets++;
1741
Jeff Garzik017560f2005-10-24 18:04:36 -04001742 sdev_printk(KERN_WARNING, SCpnt->device,
1743 "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
1744 TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
adam radford4039c302006-10-26 18:01:06 -07001746 /* Make sure we are not issuing an ioctl or resetting from ioctl */
1747 mutex_lock(&tw_dev->ioctl_lock);
1748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 /* Now reset the card and some of the device extension data */
adam radford0e78d152007-07-20 15:28:28 -07001750 if (twa_reset_device_extension(tw_dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
1752 goto out;
1753 }
1754
1755 retval = SUCCESS;
1756out:
adam radford4039c302006-10-26 18:01:06 -07001757 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 return retval;
1759} /* End twa_scsi_eh_reset() */
1760
1761/* This is the main scsi queue function to handle scsi opcodes */
1762static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1763{
1764 int request_id, retval;
1765 TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1766
adam radford4039c302006-10-26 18:01:06 -07001767 /* If we are resetting due to timed out ioctl, report as busy */
1768 if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
1769 retval = SCSI_MLQUEUE_HOST_BUSY;
1770 goto out;
1771 }
1772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 /* Check if this FW supports luns */
adam radford4039c302006-10-26 18:01:06 -07001774 if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 SCpnt->result = (DID_BAD_TARGET << 16);
1776 done(SCpnt);
1777 retval = 0;
1778 goto out;
1779 }
1780
1781 /* Save done function into scsi_cmnd struct */
1782 SCpnt->scsi_done = done;
1783
1784 /* Get a free request id */
1785 twa_get_request_id(tw_dev, &request_id);
1786
1787 /* Save the scsi command for use by the ISR */
1788 tw_dev->srb[request_id] = SCpnt;
1789
1790 /* Initialize phase to zero */
1791 SCpnt->SCp.phase = TW_PHASE_INITIAL;
1792
1793 retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
1794 switch (retval) {
1795 case SCSI_MLQUEUE_HOST_BUSY:
1796 twa_free_request_id(tw_dev, request_id);
1797 break;
1798 case 1:
1799 tw_dev->state[request_id] = TW_S_COMPLETED;
1800 twa_free_request_id(tw_dev, request_id);
1801 SCpnt->result = (DID_ERROR << 16);
1802 done(SCpnt);
1803 retval = 0;
1804 }
1805out:
1806 return retval;
1807} /* End twa_scsi_queue() */
1808
1809/* This function hands scsi cdb's to the firmware */
1810static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
1811{
1812 TW_Command_Full *full_command_packet;
1813 TW_Command_Apache *command_packet;
1814 u32 num_sectors = 0x0;
1815 int i, sg_count;
1816 struct scsi_cmnd *srb = NULL;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001817 struct scatterlist *sglist = NULL, *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 int retval = 1;
1819
1820 if (tw_dev->srb[request_id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 srb = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001822 if (scsi_sglist(srb))
1823 sglist = scsi_sglist(srb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 }
1825
1826 /* Initialize command packet */
1827 full_command_packet = tw_dev->command_packet_virt[request_id];
1828 full_command_packet->header.header_desc.size_header = 128;
1829 full_command_packet->header.status_block.error = 0;
1830 full_command_packet->header.status_block.severity__reserved = 0;
1831
1832 command_packet = &full_command_packet->command.newcommand;
1833 command_packet->status = 0;
1834 command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
1835
1836 /* We forced 16 byte cdb use earlier */
1837 if (!cdb)
1838 memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
1839 else
1840 memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
1841
1842 if (srb) {
1843 command_packet->unit = srb->device->id;
1844 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001845 cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 } else {
1847 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001848 cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 command_packet->unit = 0;
1850 }
1851
1852 command_packet->sgl_offset = 16;
1853
1854 if (!sglistarg) {
1855 /* Map sglist from scsi layer to cmd packet */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001857 if (scsi_sg_count(srb)) {
1858 if ((scsi_sg_count(srb) == 1) &&
1859 (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001860 if (srb->sc_data_direction == DMA_TO_DEVICE ||
1861 srb->sc_data_direction == DMA_BIDIRECTIONAL)
1862 scsi_sg_copy_to_buffer(srb,
1863 tw_dev->generic_buffer_virt[request_id],
1864 TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001865 command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
1866 command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 } else {
1868 sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
1869 if (sg_count == 0)
1870 goto out;
1871
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001872 scsi_for_each_sg(srb, sg, sg_count, i) {
1873 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
1874 command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
adam radford75913d92006-03-15 12:43:19 -08001875 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
1877 goto out;
1878 }
1879 }
1880 }
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001881 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 -07001882 }
1883 } else {
1884 /* Internal cdb post */
1885 for (i = 0; i < use_sg; i++) {
adam radford75913d92006-03-15 12:43:19 -08001886 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
1887 command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length);
1888 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
1890 goto out;
1891 }
1892 }
adam radford75913d92006-03-15 12:43:19 -08001893 command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895
1896 if (srb) {
1897 if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
1898 num_sectors = (u32)srb->cmnd[4];
1899
1900 if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
1901 num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
1902 }
1903
1904 /* Update sector statistic */
1905 tw_dev->sector_count = num_sectors;
1906 if (tw_dev->sector_count > tw_dev->max_sector_count)
1907 tw_dev->max_sector_count = tw_dev->sector_count;
1908
1909 /* Update SG statistics */
1910 if (srb) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001911 tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
1913 tw_dev->max_sgl_entries = tw_dev->sgl_entries;
1914 }
1915
1916 /* Now post the command to the board */
1917 if (srb) {
1918 retval = twa_post_command_packet(tw_dev, request_id, 0);
1919 } else {
1920 twa_post_command_packet(tw_dev, request_id, 1);
1921 retval = 0;
1922 }
1923out:
1924 return retval;
1925} /* End twa_scsiop_execute_scsi() */
1926
1927/* This function completes an execute scsi operation */
1928static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
1929{
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001930 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001931
1932 if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH &&
1933 (cmd->sc_data_direction == DMA_FROM_DEVICE ||
1934 cmd->sc_data_direction == DMA_BIDIRECTIONAL)) {
FUJITA Tomonorib1192d52007-05-31 15:24:03 +09001935 if (scsi_sg_count(cmd) == 1) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001936 void *buf = tw_dev->generic_buffer_virt[request_id];
1937
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001938 scsi_sg_copy_from_buffer(cmd, buf, TW_SECTOR_SIZE);
adam radfordd327d082005-09-09 15:55:13 -07001939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941} /* End twa_scsiop_execute_scsi_complete() */
1942
1943/* This function tells the controller to shut down */
1944static void __twa_shutdown(TW_Device_Extension *tw_dev)
1945{
1946 /* Disable interrupts */
1947 TW_DISABLE_INTERRUPTS(tw_dev);
1948
adam radford4039c302006-10-26 18:01:06 -07001949 /* Free up the IRQ */
1950 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
1951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
1953
1954 /* Tell the card we are shutting down */
1955 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
1956 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
1957 } else {
1958 printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
1959 }
1960
1961 /* Clear all interrupts just before exit */
1962 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1963} /* End __twa_shutdown() */
1964
1965/* Wrapper for __twa_shutdown */
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001966static void twa_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001968 struct Scsi_Host *host = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
1970
1971 __twa_shutdown(tw_dev);
1972} /* End twa_shutdown() */
1973
1974/* This function will look up a string */
1975static char *twa_string_lookup(twa_message_type *table, unsigned int code)
1976{
1977 int index;
1978
1979 for (index = 0; ((code != table[index].code) &&
1980 (table[index].text != (char *)0)); index++);
1981 return(table[index].text);
1982} /* End twa_string_lookup() */
1983
1984/* This function will perform a pci-dma unmap */
1985static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
1986{
1987 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
adam radford8454e982009-05-05 11:45:37 -07001989 if (cmd->SCp.phase == TW_PHASE_SGLIST)
1990 scsi_dma_unmap(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991} /* End twa_unmap_scsi_data() */
1992
1993/* scsi_host_template initializer */
1994static struct scsi_host_template driver_template = {
1995 .module = THIS_MODULE,
1996 .name = "3ware 9000 Storage Controller",
1997 .queuecommand = twa_scsi_queue,
1998 .eh_host_reset_handler = twa_scsi_eh_reset,
1999 .bios_param = twa_scsi_biosparam,
2000 .change_queue_depth = twa_change_queue_depth,
2001 .can_queue = TW_Q_LENGTH-2,
2002 .this_id = -1,
2003 .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH,
2004 .max_sectors = TW_MAX_SECTORS,
2005 .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
2006 .use_clustering = ENABLE_CLUSTERING,
2007 .shost_attrs = twa_host_attrs,
2008 .emulated = 1
2009};
2010
2011/* This function will probe and initialize a card */
2012static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
2013{
2014 struct Scsi_Host *host = NULL;
2015 TW_Device_Extension *tw_dev;
adam radford3dabec72008-07-22 16:47:40 -07002016 unsigned long mem_addr, mem_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 int retval = -ENODEV;
2018
2019 retval = pci_enable_device(pdev);
2020 if (retval) {
2021 TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
2022 goto out_disable_device;
2023 }
2024
2025 pci_set_master(pdev);
Tony Battersby1e6c38c2007-11-09 13:04:35 -05002026 pci_try_set_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
Yang Hongyang6a355282009-04-06 19:01:13 -07002028 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2029 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
Yang Hongyang284901a2009-04-06 19:01:15 -07002030 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2031 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford0e78d152007-07-20 15:28:28 -07002032 TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
2033 retval = -ENODEV;
2034 goto out_disable_device;
2035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
2037 host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
2038 if (!host) {
2039 TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
2040 retval = -ENOMEM;
2041 goto out_disable_device;
2042 }
2043 tw_dev = (TW_Device_Extension *)host->hostdata;
2044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 /* Save values to device extension */
2046 tw_dev->host = host;
2047 tw_dev->tw_pci_dev = pdev;
2048
2049 if (twa_initialize_device_extension(tw_dev)) {
2050 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
2051 goto out_free_device_extension;
2052 }
2053
2054 /* Request IO regions */
2055 retval = pci_request_regions(pdev, "3w-9xxx");
2056 if (retval) {
2057 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
2058 goto out_free_device_extension;
2059 }
2060
adam radford3dabec72008-07-22 16:47:40 -07002061 if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
adam radford49bfd8d2005-09-21 17:20:14 -07002062 mem_addr = pci_resource_start(pdev, 1);
adam radford3dabec72008-07-22 16:47:40 -07002063 mem_len = pci_resource_len(pdev, 1);
2064 } else {
adam radford49bfd8d2005-09-21 17:20:14 -07002065 mem_addr = pci_resource_start(pdev, 2);
adam radford3dabec72008-07-22 16:47:40 -07002066 mem_len = pci_resource_len(pdev, 2);
2067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 /* Save base address */
adam radford3dabec72008-07-22 16:47:40 -07002070 tw_dev->base_addr = ioremap(mem_addr, mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 if (!tw_dev->base_addr) {
2072 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
2073 goto out_release_mem_region;
2074 }
2075
2076 /* Disable interrupts on the card */
2077 TW_DISABLE_INTERRUPTS(tw_dev);
2078
2079 /* Initialize the card */
2080 if (twa_reset_sequence(tw_dev, 0))
adam radford4039c302006-10-26 18:01:06 -07002081 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
2083 /* Set host specific parameters */
adam radford0e78d152007-07-20 15:28:28 -07002084 if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
2085 (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
adam radford4039c302006-10-26 18:01:06 -07002086 host->max_id = TW_MAX_UNITS_9650SE;
2087 else
2088 host->max_id = TW_MAX_UNITS;
2089
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 host->max_cmd_len = TW_MAX_CDB_LEN;
2091
2092 /* Channels aren't supported by adapter */
adam radford4039c302006-10-26 18:01:06 -07002093 host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 host->max_channel = 0;
2095
2096 /* Register the card with the kernel SCSI layer */
2097 retval = scsi_add_host(host, &pdev->dev);
2098 if (retval) {
2099 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
adam radford4039c302006-10-26 18:01:06 -07002100 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 }
2102
2103 pci_set_drvdata(pdev, host);
2104
adam radford3dabec72008-07-22 16:47:40 -07002105 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 -07002106 host->host_no, mem_addr, pdev->irq);
2107 printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
2108 host->host_no,
2109 (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
2110 TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
2111 (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
2112 TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
adam radford75913d92006-03-15 12:43:19 -08002113 le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
2114 TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
adam radford3dabec72008-07-22 16:47:40 -07002116 /* Try to enable MSI */
2117 if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
2118 !pci_enable_msi(pdev))
2119 set_bit(TW_USING_MSI, &tw_dev->flags);
2120
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 /* Now setup the interrupt handler */
Thomas Gleixner1d6f3592006-07-01 19:29:42 -07002122 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 if (retval) {
2124 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
2125 goto out_remove_host;
2126 }
2127
2128 twa_device_extension_list[twa_device_extension_count] = tw_dev;
2129 twa_device_extension_count++;
2130
2131 /* Re-enable interrupts on the card */
2132 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2133
2134 /* Finally, scan the host */
2135 scsi_scan_host(host);
2136
2137 if (twa_major == -1) {
2138 if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
2139 TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
2140 }
2141 return 0;
2142
2143out_remove_host:
adam radford3dabec72008-07-22 16:47:40 -07002144 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2145 pci_disable_msi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 scsi_remove_host(host);
adam radford4039c302006-10-26 18:01:06 -07002147out_iounmap:
2148 iounmap(tw_dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149out_release_mem_region:
2150 pci_release_regions(pdev);
2151out_free_device_extension:
2152 twa_free_device_extension(tw_dev);
2153 scsi_host_put(host);
2154out_disable_device:
2155 pci_disable_device(pdev);
2156
2157 return retval;
2158} /* End twa_probe() */
2159
2160/* This function is called to remove a device */
2161static void twa_remove(struct pci_dev *pdev)
2162{
2163 struct Scsi_Host *host = pci_get_drvdata(pdev);
2164 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2165
2166 scsi_remove_host(tw_dev->host);
2167
2168 /* Unregister character device */
2169 if (twa_major >= 0) {
2170 unregister_chrdev(twa_major, "twa");
2171 twa_major = -1;
2172 }
2173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* Shutdown the card */
2175 __twa_shutdown(tw_dev);
2176
adam radford3dabec72008-07-22 16:47:40 -07002177 /* Disable MSI if enabled */
2178 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2179 pci_disable_msi(pdev);
2180
adam radford4039c302006-10-26 18:01:06 -07002181 /* Free IO remapping */
2182 iounmap(tw_dev->base_addr);
2183
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 /* Free up the mem region */
2185 pci_release_regions(pdev);
2186
2187 /* Free up device extension resources */
2188 twa_free_device_extension(tw_dev);
2189
2190 scsi_host_put(tw_dev->host);
2191 pci_disable_device(pdev);
2192 twa_device_extension_count--;
2193} /* End twa_remove() */
2194
adam radford7a252fe2009-03-09 12:15:01 -08002195#ifdef CONFIG_PM
2196/* This function is called on PCI suspend */
2197static int twa_suspend(struct pci_dev *pdev, pm_message_t state)
2198{
2199 struct Scsi_Host *host = pci_get_drvdata(pdev);
2200 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2201
2202 printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no);
2203
2204 TW_DISABLE_INTERRUPTS(tw_dev);
2205 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
2206
2207 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2208 pci_disable_msi(pdev);
2209
2210 /* Tell the card we are shutting down */
2211 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
2212 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend");
2213 } else {
2214 printk(KERN_WARNING "3w-9xxx: Suspend complete.\n");
2215 }
2216 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
2217
2218 pci_save_state(pdev);
2219 pci_disable_device(pdev);
2220 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2221
2222 return 0;
2223} /* End twa_suspend() */
2224
2225/* This function is called on PCI resume */
2226static int twa_resume(struct pci_dev *pdev)
2227{
2228 int retval = 0;
2229 struct Scsi_Host *host = pci_get_drvdata(pdev);
2230 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2231
2232 printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no);
2233 pci_set_power_state(pdev, PCI_D0);
2234 pci_enable_wake(pdev, PCI_D0, 0);
2235 pci_restore_state(pdev);
2236
2237 retval = pci_enable_device(pdev);
2238 if (retval) {
2239 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume");
2240 return retval;
2241 }
2242
2243 pci_set_master(pdev);
2244 pci_try_set_mwi(pdev);
2245
Yang Hongyange9304382009-04-13 14:40:14 -07002246 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2247 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
2248 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2249 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford7a252fe2009-03-09 12:15:01 -08002250 TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
2251 retval = -ENODEV;
2252 goto out_disable_device;
2253 }
2254
2255 /* Initialize the card */
2256 if (twa_reset_sequence(tw_dev, 0)) {
2257 retval = -ENODEV;
2258 goto out_disable_device;
2259 }
2260
2261 /* Now setup the interrupt handler */
2262 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
2263 if (retval) {
2264 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume");
2265 retval = -ENODEV;
2266 goto out_disable_device;
2267 }
2268
2269 /* Now enable MSI if enabled */
2270 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2271 pci_enable_msi(pdev);
2272
2273 /* Re-enable interrupts on the card */
2274 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2275
2276 printk(KERN_WARNING "3w-9xxx: Resume complete.\n");
2277 return 0;
2278
2279out_disable_device:
2280 scsi_remove_host(host);
2281 pci_disable_device(pdev);
2282
2283 return retval;
2284} /* End twa_resume() */
2285#endif
2286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287/* PCI Devices supported by this driver */
2288static struct pci_device_id twa_pci_tbl[] __devinitdata = {
2289 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
2290 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford49bfd8d2005-09-21 17:20:14 -07002291 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
2292 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford4039c302006-10-26 18:01:06 -07002293 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
2294 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford0e78d152007-07-20 15:28:28 -07002295 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
2296 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 { }
2298};
2299MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
2300
2301/* pci_driver initializer */
2302static struct pci_driver twa_driver = {
2303 .name = "3w-9xxx",
2304 .id_table = twa_pci_tbl,
2305 .probe = twa_probe,
2306 .remove = twa_remove,
adam radford7a252fe2009-03-09 12:15:01 -08002307#ifdef CONFIG_PM
2308 .suspend = twa_suspend,
2309 .resume = twa_resume,
2310#endif
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002311 .shutdown = twa_shutdown
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312};
2313
2314/* This function is called on driver initialization */
2315static int __init twa_init(void)
2316{
2317 printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
2318
Henrik Kretzschmardcbccbde2006-09-25 16:58:58 -07002319 return pci_register_driver(&twa_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320} /* End twa_init() */
2321
2322/* This function is called on driver exit */
2323static void __exit twa_exit(void)
2324{
2325 pci_unregister_driver(&twa_driver);
2326} /* End twa_exit() */
2327
2328module_init(twa_init);
2329module_exit(twa_exit);
2330