blob: 84d3bbaa95e7868f8cb3d2aa20e3844c721e79c6 [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 Sorensena12e25b2006-01-11 08:39:45 -050092#include <linux/mutex.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -060093#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070094#include <asm/io.h>
95#include <asm/irq.h>
96#include <asm/uaccess.h>
97#include <scsi/scsi.h>
98#include <scsi/scsi_host.h>
99#include <scsi/scsi_tcq.h>
100#include <scsi/scsi_cmnd.h>
101#include "3w-9xxx.h"
102
103/* Globals */
adam radford53ca3532009-12-10 11:53:31 -0800104#define TW_DRIVER_VERSION "2.26.02.013"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
106static unsigned int twa_device_extension_count;
107static int twa_major = -1;
108extern struct timezone sys_tz;
109
110/* Module parameters */
111MODULE_AUTHOR ("AMCC");
112MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
113MODULE_LICENSE("GPL");
114MODULE_VERSION(TW_DRIVER_VERSION);
115
adam radford3dabec72008-07-22 16:47:40 -0700116static int use_msi = 0;
117module_param(use_msi, int, S_IRUGO);
118MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/* Function prototypes */
121static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
122static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
123static char *twa_aen_severity_lookup(unsigned char severity_code);
124static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
125static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
126static int twa_chrdev_open(struct inode *inode, struct file *file);
127static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
128static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
129static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
130static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
131 u32 set_features, unsigned short current_fw_srl,
132 unsigned short current_fw_arch_id,
133 unsigned short current_fw_branch,
134 unsigned short current_fw_build,
135 unsigned short *fw_on_ctlr_srl,
136 unsigned short *fw_on_ctlr_arch_id,
137 unsigned short *fw_on_ctlr_branch,
138 unsigned short *fw_on_ctlr_build,
139 u32 *init_connect_result);
adam radford0e78d152007-07-20 15:28:28 -0700140static 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 -0700141static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
142static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
143static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
adam radford0e78d152007-07-20 15:28:28 -0700144static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
146static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
147static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
148static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
149static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
150
151/* Functions */
152
153/* Show some statistics about the card */
Tony Jonesee959b02008-02-22 00:13:36 +0100154static ssize_t twa_show_stats(struct device *dev,
155 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
Tony Jonesee959b02008-02-22 00:13:36 +0100157 struct Scsi_Host *host = class_to_shost(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
159 unsigned long flags = 0;
160 ssize_t len;
161
162 spin_lock_irqsave(tw_dev->host->host_lock, flags);
163 len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
164 "Current commands posted: %4d\n"
165 "Max commands posted: %4d\n"
166 "Current pending commands: %4d\n"
167 "Max pending commands: %4d\n"
168 "Last sgl length: %4d\n"
169 "Max sgl length: %4d\n"
170 "Last sector count: %4d\n"
171 "Max sector count: %4d\n"
172 "SCSI Host Resets: %4d\n"
173 "AEN's: %4d\n",
174 TW_DRIVER_VERSION,
175 tw_dev->posted_request_count,
176 tw_dev->max_posted_request_count,
177 tw_dev->pending_request_count,
178 tw_dev->max_pending_request_count,
179 tw_dev->sgl_entries,
180 tw_dev->max_sgl_entries,
181 tw_dev->sector_count,
182 tw_dev->max_sector_count,
183 tw_dev->num_resets,
184 tw_dev->aen_count);
185 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
186 return len;
187} /* End twa_show_stats() */
188
189/* This function will set a devices queue depth */
Mike Christiee881a172009-10-15 17:46:39 -0700190static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
191 int reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Mike Christiee881a172009-10-15 17:46:39 -0700193 if (reason != SCSI_QDEPTH_DEFAULT)
194 return -EOPNOTSUPP;
195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 if (queue_depth > TW_Q_LENGTH-2)
197 queue_depth = TW_Q_LENGTH-2;
198 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
199 return queue_depth;
200} /* End twa_change_queue_depth() */
201
202/* Create sysfs 'stats' entry */
Tony Jonesee959b02008-02-22 00:13:36 +0100203static struct device_attribute twa_host_stats_attr = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 .attr = {
205 .name = "stats",
206 .mode = S_IRUGO,
207 },
208 .show = twa_show_stats
209};
210
211/* Host attributes initializer */
Tony Jonesee959b02008-02-22 00:13:36 +0100212static struct device_attribute *twa_host_attrs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 &twa_host_stats_attr,
214 NULL,
215};
216
217/* File operations struct for character device */
Arjan van de Ven00977a52007-02-12 00:55:34 -0800218static const struct file_operations twa_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .owner = THIS_MODULE,
220 .ioctl = twa_chrdev_ioctl,
221 .open = twa_chrdev_open,
222 .release = NULL
223};
224
225/* This function will complete an aen request from the isr */
226static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
227{
228 TW_Command_Full *full_command_packet;
229 TW_Command *command_packet;
230 TW_Command_Apache_Header *header;
231 unsigned short aen;
232 int retval = 1;
233
234 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
235 tw_dev->posted_request_count--;
adam radford75913d92006-03-15 12:43:19 -0800236 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 full_command_packet = tw_dev->command_packet_virt[request_id];
238 command_packet = &full_command_packet->command.oldcommand;
239
240 /* First check for internal completion of set param for time sync */
241 if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
242 /* Keep reading the queue in case there are more aen's */
243 if (twa_aen_read_queue(tw_dev, request_id))
244 goto out2;
245 else {
246 retval = 0;
247 goto out;
248 }
249 }
250
251 switch (aen) {
252 case TW_AEN_QUEUE_EMPTY:
253 /* Quit reading the queue if this is the last one */
254 break;
255 case TW_AEN_SYNC_TIME_WITH_HOST:
256 twa_aen_sync_time(tw_dev, request_id);
257 retval = 0;
258 goto out;
259 default:
260 twa_aen_queue_event(tw_dev, header);
261
262 /* If there are more aen's, keep reading the queue */
263 if (twa_aen_read_queue(tw_dev, request_id))
264 goto out2;
265 else {
266 retval = 0;
267 goto out;
268 }
269 }
270 retval = 0;
271out2:
272 tw_dev->state[request_id] = TW_S_COMPLETED;
273 twa_free_request_id(tw_dev, request_id);
274 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
275out:
276 return retval;
277} /* End twa_aen_complete() */
278
279/* This function will drain aen queue */
280static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
281{
282 int request_id = 0;
283 char cdb[TW_MAX_CDB_LEN];
284 TW_SG_Entry sglist[1];
285 int finished = 0, count = 0;
286 TW_Command_Full *full_command_packet;
287 TW_Command_Apache_Header *header;
288 unsigned short aen;
289 int first_reset = 0, queue = 0, retval = 1;
290
291 if (no_check_reset)
292 first_reset = 0;
293 else
294 first_reset = 1;
295
296 full_command_packet = tw_dev->command_packet_virt[request_id];
297 memset(full_command_packet, 0, sizeof(TW_Command_Full));
298
299 /* Initialize cdb */
300 memset(&cdb, 0, TW_MAX_CDB_LEN);
301 cdb[0] = REQUEST_SENSE; /* opcode */
302 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
303
304 /* Initialize sglist */
305 memset(&sglist, 0, sizeof(TW_SG_Entry));
306 sglist[0].length = TW_SECTOR_SIZE;
307 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
308
309 if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
310 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
311 goto out;
312 }
313
314 /* Mark internal command */
315 tw_dev->srb[request_id] = NULL;
316
317 do {
318 /* Send command to the board */
319 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
320 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
321 goto out;
322 }
323
324 /* Now poll for completion */
325 if (twa_poll_response(tw_dev, request_id, 30)) {
326 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
327 tw_dev->posted_request_count--;
328 goto out;
329 }
330
331 tw_dev->posted_request_count--;
332 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
adam radford75913d92006-03-15 12:43:19 -0800333 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 queue = 0;
335 count++;
336
337 switch (aen) {
338 case TW_AEN_QUEUE_EMPTY:
339 if (first_reset != 1)
340 goto out;
341 else
342 finished = 1;
343 break;
344 case TW_AEN_SOFT_RESET:
345 if (first_reset == 0)
346 first_reset = 1;
347 else
348 queue = 1;
349 break;
350 case TW_AEN_SYNC_TIME_WITH_HOST:
351 break;
352 default:
353 queue = 1;
354 }
355
356 /* Now queue an event info */
357 if (queue)
358 twa_aen_queue_event(tw_dev, header);
359 } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
360
361 if (count == TW_MAX_AEN_DRAIN)
362 goto out;
363
364 retval = 0;
365out:
366 tw_dev->state[request_id] = TW_S_INITIAL;
367 return retval;
368} /* End twa_aen_drain_queue() */
369
370/* This function will queue an event */
371static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
372{
373 u32 local_time;
374 struct timeval time;
375 TW_Event *event;
376 unsigned short aen;
377 char host[16];
378 char *error_str;
379
380 tw_dev->aen_count++;
381
382 /* Fill out event info */
383 event = tw_dev->event_queue[tw_dev->error_index];
384
385 /* Check for clobber */
386 host[0] = '\0';
387 if (tw_dev->host) {
388 sprintf(host, " scsi%d:", tw_dev->host->host_no);
389 if (event->retrieved == TW_AEN_NOT_RETRIEVED)
390 tw_dev->aen_clobber = 1;
391 }
392
adam radford75913d92006-03-15 12:43:19 -0800393 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 memset(event, 0, sizeof(TW_Event));
395
396 event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
397 do_gettimeofday(&time);
398 local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
399 event->time_stamp_sec = local_time;
400 event->aen_code = aen;
401 event->retrieved = TW_AEN_NOT_RETRIEVED;
402 event->sequence_id = tw_dev->error_sequence_id;
403 tw_dev->error_sequence_id++;
404
405 /* Check for embedded error string */
406 error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
407
408 header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
409 event->parameter_len = strlen(header->err_specific_desc);
adam radford75913d92006-03-15 12:43:19 -0800410 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 -0700411 if (event->severity != TW_AEN_SEVERITY_DEBUG)
412 printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
413 host,
414 twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
415 TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
416 error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
417 header->err_specific_desc);
418 else
419 tw_dev->aen_count--;
420
421 if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
422 tw_dev->event_queue_wrapped = 1;
423 tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
424} /* End twa_aen_queue_event() */
425
426/* This function will read the aen queue from the isr */
427static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
428{
429 char cdb[TW_MAX_CDB_LEN];
430 TW_SG_Entry sglist[1];
431 TW_Command_Full *full_command_packet;
432 int retval = 1;
433
434 full_command_packet = tw_dev->command_packet_virt[request_id];
435 memset(full_command_packet, 0, sizeof(TW_Command_Full));
436
437 /* Initialize cdb */
438 memset(&cdb, 0, TW_MAX_CDB_LEN);
439 cdb[0] = REQUEST_SENSE; /* opcode */
440 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
441
442 /* Initialize sglist */
443 memset(&sglist, 0, sizeof(TW_SG_Entry));
444 sglist[0].length = TW_SECTOR_SIZE;
445 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
446
447 /* Mark internal command */
448 tw_dev->srb[request_id] = NULL;
449
450 /* Now post the command packet */
451 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
452 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
453 goto out;
454 }
455 retval = 0;
456out:
457 return retval;
458} /* End twa_aen_read_queue() */
459
460/* This function will look up an AEN severity string */
461static char *twa_aen_severity_lookup(unsigned char severity_code)
462{
463 char *retval = NULL;
464
465 if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
466 (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
467 goto out;
468
469 retval = twa_aen_severity_table[severity_code];
470out:
471 return retval;
472} /* End twa_aen_severity_lookup() */
473
474/* This function will sync firmware time with the host time */
475static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
476{
477 u32 schedulertime;
478 struct timeval utc;
479 TW_Command_Full *full_command_packet;
480 TW_Command *command_packet;
481 TW_Param_Apache *param;
482 u32 local_time;
483
484 /* Fill out the command packet */
485 full_command_packet = tw_dev->command_packet_virt[request_id];
486 memset(full_command_packet, 0, sizeof(TW_Command_Full));
487 command_packet = &full_command_packet->command.oldcommand;
488 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
489 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -0800490 command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
491 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 command_packet->size = TW_COMMAND_SIZE;
adam radford75913d92006-03-15 12:43:19 -0800493 command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 /* Setup the param */
496 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
497 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -0800498 param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */
499 param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
500 param->parameter_size_bytes = cpu_to_le16(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 /* Convert system time in UTC to local time seconds since last
503 Sunday 12:00AM */
504 do_gettimeofday(&utc);
505 local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
506 schedulertime = local_time - (3 * 86400);
adam radford75913d92006-03-15 12:43:19 -0800507 schedulertime = cpu_to_le32(schedulertime % 604800);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 memcpy(param->data, &schedulertime, sizeof(u32));
510
511 /* Mark internal command */
512 tw_dev->srb[request_id] = NULL;
513
514 /* Now post the command */
515 twa_post_command_packet(tw_dev, request_id, 1);
516} /* End twa_aen_sync_time() */
517
518/* This function will allocate memory and check if it is correctly aligned */
519static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
520{
521 int i;
522 dma_addr_t dma_handle;
523 unsigned long *cpu_addr;
524 int retval = 1;
525
526 cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
527 if (!cpu_addr) {
528 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
529 goto out;
530 }
531
532 if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
533 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
534 pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
535 goto out;
536 }
537
538 memset(cpu_addr, 0, size*TW_Q_LENGTH);
539
540 for (i = 0; i < TW_Q_LENGTH; i++) {
541 switch(which) {
542 case 0:
543 tw_dev->command_packet_phys[i] = dma_handle+(i*size);
544 tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
545 break;
546 case 1:
547 tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
548 tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
549 break;
550 }
551 }
552 retval = 0;
553out:
554 return retval;
555} /* End twa_allocate_memory() */
556
557/* This function will check the status register for unexpected bits */
558static int twa_check_bits(u32 status_reg_value)
559{
560 int retval = 1;
561
562 if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
563 goto out;
564 if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
565 goto out;
566
567 retval = 0;
568out:
569 return retval;
570} /* End twa_check_bits() */
571
572/* This function will check the srl and decide if we are compatible */
573static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
574{
575 int retval = 1;
576 unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
577 unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
578 u32 init_connect_result = 0;
579
580 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
581 TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
582 TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
583 TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
584 &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
585 &fw_on_ctlr_build, &init_connect_result)) {
586 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
587 goto out;
588 }
589
adam radford4039c302006-10-26 18:01:06 -0700590 tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl;
591 tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch;
592 tw_dev->tw_compat_info.working_build = fw_on_ctlr_build;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 /* Try base mode compatibility */
595 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
596 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
597 TW_EXTENDED_INIT_CONNECT,
598 TW_BASE_FW_SRL, TW_9000_ARCH_ID,
599 TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
600 &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
601 &fw_on_ctlr_branch, &fw_on_ctlr_build,
602 &init_connect_result)) {
603 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
604 goto out;
605 }
606 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
607 if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
608 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
609 } else {
610 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
611 }
612 goto out;
613 }
adam radford4039c302006-10-26 18:01:06 -0700614 tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL;
615 tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH;
616 tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
adam radford4039c302006-10-26 18:01:06 -0700618
619 /* Load rest of compatibility struct */
620 strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
621 tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
622 tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
623 tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
624 tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
625 tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
626 tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
627 tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
628 tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
629 tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 retval = 0;
632out:
633 return retval;
634} /* End twa_check_srl() */
635
636/* This function handles ioctl for the character device */
637static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
638{
639 long timeout;
640 unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
641 dma_addr_t dma_handle;
642 int request_id = 0;
643 unsigned int sequence_id = 0;
644 unsigned char event_index, start_index;
645 TW_Ioctl_Driver_Command driver_command;
646 TW_Ioctl_Buf_Apache *tw_ioctl;
647 TW_Lock *tw_lock;
648 TW_Command_Full *full_command_packet;
649 TW_Compatibility_Info *tw_compat_info;
650 TW_Event *event;
651 struct timeval current_time;
652 u32 current_time_ms;
653 TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
654 int retval = TW_IOCTL_ERROR_OS_EFAULT;
655 void __user *argp = (void __user *)arg;
656
657 /* Only let one of these through at a time */
Jes Sorensena12e25b2006-01-11 08:39:45 -0500658 if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 retval = TW_IOCTL_ERROR_OS_EINTR;
660 goto out;
661 }
662
663 /* First copy down the driver command */
664 if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
665 goto out2;
666
667 /* Check data buffer size */
adam radford4039c302006-10-26 18:01:06 -0700668 if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 retval = TW_IOCTL_ERROR_OS_EINVAL;
670 goto out2;
671 }
672
673 /* Hardware can only do multiple of 512 byte transfers */
674 data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
675
676 /* Now allocate ioctl buf memory */
677 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);
678 if (!cpu_addr) {
679 retval = TW_IOCTL_ERROR_OS_ENOMEM;
680 goto out2;
681 }
682
683 tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
684
685 /* Now copy down the entire ioctl */
686 if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
687 goto out3;
688
689 /* See which ioctl we are doing */
690 switch (cmd) {
691 case TW_IOCTL_FIRMWARE_PASS_THROUGH:
692 spin_lock_irqsave(tw_dev->host->host_lock, flags);
693 twa_get_request_id(tw_dev, &request_id);
694
695 /* Flag internal command */
696 tw_dev->srb[request_id] = NULL;
697
698 /* Flag chrdev ioctl */
699 tw_dev->chrdev_request_id = request_id;
700
701 full_command_packet = &tw_ioctl->firmware_command;
702
703 /* Load request id and sglist for both command types */
adam radford0e78d152007-07-20 15:28:28 -0700704 twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
707
708 /* Now post the command packet to the controller */
709 twa_post_command_packet(tw_dev, request_id, 1);
710 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
711
712 timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
713
714 /* Now wait for command to complete */
715 timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* We timed out, and didn't get an interrupt */
718 if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
719 /* Now we need to reset the board */
720 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 -0700721 tw_dev->host->host_no, TW_DRIVER, 0x37,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 cmd);
723 retval = TW_IOCTL_ERROR_OS_EIO;
adam radford0e78d152007-07-20 15:28:28 -0700724 twa_reset_device_extension(tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 goto out3;
726 }
727
728 /* Now copy in the command packet response */
729 memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
730
731 /* Now complete the io */
732 spin_lock_irqsave(tw_dev->host->host_lock, flags);
733 tw_dev->posted_request_count--;
734 tw_dev->state[request_id] = TW_S_COMPLETED;
735 twa_free_request_id(tw_dev, request_id);
736 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
737 break;
738 case TW_IOCTL_GET_COMPATIBILITY_INFO:
739 tw_ioctl->driver_command.status = 0;
Dirk Hohndel06fe9fb2009-09-28 21:43:57 -0400740 /* Copy compatibility struct into ioctl data buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
adam radford4039c302006-10-26 18:01:06 -0700742 memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 break;
744 case TW_IOCTL_GET_LAST_EVENT:
745 if (tw_dev->event_queue_wrapped) {
746 if (tw_dev->aen_clobber) {
747 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
748 tw_dev->aen_clobber = 0;
749 } else
750 tw_ioctl->driver_command.status = 0;
751 } else {
752 if (!tw_dev->error_index) {
753 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
754 break;
755 }
756 tw_ioctl->driver_command.status = 0;
757 }
758 event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
759 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
760 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
761 break;
762 case TW_IOCTL_GET_FIRST_EVENT:
763 if (tw_dev->event_queue_wrapped) {
764 if (tw_dev->aen_clobber) {
765 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
766 tw_dev->aen_clobber = 0;
767 } else
768 tw_ioctl->driver_command.status = 0;
769 event_index = tw_dev->error_index;
770 } else {
771 if (!tw_dev->error_index) {
772 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
773 break;
774 }
775 tw_ioctl->driver_command.status = 0;
776 event_index = 0;
777 }
778 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
779 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
780 break;
781 case TW_IOCTL_GET_NEXT_EVENT:
782 event = (TW_Event *)tw_ioctl->data_buffer;
783 sequence_id = event->sequence_id;
784 tw_ioctl->driver_command.status = 0;
785
786 if (tw_dev->event_queue_wrapped) {
787 if (tw_dev->aen_clobber) {
788 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
789 tw_dev->aen_clobber = 0;
790 }
791 start_index = tw_dev->error_index;
792 } else {
793 if (!tw_dev->error_index) {
794 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
795 break;
796 }
797 start_index = 0;
798 }
799 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
800
801 if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
802 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
803 tw_dev->aen_clobber = 1;
804 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
805 break;
806 }
807 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
808 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
809 break;
810 case TW_IOCTL_GET_PREVIOUS_EVENT:
811 event = (TW_Event *)tw_ioctl->data_buffer;
812 sequence_id = event->sequence_id;
813 tw_ioctl->driver_command.status = 0;
814
815 if (tw_dev->event_queue_wrapped) {
816 if (tw_dev->aen_clobber) {
817 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
818 tw_dev->aen_clobber = 0;
819 }
820 start_index = tw_dev->error_index;
821 } else {
822 if (!tw_dev->error_index) {
823 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
824 break;
825 }
826 start_index = 0;
827 }
828 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
829
830 if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
831 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
832 tw_dev->aen_clobber = 1;
833 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
834 break;
835 }
836 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
837 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
838 break;
839 case TW_IOCTL_GET_LOCK:
840 tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
841 do_gettimeofday(&current_time);
842 current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
843
844 if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
845 tw_dev->ioctl_sem_lock = 1;
846 tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
847 tw_ioctl->driver_command.status = 0;
848 tw_lock->time_remaining_msec = tw_lock->timeout_msec;
849 } else {
850 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
851 tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
852 }
853 break;
854 case TW_IOCTL_RELEASE_LOCK:
855 if (tw_dev->ioctl_sem_lock == 1) {
856 tw_dev->ioctl_sem_lock = 0;
857 tw_ioctl->driver_command.status = 0;
858 } else {
859 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
860 }
861 break;
862 default:
863 retval = TW_IOCTL_ERROR_OS_ENOTTY;
864 goto out3;
865 }
866
867 /* Now copy the entire response to userspace */
868 if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
869 retval = 0;
870out3:
871 /* Now free ioctl buf memory */
872 dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
873out2:
Jes Sorensena12e25b2006-01-11 08:39:45 -0500874 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875out:
876 return retval;
877} /* End twa_chrdev_ioctl() */
878
879/* This function handles open for the character device */
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600880/* NOTE that this function will race with remove. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881static int twa_chrdev_open(struct inode *inode, struct file *file)
882{
883 unsigned int minor_number;
884 int retval = TW_IOCTL_ERROR_OS_ENODEV;
885
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600886 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 minor_number = iminor(inode);
888 if (minor_number >= twa_device_extension_count)
889 goto out;
890 retval = 0;
891out:
892 return retval;
893} /* End twa_chrdev_open() */
894
895/* This function will print readable messages from status register errors */
896static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
897{
898 int retval = 1;
899
900 /* Check for various error conditions and handle them appropriately */
901 if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
902 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
903 writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
904 }
905
906 if (status_reg_value & TW_STATUS_PCI_ABORT) {
907 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
908 writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
909 pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
910 }
911
912 if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
adam radford0e78d152007-07-20 15:28:28 -0700913 if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
914 (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
915 (!test_bit(TW_IN_RESET, &tw_dev->flags)))
adam radford4039c302006-10-26 18:01:06 -0700916 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
918 }
919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
921 if (tw_dev->reset_print == 0) {
922 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
923 tw_dev->reset_print = 1;
924 }
925 goto out;
926 }
927 retval = 0;
928out:
929 return retval;
930} /* End twa_decode_bits() */
931
932/* This function will empty the response queue */
933static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
934{
935 u32 status_reg_value, response_que_value;
936 int count = 0, retval = 1;
937
938 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
939
940 while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
941 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
942 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
943 count++;
944 }
945 if (count == TW_MAX_RESPONSE_DRAIN)
946 goto out;
947
948 retval = 0;
949out:
950 return retval;
951} /* End twa_empty_response_queue() */
952
adam radford49bfd8d2005-09-21 17:20:14 -0700953/* This function will clear the pchip/response queue on 9550SX */
954static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
955{
adam radford75913d92006-03-15 12:43:19 -0800956 u32 response_que_value = 0;
957 unsigned long before;
958 int retval = 1;
adam radford49bfd8d2005-09-21 17:20:14 -0700959
adam radford0e78d152007-07-20 15:28:28 -0700960 if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
adam radford75913d92006-03-15 12:43:19 -0800961 before = jiffies;
962 while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
adam radford49bfd8d2005-09-21 17:20:14 -0700963 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
adam radford4039c302006-10-26 18:01:06 -0700964 msleep(1);
adam radford75913d92006-03-15 12:43:19 -0800965 if (time_after(jiffies, before + HZ * 30))
adam radford49bfd8d2005-09-21 17:20:14 -0700966 goto out;
adam radford49bfd8d2005-09-21 17:20:14 -0700967 }
adam radford75913d92006-03-15 12:43:19 -0800968 /* P-chip settle time */
969 msleep(500);
adam radford49bfd8d2005-09-21 17:20:14 -0700970 retval = 0;
971 } else
972 retval = 0;
973out:
974 return retval;
975} /* End twa_empty_response_queue_large() */
976
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977/* This function passes sense keys from firmware to scsi layer */
978static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
979{
980 TW_Command_Full *full_command_packet;
981 unsigned short error;
982 int retval = 1;
983 char *error_str;
984
985 full_command_packet = tw_dev->command_packet_virt[request_id];
986
987 /* Check for embedded error string */
988 error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
989
990 /* Don't print error for Logical unit not supported during rollcall */
adam radford75913d92006-03-15 12:43:19 -0800991 error = le16_to_cpu(full_command_packet->header.status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
993 if (print_host)
994 printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
995 tw_dev->host->host_no,
996 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
997 full_command_packet->header.status_block.error,
998 error_str[0] == '\0' ?
999 twa_string_lookup(twa_error_table,
1000 full_command_packet->header.status_block.error) : error_str,
1001 full_command_packet->header.err_specific_desc);
1002 else
1003 printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
1004 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
1005 full_command_packet->header.status_block.error,
1006 error_str[0] == '\0' ?
1007 twa_string_lookup(twa_error_table,
1008 full_command_packet->header.status_block.error) : error_str,
1009 full_command_packet->header.err_specific_desc);
1010 }
1011
1012 if (copy_sense) {
1013 memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
1014 tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
1015 retval = TW_ISR_DONT_RESULT;
1016 goto out;
1017 }
1018 retval = 0;
1019out:
1020 return retval;
1021} /* End twa_fill_sense() */
1022
1023/* This function will free up device extension resources */
1024static void twa_free_device_extension(TW_Device_Extension *tw_dev)
1025{
1026 if (tw_dev->command_packet_virt[0])
1027 pci_free_consistent(tw_dev->tw_pci_dev,
1028 sizeof(TW_Command_Full)*TW_Q_LENGTH,
1029 tw_dev->command_packet_virt[0],
1030 tw_dev->command_packet_phys[0]);
1031
1032 if (tw_dev->generic_buffer_virt[0])
1033 pci_free_consistent(tw_dev->tw_pci_dev,
1034 TW_SECTOR_SIZE*TW_Q_LENGTH,
1035 tw_dev->generic_buffer_virt[0],
1036 tw_dev->generic_buffer_phys[0]);
1037
Jesper Juhlc9475cb2005-11-07 01:01:26 -08001038 kfree(tw_dev->event_queue[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039} /* End twa_free_device_extension() */
1040
1041/* This function will free a request id */
1042static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
1043{
1044 tw_dev->free_queue[tw_dev->free_tail] = request_id;
1045 tw_dev->state[request_id] = TW_S_FINISHED;
1046 tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
1047} /* End twa_free_request_id() */
1048
Alexey Dobriyan7f927fc2006-03-28 01:56:53 -08001049/* This function will get parameter table entries from the firmware */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
1051{
1052 TW_Command_Full *full_command_packet;
1053 TW_Command *command_packet;
1054 TW_Param_Apache *param;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 void *retval = NULL;
1056
1057 /* Setup the command packet */
1058 full_command_packet = tw_dev->command_packet_virt[request_id];
1059 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1060 command_packet = &full_command_packet->command.oldcommand;
1061
1062 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1063 command_packet->size = TW_COMMAND_SIZE;
1064 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001065 command_packet->byte6_offset.block_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 /* Now setup the param */
1068 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
1069 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001070 param->table_id = cpu_to_le16(table_id | 0x8000);
1071 param->parameter_id = cpu_to_le16(parameter_id);
1072 param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
adam radford3dabec72008-07-22 16:47:40 -07001074 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 -08001075 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 /* Post the command packet to the board */
1078 twa_post_command_packet(tw_dev, request_id, 1);
1079
1080 /* Poll for completion */
1081 if (twa_poll_response(tw_dev, request_id, 30))
1082 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
1083 else
1084 retval = (void *)&(param->data[0]);
1085
1086 tw_dev->posted_request_count--;
1087 tw_dev->state[request_id] = TW_S_INITIAL;
1088
1089 return retval;
1090} /* End twa_get_param() */
1091
1092/* This function will assign an available request id */
1093static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
1094{
1095 *request_id = tw_dev->free_queue[tw_dev->free_head];
1096 tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
1097 tw_dev->state[*request_id] = TW_S_STARTED;
1098} /* End twa_get_request_id() */
1099
1100/* This function will send an initconnection command to controller */
1101static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
1102 u32 set_features, unsigned short current_fw_srl,
1103 unsigned short current_fw_arch_id,
1104 unsigned short current_fw_branch,
1105 unsigned short current_fw_build,
1106 unsigned short *fw_on_ctlr_srl,
1107 unsigned short *fw_on_ctlr_arch_id,
1108 unsigned short *fw_on_ctlr_branch,
1109 unsigned short *fw_on_ctlr_build,
1110 u32 *init_connect_result)
1111{
1112 TW_Command_Full *full_command_packet;
1113 TW_Initconnect *tw_initconnect;
1114 int request_id = 0, retval = 1;
1115
1116 /* Initialize InitConnection command packet */
1117 full_command_packet = tw_dev->command_packet_virt[request_id];
1118 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1119 full_command_packet->header.header_desc.size_header = 128;
1120
1121 tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
1122 tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
1123 tw_initconnect->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001124 tw_initconnect->message_credits = cpu_to_le16(message_credits);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 tw_initconnect->features = set_features;
1126
1127 /* Turn on 64-bit sgl support if we need to */
1128 tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
1129
adam radford75913d92006-03-15 12:43:19 -08001130 tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
1131
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 if (set_features & TW_EXTENDED_INIT_CONNECT) {
1133 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
adam radford75913d92006-03-15 12:43:19 -08001134 tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
1135 tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
1136 tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
1137 tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 } else
1139 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
1140
1141 /* Send command packet to the board */
1142 twa_post_command_packet(tw_dev, request_id, 1);
1143
1144 /* Poll for completion */
1145 if (twa_poll_response(tw_dev, request_id, 30)) {
1146 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
1147 } else {
1148 if (set_features & TW_EXTENDED_INIT_CONNECT) {
adam radford75913d92006-03-15 12:43:19 -08001149 *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
1150 *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
1151 *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
1152 *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
1153 *init_connect_result = le32_to_cpu(tw_initconnect->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155 retval = 0;
1156 }
1157
1158 tw_dev->posted_request_count--;
1159 tw_dev->state[request_id] = TW_S_INITIAL;
1160
1161 return retval;
1162} /* End twa_initconnection() */
1163
1164/* This function will initialize the fields of a device extension */
1165static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
1166{
1167 int i, retval = 1;
1168
1169 /* Initialize command packet buffers */
1170 if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
1171 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
1172 goto out;
1173 }
1174
1175 /* Initialize generic buffer */
1176 if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
1177 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
1178 goto out;
1179 }
1180
1181 /* Allocate event info space */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001182 tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (!tw_dev->event_queue[0]) {
1184 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
1185 goto out;
1186 }
1187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 for (i = 0; i < TW_Q_LENGTH; i++) {
1190 tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
1191 tw_dev->free_queue[i] = i;
1192 tw_dev->state[i] = TW_S_INITIAL;
1193 }
1194
1195 tw_dev->pending_head = TW_Q_START;
1196 tw_dev->pending_tail = TW_Q_START;
1197 tw_dev->free_head = TW_Q_START;
1198 tw_dev->free_tail = TW_Q_START;
1199 tw_dev->error_sequence_id = 1;
1200 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1201
Jes Sorensena12e25b2006-01-11 08:39:45 -05001202 mutex_init(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 init_waitqueue_head(&tw_dev->ioctl_wqueue);
1204
1205 retval = 0;
1206out:
1207 return retval;
1208} /* End twa_initialize_device_extension() */
1209
1210/* This function is the interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +01001211static irqreturn_t twa_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
1213 int request_id, error = 0;
1214 u32 status_reg_value;
1215 TW_Response_Queue response_que;
1216 TW_Command_Full *full_command_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
1218 int handled = 0;
1219
1220 /* Get the per adapter lock */
1221 spin_lock(tw_dev->host->host_lock);
1222
1223 /* Read the registers */
1224 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1225
1226 /* Check if this is our interrupt, otherwise bail */
1227 if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
1228 goto twa_interrupt_bail;
1229
1230 handled = 1;
1231
adam radford4039c302006-10-26 18:01:06 -07001232 /* If we are resetting, bail */
1233 if (test_bit(TW_IN_RESET, &tw_dev->flags))
1234 goto twa_interrupt_bail;
1235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 /* Check controller for errors */
1237 if (twa_check_bits(status_reg_value)) {
1238 if (twa_decode_bits(tw_dev, status_reg_value)) {
1239 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1240 goto twa_interrupt_bail;
1241 }
1242 }
1243
1244 /* Handle host interrupt */
1245 if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
1246 TW_CLEAR_HOST_INTERRUPT(tw_dev);
1247
1248 /* Handle attention interrupt */
1249 if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
1250 TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
1251 if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
1252 twa_get_request_id(tw_dev, &request_id);
1253
1254 error = twa_aen_read_queue(tw_dev, request_id);
1255 if (error) {
1256 tw_dev->state[request_id] = TW_S_COMPLETED;
1257 twa_free_request_id(tw_dev, request_id);
1258 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
1259 }
1260 }
1261 }
1262
1263 /* Handle command interrupt */
1264 if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
1265 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1266 /* Drain as many pending commands as we can */
1267 while (tw_dev->pending_request_count > 0) {
1268 request_id = tw_dev->pending_queue[tw_dev->pending_head];
1269 if (tw_dev->state[request_id] != TW_S_PENDING) {
1270 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
1271 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1272 goto twa_interrupt_bail;
1273 }
1274 if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
1275 tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
1276 tw_dev->pending_request_count--;
1277 } else {
1278 /* If we get here, we will continue re-posting on the next command interrupt */
1279 break;
1280 }
1281 }
1282 }
1283
1284 /* Handle response interrupt */
1285 if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
1286
1287 /* Drain the response queue from the board */
1288 while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
1289 /* Complete the response */
1290 response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1291 request_id = TW_RESID_OUT(response_que.response_id);
1292 full_command_packet = tw_dev->command_packet_virt[request_id];
1293 error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 /* Check for command packet errors */
1295 if (full_command_packet->command.newcommand.status != 0) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001296 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 error = twa_fill_sense(tw_dev, request_id, 1, 1);
1298 } else {
1299 /* Skip ioctl error prints */
1300 if (request_id != tw_dev->chrdev_request_id) {
1301 error = twa_fill_sense(tw_dev, request_id, 0, 1);
1302 }
1303 }
1304 }
1305
1306 /* Check for correct state */
1307 if (tw_dev->state[request_id] != TW_S_POSTED) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001308 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
1310 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1311 goto twa_interrupt_bail;
1312 }
1313 }
1314
1315 /* Check for internal command completion */
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001316 if (tw_dev->srb[request_id] == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (request_id != tw_dev->chrdev_request_id) {
1318 if (twa_aen_complete(tw_dev, request_id))
1319 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
1320 } else {
1321 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1322 wake_up(&tw_dev->ioctl_wqueue);
1323 }
1324 } else {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001325 struct scsi_cmnd *cmd;
1326
1327 cmd = tw_dev->srb[request_id];
1328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 twa_scsiop_execute_scsi_complete(tw_dev, request_id);
1330 /* If no error command was a success */
1331 if (error == 0) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001332 cmd->result = (DID_OK << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
1334
1335 /* If error, command failed */
1336 if (error == 1) {
1337 /* Ask for a host reset */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001338 cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 }
1340
1341 /* Report residual bytes for single sgl */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001342 if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
1343 if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
1344 scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 }
1346
1347 /* Now complete the io */
1348 tw_dev->state[request_id] = TW_S_COMPLETED;
1349 twa_free_request_id(tw_dev, request_id);
1350 tw_dev->posted_request_count--;
1351 tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
1352 twa_unmap_scsi_data(tw_dev, request_id);
1353 }
1354
1355 /* Check for valid status after each drain */
1356 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1357 if (twa_check_bits(status_reg_value)) {
1358 if (twa_decode_bits(tw_dev, status_reg_value)) {
1359 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1360 goto twa_interrupt_bail;
1361 }
1362 }
1363 }
1364 }
1365
1366twa_interrupt_bail:
1367 spin_unlock(tw_dev->host->host_lock);
1368 return IRQ_RETVAL(handled);
1369} /* End twa_interrupt() */
1370
1371/* This function will load the request id and various sgls for ioctls */
adam radford0e78d152007-07-20 15:28:28 -07001372static 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 -07001373{
1374 TW_Command *oldcommand;
1375 TW_Command_Apache *newcommand;
1376 TW_SG_Entry *sgl;
adam radford0e78d152007-07-20 15:28:28 -07001377 unsigned int pae = 0;
1378
1379 if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
1380 pae = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
1382 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1383 newcommand = &full_command_packet->command.newcommand;
adam radford4039c302006-10-26 18:01:06 -07001384 newcommand->request_id__lunl =
1385 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
adam radford53ca3532009-12-10 11:53:31 -08001386 if (length) {
1387 newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1388 newcommand->sg_list[0].length = cpu_to_le32(length);
1389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 newcommand->sgl_entries__lunh =
adam radford53ca3532009-12-10 11:53:31 -08001391 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
1393 oldcommand = &full_command_packet->command.oldcommand;
1394 oldcommand->request_id = request_id;
1395
1396 if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
1397 /* Load the sg list */
adam radford0e78d152007-07-20 15:28:28 -07001398 if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
1399 sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
1400 else
1401 sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
adam radford75913d92006-03-15 12:43:19 -08001402 sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1403 sgl->length = cpu_to_le32(length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
adam radford0e78d152007-07-20 15:28:28 -07001405 oldcommand->size += pae;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 }
1407 }
1408} /* End twa_load_sgl() */
1409
1410/* This function will perform a pci-dma mapping for a scatter gather list */
1411static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
1412{
1413 int use_sg;
1414 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001416 use_sg = scsi_dma_map(cmd);
1417 if (!use_sg)
1418 return 0;
1419 else if (use_sg < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001421 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 }
1423
1424 cmd->SCp.phase = TW_PHASE_SGLIST;
1425 cmd->SCp.have_data_in = use_sg;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001426
1427 return use_sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428} /* End twa_map_scsi_sg_data() */
1429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430/* This function will poll for a response interrupt of a request */
1431static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
1432{
1433 int retval = 1, found = 0, response_request_id;
1434 TW_Response_Queue response_queue;
1435 TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
1436
1437 if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
1438 response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1439 response_request_id = TW_RESID_OUT(response_queue.response_id);
1440 if (request_id != response_request_id) {
1441 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
1442 goto out;
1443 }
1444 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1445 if (full_command_packet->command.newcommand.status != 0) {
1446 /* bad response */
1447 twa_fill_sense(tw_dev, request_id, 0, 0);
1448 goto out;
1449 }
1450 found = 1;
1451 } else {
1452 if (full_command_packet->command.oldcommand.status != 0) {
1453 /* bad response */
1454 twa_fill_sense(tw_dev, request_id, 0, 0);
1455 goto out;
1456 }
1457 found = 1;
1458 }
1459 }
1460
1461 if (found)
1462 retval = 0;
1463out:
1464 return retval;
1465} /* End twa_poll_response() */
1466
1467/* This function will poll the status register for a flag */
1468static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1469{
1470 u32 status_reg_value;
1471 unsigned long before;
1472 int retval = 1;
1473
1474 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1475 before = jiffies;
1476
1477 if (twa_check_bits(status_reg_value))
1478 twa_decode_bits(tw_dev, status_reg_value);
1479
1480 while ((status_reg_value & flag) != flag) {
1481 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1482
1483 if (twa_check_bits(status_reg_value))
1484 twa_decode_bits(tw_dev, status_reg_value);
1485
1486 if (time_after(jiffies, before + HZ * seconds))
1487 goto out;
1488
1489 msleep(50);
1490 }
1491 retval = 0;
1492out:
1493 return retval;
1494} /* End twa_poll_status() */
1495
1496/* This function will poll the status register for disappearance of a flag */
1497static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1498{
1499 u32 status_reg_value;
1500 unsigned long before;
1501 int retval = 1;
1502
1503 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1504 before = jiffies;
1505
1506 if (twa_check_bits(status_reg_value))
1507 twa_decode_bits(tw_dev, status_reg_value);
1508
1509 while ((status_reg_value & flag) != 0) {
1510 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1511 if (twa_check_bits(status_reg_value))
1512 twa_decode_bits(tw_dev, status_reg_value);
1513
1514 if (time_after(jiffies, before + HZ * seconds))
1515 goto out;
1516
1517 msleep(50);
1518 }
1519 retval = 0;
1520out:
1521 return retval;
1522} /* End twa_poll_status_gone() */
1523
1524/* This function will attempt to post a command packet to the board */
1525static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
1526{
1527 u32 status_reg_value;
1528 dma_addr_t command_que_value;
1529 int retval = 1;
1530
1531 command_que_value = tw_dev->command_packet_phys[request_id];
adam radford4039c302006-10-26 18:01:06 -07001532
1533 /* For 9650SE write low 4 bytes first */
adam radford0e78d152007-07-20 15:28:28 -07001534 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1535 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001536 command_que_value += TW_COMMAND_OFFSET;
1537 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
1538 }
1539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1541
1542 if (twa_check_bits(status_reg_value))
1543 twa_decode_bits(tw_dev, status_reg_value);
1544
1545 if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
1546
1547 /* Only pend internal driver commands */
1548 if (!internal) {
1549 retval = SCSI_MLQUEUE_HOST_BUSY;
1550 goto out;
1551 }
1552
1553 /* Couldn't post the command packet, so we do it later */
1554 if (tw_dev->state[request_id] != TW_S_PENDING) {
1555 tw_dev->state[request_id] = TW_S_PENDING;
1556 tw_dev->pending_request_count++;
1557 if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
1558 tw_dev->max_pending_request_count = tw_dev->pending_request_count;
1559 }
1560 tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
1561 tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
1562 }
1563 TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
1564 goto out;
1565 } else {
adam radford0e78d152007-07-20 15:28:28 -07001566 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1567 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001568 /* Now write upper 4 bytes */
1569 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 } else {
adam radford4039c302006-10-26 18:01:06 -07001571 if (sizeof(dma_addr_t) > 4) {
1572 command_que_value += TW_COMMAND_OFFSET;
1573 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1574 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
1575 } else {
1576 writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 }
1579 tw_dev->state[request_id] = TW_S_POSTED;
1580 tw_dev->posted_request_count++;
1581 if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
1582 tw_dev->max_posted_request_count = tw_dev->posted_request_count;
1583 }
1584 }
1585 retval = 0;
1586out:
1587 return retval;
1588} /* End twa_post_command_packet() */
1589
1590/* This function will reset a device extension */
adam radford0e78d152007-07-20 15:28:28 -07001591static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592{
1593 int i = 0;
1594 int retval = 1;
1595 unsigned long flags = 0;
1596
1597 set_bit(TW_IN_RESET, &tw_dev->flags);
1598 TW_DISABLE_INTERRUPTS(tw_dev);
1599 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1600 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1601
1602 /* Abort all requests that are in progress */
1603 for (i = 0; i < TW_Q_LENGTH; i++) {
1604 if ((tw_dev->state[i] != TW_S_FINISHED) &&
1605 (tw_dev->state[i] != TW_S_INITIAL) &&
1606 (tw_dev->state[i] != TW_S_COMPLETED)) {
1607 if (tw_dev->srb[i]) {
1608 tw_dev->srb[i]->result = (DID_RESET << 16);
1609 tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
1610 twa_unmap_scsi_data(tw_dev, i);
1611 }
1612 }
1613 }
1614
1615 /* Reset queues and counts */
1616 for (i = 0; i < TW_Q_LENGTH; i++) {
1617 tw_dev->free_queue[i] = i;
1618 tw_dev->state[i] = TW_S_INITIAL;
1619 }
1620 tw_dev->free_head = TW_Q_START;
1621 tw_dev->free_tail = TW_Q_START;
1622 tw_dev->posted_request_count = 0;
1623 tw_dev->pending_request_count = 0;
1624 tw_dev->pending_head = TW_Q_START;
1625 tw_dev->pending_tail = TW_Q_START;
1626 tw_dev->reset_print = 0;
1627
1628 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1629
1630 if (twa_reset_sequence(tw_dev, 1))
1631 goto out;
1632
1633 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
adam radford4039c302006-10-26 18:01:06 -07001634 clear_bit(TW_IN_RESET, &tw_dev->flags);
1635 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 retval = 0;
1638out:
1639 return retval;
1640} /* End twa_reset_device_extension() */
1641
1642/* This function will reset a controller */
1643static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
1644{
1645 int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
1646
1647 while (tries < TW_MAX_RESET_TRIES) {
adam radford49bfd8d2005-09-21 17:20:14 -07001648 if (do_soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 TW_SOFT_RESET(tw_dev);
adam radford49bfd8d2005-09-21 17:20:14 -07001650 /* Clear pchip/response queue on 9550SX */
1651 if (twa_empty_response_queue_large(tw_dev)) {
1652 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence");
1653 do_soft_reset = 1;
1654 tries++;
1655 continue;
1656 }
1657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659 /* Make sure controller is in a good state */
1660 if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
1661 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
1662 do_soft_reset = 1;
1663 tries++;
1664 continue;
1665 }
1666
1667 /* Empty response queue */
1668 if (twa_empty_response_queue(tw_dev)) {
1669 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
1670 do_soft_reset = 1;
1671 tries++;
1672 continue;
1673 }
1674
1675 flashed = 0;
1676
1677 /* Check for compatibility/flash */
1678 if (twa_check_srl(tw_dev, &flashed)) {
1679 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
1680 do_soft_reset = 1;
1681 tries++;
1682 continue;
1683 } else {
1684 if (flashed) {
1685 tries++;
1686 continue;
1687 }
1688 }
1689
1690 /* Drain the AEN queue */
1691 if (twa_aen_drain_queue(tw_dev, soft_reset)) {
1692 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
1693 do_soft_reset = 1;
1694 tries++;
1695 continue;
1696 }
1697
1698 /* If we got here, controller is in a good state */
1699 retval = 0;
1700 goto out;
1701 }
1702out:
1703 return retval;
1704} /* End twa_reset_sequence() */
1705
1706/* This funciton returns unit geometry in cylinders/heads/sectors */
1707static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
1708{
1709 int heads, sectors, cylinders;
1710 TW_Device_Extension *tw_dev;
1711
1712 tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
1713
1714 if (capacity >= 0x200000) {
1715 heads = 255;
1716 sectors = 63;
1717 cylinders = sector_div(capacity, heads * sectors);
1718 } else {
1719 heads = 64;
1720 sectors = 32;
1721 cylinders = sector_div(capacity, heads * sectors);
1722 }
1723
1724 geom[0] = heads;
1725 geom[1] = sectors;
1726 geom[2] = cylinders;
1727
1728 return 0;
1729} /* End twa_scsi_biosparam() */
1730
1731/* This is the new scsi eh reset function */
1732static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
1733{
1734 TW_Device_Extension *tw_dev = NULL;
1735 int retval = FAILED;
1736
1737 tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1738
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 tw_dev->num_resets++;
1740
Jeff Garzik017560f2005-10-24 18:04:36 -04001741 sdev_printk(KERN_WARNING, SCpnt->device,
1742 "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
1743 TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
adam radford4039c302006-10-26 18:01:06 -07001745 /* Make sure we are not issuing an ioctl or resetting from ioctl */
1746 mutex_lock(&tw_dev->ioctl_lock);
1747
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 /* Now reset the card and some of the device extension data */
adam radford0e78d152007-07-20 15:28:28 -07001749 if (twa_reset_device_extension(tw_dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
1751 goto out;
1752 }
1753
1754 retval = SUCCESS;
1755out:
adam radford4039c302006-10-26 18:01:06 -07001756 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return retval;
1758} /* End twa_scsi_eh_reset() */
1759
1760/* This is the main scsi queue function to handle scsi opcodes */
1761static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
1762{
1763 int request_id, retval;
1764 TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1765
adam radford4039c302006-10-26 18:01:06 -07001766 /* If we are resetting due to timed out ioctl, report as busy */
1767 if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
1768 retval = SCSI_MLQUEUE_HOST_BUSY;
1769 goto out;
1770 }
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 /* Check if this FW supports luns */
adam radford4039c302006-10-26 18:01:06 -07001773 if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 SCpnt->result = (DID_BAD_TARGET << 16);
1775 done(SCpnt);
1776 retval = 0;
1777 goto out;
1778 }
1779
1780 /* Save done function into scsi_cmnd struct */
1781 SCpnt->scsi_done = done;
1782
1783 /* Get a free request id */
1784 twa_get_request_id(tw_dev, &request_id);
1785
1786 /* Save the scsi command for use by the ISR */
1787 tw_dev->srb[request_id] = SCpnt;
1788
1789 /* Initialize phase to zero */
1790 SCpnt->SCp.phase = TW_PHASE_INITIAL;
1791
1792 retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
1793 switch (retval) {
1794 case SCSI_MLQUEUE_HOST_BUSY:
1795 twa_free_request_id(tw_dev, request_id);
1796 break;
1797 case 1:
1798 tw_dev->state[request_id] = TW_S_COMPLETED;
1799 twa_free_request_id(tw_dev, request_id);
1800 SCpnt->result = (DID_ERROR << 16);
1801 done(SCpnt);
1802 retval = 0;
1803 }
1804out:
1805 return retval;
1806} /* End twa_scsi_queue() */
1807
1808/* This function hands scsi cdb's to the firmware */
1809static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
1810{
1811 TW_Command_Full *full_command_packet;
1812 TW_Command_Apache *command_packet;
1813 u32 num_sectors = 0x0;
1814 int i, sg_count;
1815 struct scsi_cmnd *srb = NULL;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001816 struct scatterlist *sglist = NULL, *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 int retval = 1;
1818
1819 if (tw_dev->srb[request_id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 srb = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001821 if (scsi_sglist(srb))
1822 sglist = scsi_sglist(srb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 }
1824
1825 /* Initialize command packet */
1826 full_command_packet = tw_dev->command_packet_virt[request_id];
1827 full_command_packet->header.header_desc.size_header = 128;
1828 full_command_packet->header.status_block.error = 0;
1829 full_command_packet->header.status_block.severity__reserved = 0;
1830
1831 command_packet = &full_command_packet->command.newcommand;
1832 command_packet->status = 0;
1833 command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
1834
1835 /* We forced 16 byte cdb use earlier */
1836 if (!cdb)
1837 memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
1838 else
1839 memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
1840
1841 if (srb) {
1842 command_packet->unit = srb->device->id;
1843 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001844 cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 } else {
1846 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001847 cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 command_packet->unit = 0;
1849 }
1850
1851 command_packet->sgl_offset = 16;
1852
1853 if (!sglistarg) {
1854 /* Map sglist from scsi layer to cmd packet */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001856 if (scsi_sg_count(srb)) {
1857 if ((scsi_sg_count(srb) == 1) &&
1858 (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001859 if (srb->sc_data_direction == DMA_TO_DEVICE ||
1860 srb->sc_data_direction == DMA_BIDIRECTIONAL)
1861 scsi_sg_copy_to_buffer(srb,
1862 tw_dev->generic_buffer_virt[request_id],
1863 TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001864 command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
1865 command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 } else {
1867 sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
1868 if (sg_count == 0)
1869 goto out;
1870
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001871 scsi_for_each_sg(srb, sg, sg_count, i) {
1872 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
1873 command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
adam radford75913d92006-03-15 12:43:19 -08001874 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
1876 goto out;
1877 }
1878 }
1879 }
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001880 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 -07001881 }
1882 } else {
1883 /* Internal cdb post */
1884 for (i = 0; i < use_sg; i++) {
adam radford75913d92006-03-15 12:43:19 -08001885 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
1886 command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length);
1887 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
1889 goto out;
1890 }
1891 }
adam radford75913d92006-03-15 12:43:19 -08001892 command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
1894
1895 if (srb) {
1896 if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
1897 num_sectors = (u32)srb->cmnd[4];
1898
1899 if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
1900 num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
1901 }
1902
1903 /* Update sector statistic */
1904 tw_dev->sector_count = num_sectors;
1905 if (tw_dev->sector_count > tw_dev->max_sector_count)
1906 tw_dev->max_sector_count = tw_dev->sector_count;
1907
1908 /* Update SG statistics */
1909 if (srb) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001910 tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
1912 tw_dev->max_sgl_entries = tw_dev->sgl_entries;
1913 }
1914
1915 /* Now post the command to the board */
1916 if (srb) {
1917 retval = twa_post_command_packet(tw_dev, request_id, 0);
1918 } else {
1919 twa_post_command_packet(tw_dev, request_id, 1);
1920 retval = 0;
1921 }
1922out:
1923 return retval;
1924} /* End twa_scsiop_execute_scsi() */
1925
1926/* This function completes an execute scsi operation */
1927static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
1928{
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001929 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001930
1931 if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH &&
1932 (cmd->sc_data_direction == DMA_FROM_DEVICE ||
1933 cmd->sc_data_direction == DMA_BIDIRECTIONAL)) {
FUJITA Tomonorib1192d52007-05-31 15:24:03 +09001934 if (scsi_sg_count(cmd) == 1) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001935 void *buf = tw_dev->generic_buffer_virt[request_id];
1936
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001937 scsi_sg_copy_from_buffer(cmd, buf, TW_SECTOR_SIZE);
adam radfordd327d082005-09-09 15:55:13 -07001938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 }
1940} /* End twa_scsiop_execute_scsi_complete() */
1941
1942/* This function tells the controller to shut down */
1943static void __twa_shutdown(TW_Device_Extension *tw_dev)
1944{
1945 /* Disable interrupts */
1946 TW_DISABLE_INTERRUPTS(tw_dev);
1947
adam radford4039c302006-10-26 18:01:06 -07001948 /* Free up the IRQ */
1949 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
1950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
1952
1953 /* Tell the card we are shutting down */
1954 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
1955 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
1956 } else {
1957 printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
1958 }
1959
1960 /* Clear all interrupts just before exit */
1961 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1962} /* End __twa_shutdown() */
1963
1964/* Wrapper for __twa_shutdown */
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001965static void twa_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001967 struct Scsi_Host *host = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
1969
1970 __twa_shutdown(tw_dev);
1971} /* End twa_shutdown() */
1972
1973/* This function will look up a string */
1974static char *twa_string_lookup(twa_message_type *table, unsigned int code)
1975{
1976 int index;
1977
1978 for (index = 0; ((code != table[index].code) &&
1979 (table[index].text != (char *)0)); index++);
1980 return(table[index].text);
1981} /* End twa_string_lookup() */
1982
1983/* This function will perform a pci-dma unmap */
1984static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
1985{
1986 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
adam radford8454e982009-05-05 11:45:37 -07001988 if (cmd->SCp.phase == TW_PHASE_SGLIST)
1989 scsi_dma_unmap(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990} /* End twa_unmap_scsi_data() */
1991
1992/* scsi_host_template initializer */
1993static struct scsi_host_template driver_template = {
1994 .module = THIS_MODULE,
1995 .name = "3ware 9000 Storage Controller",
1996 .queuecommand = twa_scsi_queue,
1997 .eh_host_reset_handler = twa_scsi_eh_reset,
1998 .bios_param = twa_scsi_biosparam,
1999 .change_queue_depth = twa_change_queue_depth,
2000 .can_queue = TW_Q_LENGTH-2,
2001 .this_id = -1,
2002 .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH,
2003 .max_sectors = TW_MAX_SECTORS,
2004 .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
2005 .use_clustering = ENABLE_CLUSTERING,
2006 .shost_attrs = twa_host_attrs,
2007 .emulated = 1
2008};
2009
2010/* This function will probe and initialize a card */
2011static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
2012{
2013 struct Scsi_Host *host = NULL;
2014 TW_Device_Extension *tw_dev;
adam radford3dabec72008-07-22 16:47:40 -07002015 unsigned long mem_addr, mem_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 int retval = -ENODEV;
2017
2018 retval = pci_enable_device(pdev);
2019 if (retval) {
2020 TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
2021 goto out_disable_device;
2022 }
2023
2024 pci_set_master(pdev);
Tony Battersby1e6c38c2007-11-09 13:04:35 -05002025 pci_try_set_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Yang Hongyang6a355282009-04-06 19:01:13 -07002027 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2028 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
Yang Hongyang284901a2009-04-06 19:01:15 -07002029 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2030 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford0e78d152007-07-20 15:28:28 -07002031 TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
2032 retval = -ENODEV;
2033 goto out_disable_device;
2034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
2036 host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
2037 if (!host) {
2038 TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
2039 retval = -ENOMEM;
2040 goto out_disable_device;
2041 }
2042 tw_dev = (TW_Device_Extension *)host->hostdata;
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 /* Save values to device extension */
2045 tw_dev->host = host;
2046 tw_dev->tw_pci_dev = pdev;
2047
2048 if (twa_initialize_device_extension(tw_dev)) {
2049 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
2050 goto out_free_device_extension;
2051 }
2052
2053 /* Request IO regions */
2054 retval = pci_request_regions(pdev, "3w-9xxx");
2055 if (retval) {
2056 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
2057 goto out_free_device_extension;
2058 }
2059
adam radford3dabec72008-07-22 16:47:40 -07002060 if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
adam radford49bfd8d2005-09-21 17:20:14 -07002061 mem_addr = pci_resource_start(pdev, 1);
adam radford3dabec72008-07-22 16:47:40 -07002062 mem_len = pci_resource_len(pdev, 1);
2063 } else {
adam radford49bfd8d2005-09-21 17:20:14 -07002064 mem_addr = pci_resource_start(pdev, 2);
adam radford3dabec72008-07-22 16:47:40 -07002065 mem_len = pci_resource_len(pdev, 2);
2066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
2068 /* Save base address */
adam radford3dabec72008-07-22 16:47:40 -07002069 tw_dev->base_addr = ioremap(mem_addr, mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (!tw_dev->base_addr) {
2071 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
2072 goto out_release_mem_region;
2073 }
2074
2075 /* Disable interrupts on the card */
2076 TW_DISABLE_INTERRUPTS(tw_dev);
2077
2078 /* Initialize the card */
2079 if (twa_reset_sequence(tw_dev, 0))
adam radford4039c302006-10-26 18:01:06 -07002080 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 /* Set host specific parameters */
adam radford0e78d152007-07-20 15:28:28 -07002083 if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
2084 (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
adam radford4039c302006-10-26 18:01:06 -07002085 host->max_id = TW_MAX_UNITS_9650SE;
2086 else
2087 host->max_id = TW_MAX_UNITS;
2088
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 host->max_cmd_len = TW_MAX_CDB_LEN;
2090
2091 /* Channels aren't supported by adapter */
adam radford4039c302006-10-26 18:01:06 -07002092 host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 host->max_channel = 0;
2094
2095 /* Register the card with the kernel SCSI layer */
2096 retval = scsi_add_host(host, &pdev->dev);
2097 if (retval) {
2098 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
adam radford4039c302006-10-26 18:01:06 -07002099 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 }
2101
2102 pci_set_drvdata(pdev, host);
2103
adam radford3dabec72008-07-22 16:47:40 -07002104 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 -07002105 host->host_no, mem_addr, pdev->irq);
2106 printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
2107 host->host_no,
2108 (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
2109 TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
2110 (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
2111 TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
adam radford75913d92006-03-15 12:43:19 -08002112 le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
2113 TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
adam radford3dabec72008-07-22 16:47:40 -07002115 /* Try to enable MSI */
2116 if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
2117 !pci_enable_msi(pdev))
2118 set_bit(TW_USING_MSI, &tw_dev->flags);
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 /* Now setup the interrupt handler */
Thomas Gleixner1d6f3592006-07-01 19:29:42 -07002121 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 if (retval) {
2123 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
2124 goto out_remove_host;
2125 }
2126
2127 twa_device_extension_list[twa_device_extension_count] = tw_dev;
2128 twa_device_extension_count++;
2129
2130 /* Re-enable interrupts on the card */
2131 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2132
2133 /* Finally, scan the host */
2134 scsi_scan_host(host);
2135
2136 if (twa_major == -1) {
2137 if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
2138 TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
2139 }
2140 return 0;
2141
2142out_remove_host:
adam radford3dabec72008-07-22 16:47:40 -07002143 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2144 pci_disable_msi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 scsi_remove_host(host);
adam radford4039c302006-10-26 18:01:06 -07002146out_iounmap:
2147 iounmap(tw_dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148out_release_mem_region:
2149 pci_release_regions(pdev);
2150out_free_device_extension:
2151 twa_free_device_extension(tw_dev);
2152 scsi_host_put(host);
2153out_disable_device:
2154 pci_disable_device(pdev);
2155
2156 return retval;
2157} /* End twa_probe() */
2158
2159/* This function is called to remove a device */
2160static void twa_remove(struct pci_dev *pdev)
2161{
2162 struct Scsi_Host *host = pci_get_drvdata(pdev);
2163 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2164
2165 scsi_remove_host(tw_dev->host);
2166
2167 /* Unregister character device */
2168 if (twa_major >= 0) {
2169 unregister_chrdev(twa_major, "twa");
2170 twa_major = -1;
2171 }
2172
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 /* Shutdown the card */
2174 __twa_shutdown(tw_dev);
2175
adam radford3dabec72008-07-22 16:47:40 -07002176 /* Disable MSI if enabled */
2177 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2178 pci_disable_msi(pdev);
2179
adam radford4039c302006-10-26 18:01:06 -07002180 /* Free IO remapping */
2181 iounmap(tw_dev->base_addr);
2182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 /* Free up the mem region */
2184 pci_release_regions(pdev);
2185
2186 /* Free up device extension resources */
2187 twa_free_device_extension(tw_dev);
2188
2189 scsi_host_put(tw_dev->host);
2190 pci_disable_device(pdev);
2191 twa_device_extension_count--;
2192} /* End twa_remove() */
2193
adam radford7a252fe2009-03-09 12:15:01 -08002194#ifdef CONFIG_PM
2195/* This function is called on PCI suspend */
2196static int twa_suspend(struct pci_dev *pdev, pm_message_t state)
2197{
2198 struct Scsi_Host *host = pci_get_drvdata(pdev);
2199 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2200
2201 printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no);
2202
2203 TW_DISABLE_INTERRUPTS(tw_dev);
2204 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
2205
2206 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2207 pci_disable_msi(pdev);
2208
2209 /* Tell the card we are shutting down */
2210 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
2211 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend");
2212 } else {
2213 printk(KERN_WARNING "3w-9xxx: Suspend complete.\n");
2214 }
2215 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
2216
2217 pci_save_state(pdev);
2218 pci_disable_device(pdev);
2219 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2220
2221 return 0;
2222} /* End twa_suspend() */
2223
2224/* This function is called on PCI resume */
2225static int twa_resume(struct pci_dev *pdev)
2226{
2227 int retval = 0;
2228 struct Scsi_Host *host = pci_get_drvdata(pdev);
2229 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2230
2231 printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no);
2232 pci_set_power_state(pdev, PCI_D0);
2233 pci_enable_wake(pdev, PCI_D0, 0);
2234 pci_restore_state(pdev);
2235
2236 retval = pci_enable_device(pdev);
2237 if (retval) {
2238 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume");
2239 return retval;
2240 }
2241
2242 pci_set_master(pdev);
2243 pci_try_set_mwi(pdev);
2244
Yang Hongyange9304382009-04-13 14:40:14 -07002245 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2246 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
2247 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2248 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford7a252fe2009-03-09 12:15:01 -08002249 TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
2250 retval = -ENODEV;
2251 goto out_disable_device;
2252 }
2253
2254 /* Initialize the card */
2255 if (twa_reset_sequence(tw_dev, 0)) {
2256 retval = -ENODEV;
2257 goto out_disable_device;
2258 }
2259
2260 /* Now setup the interrupt handler */
2261 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
2262 if (retval) {
2263 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume");
2264 retval = -ENODEV;
2265 goto out_disable_device;
2266 }
2267
2268 /* Now enable MSI if enabled */
2269 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2270 pci_enable_msi(pdev);
2271
2272 /* Re-enable interrupts on the card */
2273 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2274
2275 printk(KERN_WARNING "3w-9xxx: Resume complete.\n");
2276 return 0;
2277
2278out_disable_device:
2279 scsi_remove_host(host);
2280 pci_disable_device(pdev);
2281
2282 return retval;
2283} /* End twa_resume() */
2284#endif
2285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286/* PCI Devices supported by this driver */
2287static struct pci_device_id twa_pci_tbl[] __devinitdata = {
2288 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
2289 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford49bfd8d2005-09-21 17:20:14 -07002290 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
2291 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford4039c302006-10-26 18:01:06 -07002292 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
2293 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford0e78d152007-07-20 15:28:28 -07002294 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
2295 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 { }
2297};
2298MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
2299
2300/* pci_driver initializer */
2301static struct pci_driver twa_driver = {
2302 .name = "3w-9xxx",
2303 .id_table = twa_pci_tbl,
2304 .probe = twa_probe,
2305 .remove = twa_remove,
adam radford7a252fe2009-03-09 12:15:01 -08002306#ifdef CONFIG_PM
2307 .suspend = twa_suspend,
2308 .resume = twa_resume,
2309#endif
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002310 .shutdown = twa_shutdown
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311};
2312
2313/* This function is called on driver initialization */
2314static int __init twa_init(void)
2315{
2316 printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
2317
Henrik Kretzschmardcbccbde2006-09-25 16:58:58 -07002318 return pci_register_driver(&twa_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319} /* End twa_init() */
2320
2321/* This function is called on driver exit */
2322static void __exit twa_exit(void)
2323{
2324 pci_unregister_driver(&twa_driver);
2325} /* End twa_exit() */
2326
2327module_init(twa_init);
2328module_exit(twa_exit);
2329