blob: b78a2f3745f2f56c9a18ca98070adb1ea8b44541 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
3
adam radford4deedd82010-03-08 12:37:46 -08004 Written By: Adam Radford <linuxraid@lsi.com>
5 Modifications By: Tom Couch <linuxraid@lsi.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
adam radford7a252fe2009-03-09 12:15:01 -08007 Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
adam radford4deedd82010-03-08 12:37:46 -08008 Copyright (C) 2010 LSI Corporation.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; version 2 of the License.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 NO WARRANTY
20 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
21 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
22 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
23 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
24 solely responsible for determining the appropriateness of using and
25 distributing the Program and assumes all risks associated with its
26 exercise of rights under this Agreement, including but not limited to
27 the risks and costs of program errors, damage to or loss of data,
28 programs or equipment, and unavailability or interruption of operations.
29
30 DISCLAIMER OF LIABILITY
31 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
32 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
34 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
35 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
37 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
38
39 You should have received a copy of the GNU General Public License
40 along with this program; if not, write to the Free Software
41 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42
43 Bugs/Comments/Suggestions should be mailed to:
adam radford4deedd82010-03-08 12:37:46 -080044 linuxraid@lsi.com
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 For more information, goto:
adam radford4deedd82010-03-08 12:37:46 -080047 http://www.lsi.com
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49 Note: This version of the driver does not contain a bundled firmware
50 image.
51
52 History
53 -------
54 2.26.02.000 - Driver cleanup for kernel submission.
55 2.26.02.001 - Replace schedule_timeout() calls with msleep().
56 2.26.02.002 - Add support for PAE mode.
57 Add lun support.
58 Fix twa_remove() to free irq handler/unregister_chrdev()
59 before shutting down card.
60 Change to new 'change_queue_depth' api.
61 Fix 'handled=1' ISR usage, remove bogus IRQ check.
62 Remove un-needed eh_abort handler.
63 Add support for embedded firmware error strings.
adam radfordd327d082005-09-09 15:55:13 -070064 2.26.02.003 - Correctly handle single sgl's with use_sg=1.
adam radford49bfd8d2005-09-21 17:20:14 -070065 2.26.02.004 - Add support for 9550SX controllers.
adam radford62288f12006-02-05 14:51:43 -080066 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher.
adam radford75913d92006-03-15 12:43:19 -080067 2.26.02.006 - Fix 9550SX pchip reset timeout.
68 Add big endian support.
adam radford1e08dcb2006-04-11 11:25:09 -070069 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic().
adam radford4039c302006-10-26 18:01:06 -070070 2.26.02.008 - Free irq handler in __twa_shutdown().
71 Serialize reset code.
72 Add support for 9650SE controllers.
adam radford0e78d152007-07-20 15:28:28 -070073 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
74 2.26.02.010 - Add support for 9690SA controllers.
adam radford3dabec72008-07-22 16:47:40 -070075 2.26.02.011 - Increase max AENs drained to 256.
76 Add MSI support and "use_msi" module parameter.
77 Fix bug in twa_get_param() on 4GB+.
78 Use pci_resource_len() for ioremap().
adam radford7a252fe2009-03-09 12:15:01 -080079 2.26.02.012 - Add power management support.
adam radford53ca3532009-12-10 11:53:31 -080080 2.26.02.013 - Fix bug in twa_load_sgl().
adam radford4deedd82010-03-08 12:37:46 -080081 2.26.02.014 - Force 60 second timeout default.
Linus Torvalds1da177e2005-04-16 15:20:36 -070082*/
83
84#include <linux/module.h>
85#include <linux/reboot.h>
86#include <linux/spinlock.h>
87#include <linux/interrupt.h>
88#include <linux/moduleparam.h>
89#include <linux/errno.h>
90#include <linux/types.h>
91#include <linux/delay.h>
92#include <linux/pci.h>
93#include <linux/time.h>
Jes Sorensena12e25bd2006-01-11 08:39:45 -050094#include <linux/mutex.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090095#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#include <asm/io.h>
97#include <asm/irq.h>
98#include <asm/uaccess.h>
99#include <scsi/scsi.h>
100#include <scsi/scsi_host.h>
101#include <scsi/scsi_tcq.h>
102#include <scsi/scsi_cmnd.h>
103#include "3w-9xxx.h"
104
105/* Globals */
adam radford4deedd82010-03-08 12:37:46 -0800106#define TW_DRIVER_VERSION "2.26.02.014"
Arnd Bergmannc45d15d2010-06-02 14:28:52 +0200107static DEFINE_MUTEX(twa_chrdev_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
109static unsigned int twa_device_extension_count;
110static int twa_major = -1;
111extern struct timezone sys_tz;
112
113/* Module parameters */
adam radford4deedd82010-03-08 12:37:46 -0800114MODULE_AUTHOR ("LSI");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
116MODULE_LICENSE("GPL");
117MODULE_VERSION(TW_DRIVER_VERSION);
118
adam radford3dabec72008-07-22 16:47:40 -0700119static int use_msi = 0;
120module_param(use_msi, int, S_IRUGO);
121MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0");
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/* Function prototypes */
124static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
125static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
126static char *twa_aen_severity_lookup(unsigned char severity_code);
127static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
Arnd Bergmannf4927c42010-04-27 00:24:01 +0200128static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129static int twa_chrdev_open(struct inode *inode, struct file *file);
130static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
131static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
132static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
133static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
134 u32 set_features, unsigned short current_fw_srl,
135 unsigned short current_fw_arch_id,
136 unsigned short current_fw_branch,
137 unsigned short current_fw_build,
138 unsigned short *fw_on_ctlr_srl,
139 unsigned short *fw_on_ctlr_arch_id,
140 unsigned short *fw_on_ctlr_branch,
141 unsigned short *fw_on_ctlr_build,
142 u32 *init_connect_result);
adam radford0e78d152007-07-20 15:28:28 -0700143static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
145static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
146static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
adam radford0e78d152007-07-20 15:28:28 -0700147static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
149static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
150static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
151static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153/* Functions */
154
155/* Show some statistics about the card */
Tony Jonesee959b02008-02-22 00:13:36 +0100156static ssize_t twa_show_stats(struct device *dev,
157 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
Tony Jonesee959b02008-02-22 00:13:36 +0100159 struct Scsi_Host *host = class_to_shost(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
161 unsigned long flags = 0;
162 ssize_t len;
163
164 spin_lock_irqsave(tw_dev->host->host_lock, flags);
165 len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
166 "Current commands posted: %4d\n"
167 "Max commands posted: %4d\n"
168 "Current pending commands: %4d\n"
169 "Max pending commands: %4d\n"
170 "Last sgl length: %4d\n"
171 "Max sgl length: %4d\n"
172 "Last sector count: %4d\n"
173 "Max sector count: %4d\n"
174 "SCSI Host Resets: %4d\n"
175 "AEN's: %4d\n",
176 TW_DRIVER_VERSION,
177 tw_dev->posted_request_count,
178 tw_dev->max_posted_request_count,
179 tw_dev->pending_request_count,
180 tw_dev->max_pending_request_count,
181 tw_dev->sgl_entries,
182 tw_dev->max_sgl_entries,
183 tw_dev->sector_count,
184 tw_dev->max_sector_count,
185 tw_dev->num_resets,
186 tw_dev->aen_count);
187 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
188 return len;
189} /* End twa_show_stats() */
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191/* Create sysfs 'stats' entry */
Tony Jonesee959b02008-02-22 00:13:36 +0100192static struct device_attribute twa_host_stats_attr = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 .attr = {
194 .name = "stats",
195 .mode = S_IRUGO,
196 },
197 .show = twa_show_stats
198};
199
200/* Host attributes initializer */
Tony Jonesee959b02008-02-22 00:13:36 +0100201static struct device_attribute *twa_host_attrs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 &twa_host_stats_attr,
203 NULL,
204};
205
206/* File operations struct for character device */
Arjan van de Ven00977a52007-02-12 00:55:34 -0800207static const struct file_operations twa_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 .owner = THIS_MODULE,
Arnd Bergmannf4927c42010-04-27 00:24:01 +0200209 .unlocked_ioctl = twa_chrdev_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 .open = twa_chrdev_open,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200211 .release = NULL,
212 .llseek = noop_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213};
214
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +0200215/*
216 * The controllers use an inline buffer instead of a mapped SGL for small,
217 * single entry buffers. Note that we treat a zero-length transfer like
218 * a mapped SGL.
219 */
220static bool twa_command_mapped(struct scsi_cmnd *cmd)
221{
222 return scsi_sg_count(cmd) != 1 ||
223 scsi_bufflen(cmd) >= TW_MIN_SGL_LENGTH;
224}
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226/* This function will complete an aen request from the isr */
227static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
228{
229 TW_Command_Full *full_command_packet;
230 TW_Command *command_packet;
231 TW_Command_Apache_Header *header;
232 unsigned short aen;
233 int retval = 1;
234
235 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
236 tw_dev->posted_request_count--;
adam radford75913d92006-03-15 12:43:19 -0800237 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 full_command_packet = tw_dev->command_packet_virt[request_id];
239 command_packet = &full_command_packet->command.oldcommand;
240
241 /* First check for internal completion of set param for time sync */
242 if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
243 /* Keep reading the queue in case there are more aen's */
244 if (twa_aen_read_queue(tw_dev, request_id))
245 goto out2;
246 else {
247 retval = 0;
248 goto out;
249 }
250 }
251
252 switch (aen) {
253 case TW_AEN_QUEUE_EMPTY:
254 /* Quit reading the queue if this is the last one */
255 break;
256 case TW_AEN_SYNC_TIME_WITH_HOST:
257 twa_aen_sync_time(tw_dev, request_id);
258 retval = 0;
259 goto out;
260 default:
261 twa_aen_queue_event(tw_dev, header);
262
263 /* If there are more aen's, keep reading the queue */
264 if (twa_aen_read_queue(tw_dev, request_id))
265 goto out2;
266 else {
267 retval = 0;
268 goto out;
269 }
270 }
271 retval = 0;
272out2:
273 tw_dev->state[request_id] = TW_S_COMPLETED;
274 twa_free_request_id(tw_dev, request_id);
275 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
276out:
277 return retval;
278} /* End twa_aen_complete() */
279
280/* This function will drain aen queue */
281static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
282{
283 int request_id = 0;
284 char cdb[TW_MAX_CDB_LEN];
285 TW_SG_Entry sglist[1];
286 int finished = 0, count = 0;
287 TW_Command_Full *full_command_packet;
288 TW_Command_Apache_Header *header;
289 unsigned short aen;
290 int first_reset = 0, queue = 0, retval = 1;
291
292 if (no_check_reset)
293 first_reset = 0;
294 else
295 first_reset = 1;
296
297 full_command_packet = tw_dev->command_packet_virt[request_id];
298 memset(full_command_packet, 0, sizeof(TW_Command_Full));
299
300 /* Initialize cdb */
301 memset(&cdb, 0, TW_MAX_CDB_LEN);
302 cdb[0] = REQUEST_SENSE; /* opcode */
303 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
304
305 /* Initialize sglist */
306 memset(&sglist, 0, sizeof(TW_SG_Entry));
307 sglist[0].length = TW_SECTOR_SIZE;
308 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
309
310 if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
311 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
312 goto out;
313 }
314
315 /* Mark internal command */
316 tw_dev->srb[request_id] = NULL;
317
318 do {
319 /* Send command to the board */
320 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
321 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
322 goto out;
323 }
324
325 /* Now poll for completion */
326 if (twa_poll_response(tw_dev, request_id, 30)) {
327 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
328 tw_dev->posted_request_count--;
329 goto out;
330 }
331
332 tw_dev->posted_request_count--;
333 header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
adam radford75913d92006-03-15 12:43:19 -0800334 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 queue = 0;
336 count++;
337
338 switch (aen) {
339 case TW_AEN_QUEUE_EMPTY:
340 if (first_reset != 1)
341 goto out;
342 else
343 finished = 1;
344 break;
345 case TW_AEN_SOFT_RESET:
346 if (first_reset == 0)
347 first_reset = 1;
348 else
349 queue = 1;
350 break;
351 case TW_AEN_SYNC_TIME_WITH_HOST:
352 break;
353 default:
354 queue = 1;
355 }
356
357 /* Now queue an event info */
358 if (queue)
359 twa_aen_queue_event(tw_dev, header);
360 } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
361
362 if (count == TW_MAX_AEN_DRAIN)
363 goto out;
364
365 retval = 0;
366out:
367 tw_dev->state[request_id] = TW_S_INITIAL;
368 return retval;
369} /* End twa_aen_drain_queue() */
370
371/* This function will queue an event */
372static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
373{
374 u32 local_time;
375 struct timeval time;
376 TW_Event *event;
377 unsigned short aen;
378 char host[16];
379 char *error_str;
380
381 tw_dev->aen_count++;
382
383 /* Fill out event info */
384 event = tw_dev->event_queue[tw_dev->error_index];
385
386 /* Check for clobber */
387 host[0] = '\0';
388 if (tw_dev->host) {
389 sprintf(host, " scsi%d:", tw_dev->host->host_no);
390 if (event->retrieved == TW_AEN_NOT_RETRIEVED)
391 tw_dev->aen_clobber = 1;
392 }
393
adam radford75913d92006-03-15 12:43:19 -0800394 aen = le16_to_cpu(header->status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 memset(event, 0, sizeof(TW_Event));
396
397 event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
398 do_gettimeofday(&time);
399 local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
400 event->time_stamp_sec = local_time;
401 event->aen_code = aen;
402 event->retrieved = TW_AEN_NOT_RETRIEVED;
403 event->sequence_id = tw_dev->error_sequence_id;
404 tw_dev->error_sequence_id++;
405
406 /* Check for embedded error string */
407 error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
408
409 header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
410 event->parameter_len = strlen(header->err_specific_desc);
adam radford75913d92006-03-15 12:43:19 -0800411 memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + (error_str[0] == '\0' ? 0 : (1 + strlen(error_str))));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (event->severity != TW_AEN_SEVERITY_DEBUG)
413 printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
414 host,
415 twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
416 TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
417 error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
418 header->err_specific_desc);
419 else
420 tw_dev->aen_count--;
421
422 if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
423 tw_dev->event_queue_wrapped = 1;
424 tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
425} /* End twa_aen_queue_event() */
426
427/* This function will read the aen queue from the isr */
428static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
429{
430 char cdb[TW_MAX_CDB_LEN];
431 TW_SG_Entry sglist[1];
432 TW_Command_Full *full_command_packet;
433 int retval = 1;
434
435 full_command_packet = tw_dev->command_packet_virt[request_id];
436 memset(full_command_packet, 0, sizeof(TW_Command_Full));
437
438 /* Initialize cdb */
439 memset(&cdb, 0, TW_MAX_CDB_LEN);
440 cdb[0] = REQUEST_SENSE; /* opcode */
441 cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
442
443 /* Initialize sglist */
444 memset(&sglist, 0, sizeof(TW_SG_Entry));
445 sglist[0].length = TW_SECTOR_SIZE;
446 sglist[0].address = tw_dev->generic_buffer_phys[request_id];
447
448 /* Mark internal command */
449 tw_dev->srb[request_id] = NULL;
450
451 /* Now post the command packet */
452 if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
453 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
454 goto out;
455 }
456 retval = 0;
457out:
458 return retval;
459} /* End twa_aen_read_queue() */
460
461/* This function will look up an AEN severity string */
462static char *twa_aen_severity_lookup(unsigned char severity_code)
463{
464 char *retval = NULL;
465
466 if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
467 (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
468 goto out;
469
470 retval = twa_aen_severity_table[severity_code];
471out:
472 return retval;
473} /* End twa_aen_severity_lookup() */
474
475/* This function will sync firmware time with the host time */
476static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
477{
478 u32 schedulertime;
479 struct timeval utc;
480 TW_Command_Full *full_command_packet;
481 TW_Command *command_packet;
482 TW_Param_Apache *param;
483 u32 local_time;
484
485 /* Fill out the command packet */
486 full_command_packet = tw_dev->command_packet_virt[request_id];
487 memset(full_command_packet, 0, sizeof(TW_Command_Full));
488 command_packet = &full_command_packet->command.oldcommand;
489 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
490 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -0800491 command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
492 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 command_packet->size = TW_COMMAND_SIZE;
adam radford75913d92006-03-15 12:43:19 -0800494 command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 /* Setup the param */
497 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
498 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -0800499 param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */
500 param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
501 param->parameter_size_bytes = cpu_to_le16(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 /* Convert system time in UTC to local time seconds since last
504 Sunday 12:00AM */
505 do_gettimeofday(&utc);
506 local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
507 schedulertime = local_time - (3 * 86400);
adam radford75913d92006-03-15 12:43:19 -0800508 schedulertime = cpu_to_le32(schedulertime % 604800);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 memcpy(param->data, &schedulertime, sizeof(u32));
511
512 /* Mark internal command */
513 tw_dev->srb[request_id] = NULL;
514
515 /* Now post the command */
516 twa_post_command_packet(tw_dev, request_id, 1);
517} /* End twa_aen_sync_time() */
518
519/* This function will allocate memory and check if it is correctly aligned */
520static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
521{
522 int i;
523 dma_addr_t dma_handle;
524 unsigned long *cpu_addr;
525 int retval = 1;
526
527 cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
528 if (!cpu_addr) {
529 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
530 goto out;
531 }
532
533 if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
534 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
535 pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
536 goto out;
537 }
538
539 memset(cpu_addr, 0, size*TW_Q_LENGTH);
540
541 for (i = 0; i < TW_Q_LENGTH; i++) {
542 switch(which) {
543 case 0:
544 tw_dev->command_packet_phys[i] = dma_handle+(i*size);
545 tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
546 break;
547 case 1:
548 tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
549 tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
550 break;
551 }
552 }
553 retval = 0;
554out:
555 return retval;
556} /* End twa_allocate_memory() */
557
558/* This function will check the status register for unexpected bits */
559static int twa_check_bits(u32 status_reg_value)
560{
561 int retval = 1;
562
563 if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
564 goto out;
565 if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
566 goto out;
567
568 retval = 0;
569out:
570 return retval;
571} /* End twa_check_bits() */
572
573/* This function will check the srl and decide if we are compatible */
574static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
575{
576 int retval = 1;
577 unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
578 unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
579 u32 init_connect_result = 0;
580
581 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
582 TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
583 TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
584 TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
585 &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
586 &fw_on_ctlr_build, &init_connect_result)) {
587 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
588 goto out;
589 }
590
adam radford4039c302006-10-26 18:01:06 -0700591 tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl;
592 tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch;
593 tw_dev->tw_compat_info.working_build = fw_on_ctlr_build;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 /* Try base mode compatibility */
596 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
597 if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
598 TW_EXTENDED_INIT_CONNECT,
599 TW_BASE_FW_SRL, TW_9000_ARCH_ID,
600 TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
601 &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
602 &fw_on_ctlr_branch, &fw_on_ctlr_build,
603 &init_connect_result)) {
604 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
605 goto out;
606 }
607 if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
608 if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
609 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
610 } else {
611 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
612 }
613 goto out;
614 }
adam radford4039c302006-10-26 18:01:06 -0700615 tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL;
616 tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH;
617 tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
adam radford4039c302006-10-26 18:01:06 -0700619
620 /* Load rest of compatibility struct */
Rickard Strandqvist2195d962014-07-27 17:11:18 +0200621 strlcpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION,
622 sizeof(tw_dev->tw_compat_info.driver_version));
adam radford4039c302006-10-26 18:01:06 -0700623 tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
624 tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
625 tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
626 tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
627 tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
628 tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
629 tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
630 tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
631 tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 retval = 0;
634out:
635 return retval;
636} /* End twa_check_srl() */
637
638/* This function handles ioctl for the character device */
Arnd Bergmannf4927c42010-04-27 00:24:01 +0200639static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Al Viro496ad9a2013-01-23 17:07:38 -0500641 struct inode *inode = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 long timeout;
643 unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
644 dma_addr_t dma_handle;
645 int request_id = 0;
646 unsigned int sequence_id = 0;
647 unsigned char event_index, start_index;
648 TW_Ioctl_Driver_Command driver_command;
649 TW_Ioctl_Buf_Apache *tw_ioctl;
650 TW_Lock *tw_lock;
651 TW_Command_Full *full_command_packet;
652 TW_Compatibility_Info *tw_compat_info;
653 TW_Event *event;
654 struct timeval current_time;
655 u32 current_time_ms;
656 TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
657 int retval = TW_IOCTL_ERROR_OS_EFAULT;
658 void __user *argp = (void __user *)arg;
659
Arnd Bergmannc45d15d2010-06-02 14:28:52 +0200660 mutex_lock(&twa_chrdev_mutex);
Arnd Bergmannf4927c42010-04-27 00:24:01 +0200661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 /* Only let one of these through at a time */
Jes Sorensena12e25bd2006-01-11 08:39:45 -0500663 if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 retval = TW_IOCTL_ERROR_OS_EINTR;
665 goto out;
666 }
667
668 /* First copy down the driver command */
669 if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
670 goto out2;
671
672 /* Check data buffer size */
adam radford4039c302006-10-26 18:01:06 -0700673 if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 retval = TW_IOCTL_ERROR_OS_EINVAL;
675 goto out2;
676 }
677
678 /* Hardware can only do multiple of 512 byte transfers */
679 data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
680
681 /* Now allocate ioctl buf memory */
682 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);
683 if (!cpu_addr) {
684 retval = TW_IOCTL_ERROR_OS_ENOMEM;
685 goto out2;
686 }
687
688 tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
689
690 /* Now copy down the entire ioctl */
691 if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
692 goto out3;
693
694 /* See which ioctl we are doing */
695 switch (cmd) {
696 case TW_IOCTL_FIRMWARE_PASS_THROUGH:
697 spin_lock_irqsave(tw_dev->host->host_lock, flags);
698 twa_get_request_id(tw_dev, &request_id);
699
700 /* Flag internal command */
701 tw_dev->srb[request_id] = NULL;
702
703 /* Flag chrdev ioctl */
704 tw_dev->chrdev_request_id = request_id;
705
706 full_command_packet = &tw_ioctl->firmware_command;
707
708 /* Load request id and sglist for both command types */
adam radford0e78d152007-07-20 15:28:28 -0700709 twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
712
713 /* Now post the command packet to the controller */
714 twa_post_command_packet(tw_dev, request_id, 1);
715 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
716
717 timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
718
719 /* Now wait for command to complete */
720 timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* We timed out, and didn't get an interrupt */
723 if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
724 /* Now we need to reset the board */
725 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 -0700726 tw_dev->host->host_no, TW_DRIVER, 0x37,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 cmd);
728 retval = TW_IOCTL_ERROR_OS_EIO;
adam radford0e78d152007-07-20 15:28:28 -0700729 twa_reset_device_extension(tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 goto out3;
731 }
732
733 /* Now copy in the command packet response */
734 memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
735
736 /* Now complete the io */
737 spin_lock_irqsave(tw_dev->host->host_lock, flags);
738 tw_dev->posted_request_count--;
739 tw_dev->state[request_id] = TW_S_COMPLETED;
740 twa_free_request_id(tw_dev, request_id);
741 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
742 break;
743 case TW_IOCTL_GET_COMPATIBILITY_INFO:
744 tw_ioctl->driver_command.status = 0;
Dirk Hohndel06fe9fb2009-09-28 21:43:57 -0400745 /* Copy compatibility struct into ioctl data buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
adam radford4039c302006-10-26 18:01:06 -0700747 memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 break;
749 case TW_IOCTL_GET_LAST_EVENT:
750 if (tw_dev->event_queue_wrapped) {
751 if (tw_dev->aen_clobber) {
752 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
753 tw_dev->aen_clobber = 0;
754 } else
755 tw_ioctl->driver_command.status = 0;
756 } else {
757 if (!tw_dev->error_index) {
758 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
759 break;
760 }
761 tw_ioctl->driver_command.status = 0;
762 }
763 event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
764 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
765 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
766 break;
767 case TW_IOCTL_GET_FIRST_EVENT:
768 if (tw_dev->event_queue_wrapped) {
769 if (tw_dev->aen_clobber) {
770 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
771 tw_dev->aen_clobber = 0;
772 } else
773 tw_ioctl->driver_command.status = 0;
774 event_index = tw_dev->error_index;
775 } else {
776 if (!tw_dev->error_index) {
777 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
778 break;
779 }
780 tw_ioctl->driver_command.status = 0;
781 event_index = 0;
782 }
783 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
784 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
785 break;
786 case TW_IOCTL_GET_NEXT_EVENT:
787 event = (TW_Event *)tw_ioctl->data_buffer;
788 sequence_id = event->sequence_id;
789 tw_ioctl->driver_command.status = 0;
790
791 if (tw_dev->event_queue_wrapped) {
792 if (tw_dev->aen_clobber) {
793 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
794 tw_dev->aen_clobber = 0;
795 }
796 start_index = tw_dev->error_index;
797 } else {
798 if (!tw_dev->error_index) {
799 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
800 break;
801 }
802 start_index = 0;
803 }
804 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
805
806 if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
807 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
808 tw_dev->aen_clobber = 1;
809 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
810 break;
811 }
812 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
813 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
814 break;
815 case TW_IOCTL_GET_PREVIOUS_EVENT:
816 event = (TW_Event *)tw_ioctl->data_buffer;
817 sequence_id = event->sequence_id;
818 tw_ioctl->driver_command.status = 0;
819
820 if (tw_dev->event_queue_wrapped) {
821 if (tw_dev->aen_clobber) {
822 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
823 tw_dev->aen_clobber = 0;
824 }
825 start_index = tw_dev->error_index;
826 } else {
827 if (!tw_dev->error_index) {
828 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
829 break;
830 }
831 start_index = 0;
832 }
833 event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
834
835 if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
836 if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
837 tw_dev->aen_clobber = 1;
838 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
839 break;
840 }
841 memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
842 tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
843 break;
844 case TW_IOCTL_GET_LOCK:
845 tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
846 do_gettimeofday(&current_time);
847 current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
848
849 if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
850 tw_dev->ioctl_sem_lock = 1;
851 tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
852 tw_ioctl->driver_command.status = 0;
853 tw_lock->time_remaining_msec = tw_lock->timeout_msec;
854 } else {
855 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
856 tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
857 }
858 break;
859 case TW_IOCTL_RELEASE_LOCK:
860 if (tw_dev->ioctl_sem_lock == 1) {
861 tw_dev->ioctl_sem_lock = 0;
862 tw_ioctl->driver_command.status = 0;
863 } else {
864 tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
865 }
866 break;
867 default:
868 retval = TW_IOCTL_ERROR_OS_ENOTTY;
869 goto out3;
870 }
871
872 /* Now copy the entire response to userspace */
873 if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
874 retval = 0;
875out3:
876 /* Now free ioctl buf memory */
877 dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
878out2:
Jes Sorensena12e25bd2006-01-11 08:39:45 -0500879 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880out:
Arnd Bergmannc45d15d2010-06-02 14:28:52 +0200881 mutex_unlock(&twa_chrdev_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return retval;
883} /* End twa_chrdev_ioctl() */
884
885/* This function handles open for the character device */
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600886/* NOTE that this function will race with remove. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887static int twa_chrdev_open(struct inode *inode, struct file *file)
888{
889 unsigned int minor_number;
890 int retval = TW_IOCTL_ERROR_OS_ENODEV;
891
Wenwen Wang80e75bd2018-05-07 19:46:43 -0500892 if (!capable(CAP_SYS_ADMIN)) {
893 retval = -EACCES;
894 goto out;
895 }
896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 minor_number = iminor(inode);
898 if (minor_number >= twa_device_extension_count)
899 goto out;
900 retval = 0;
901out:
902 return retval;
903} /* End twa_chrdev_open() */
904
905/* This function will print readable messages from status register errors */
906static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
907{
908 int retval = 1;
909
910 /* Check for various error conditions and handle them appropriately */
911 if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
912 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
913 writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
914 }
915
916 if (status_reg_value & TW_STATUS_PCI_ABORT) {
917 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
918 writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
919 pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
920 }
921
922 if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
adam radford0e78d152007-07-20 15:28:28 -0700923 if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
924 (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
925 (!test_bit(TW_IN_RESET, &tw_dev->flags)))
adam radford4039c302006-10-26 18:01:06 -0700926 TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
928 }
929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
931 if (tw_dev->reset_print == 0) {
932 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
933 tw_dev->reset_print = 1;
934 }
935 goto out;
936 }
937 retval = 0;
938out:
939 return retval;
940} /* End twa_decode_bits() */
941
942/* This function will empty the response queue */
943static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
944{
945 u32 status_reg_value, response_que_value;
946 int count = 0, retval = 1;
947
948 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
949
950 while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
951 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
952 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
953 count++;
954 }
955 if (count == TW_MAX_RESPONSE_DRAIN)
956 goto out;
957
958 retval = 0;
959out:
960 return retval;
961} /* End twa_empty_response_queue() */
962
adam radford49bfd8d2005-09-21 17:20:14 -0700963/* This function will clear the pchip/response queue on 9550SX */
964static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
965{
adam radford75913d92006-03-15 12:43:19 -0800966 u32 response_que_value = 0;
967 unsigned long before;
968 int retval = 1;
adam radford49bfd8d2005-09-21 17:20:14 -0700969
adam radford0e78d152007-07-20 15:28:28 -0700970 if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
adam radford75913d92006-03-15 12:43:19 -0800971 before = jiffies;
972 while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
adam radford49bfd8d2005-09-21 17:20:14 -0700973 response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
adam radford4039c302006-10-26 18:01:06 -0700974 msleep(1);
adam radford75913d92006-03-15 12:43:19 -0800975 if (time_after(jiffies, before + HZ * 30))
adam radford49bfd8d2005-09-21 17:20:14 -0700976 goto out;
adam radford49bfd8d2005-09-21 17:20:14 -0700977 }
adam radford75913d92006-03-15 12:43:19 -0800978 /* P-chip settle time */
979 msleep(500);
adam radford49bfd8d2005-09-21 17:20:14 -0700980 retval = 0;
981 } else
982 retval = 0;
983out:
984 return retval;
985} /* End twa_empty_response_queue_large() */
986
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987/* This function passes sense keys from firmware to scsi layer */
988static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
989{
990 TW_Command_Full *full_command_packet;
991 unsigned short error;
992 int retval = 1;
993 char *error_str;
994
995 full_command_packet = tw_dev->command_packet_virt[request_id];
996
997 /* Check for embedded error string */
998 error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
999
1000 /* Don't print error for Logical unit not supported during rollcall */
adam radford75913d92006-03-15 12:43:19 -08001001 error = le16_to_cpu(full_command_packet->header.status_block.error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
1003 if (print_host)
1004 printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
1005 tw_dev->host->host_no,
1006 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
1007 full_command_packet->header.status_block.error,
1008 error_str[0] == '\0' ?
1009 twa_string_lookup(twa_error_table,
1010 full_command_packet->header.status_block.error) : error_str,
1011 full_command_packet->header.err_specific_desc);
1012 else
1013 printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
1014 TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
1015 full_command_packet->header.status_block.error,
1016 error_str[0] == '\0' ?
1017 twa_string_lookup(twa_error_table,
1018 full_command_packet->header.status_block.error) : error_str,
1019 full_command_packet->header.err_specific_desc);
1020 }
1021
1022 if (copy_sense) {
1023 memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
1024 tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
1025 retval = TW_ISR_DONT_RESULT;
1026 goto out;
1027 }
1028 retval = 0;
1029out:
1030 return retval;
1031} /* End twa_fill_sense() */
1032
1033/* This function will free up device extension resources */
1034static void twa_free_device_extension(TW_Device_Extension *tw_dev)
1035{
1036 if (tw_dev->command_packet_virt[0])
1037 pci_free_consistent(tw_dev->tw_pci_dev,
1038 sizeof(TW_Command_Full)*TW_Q_LENGTH,
1039 tw_dev->command_packet_virt[0],
1040 tw_dev->command_packet_phys[0]);
1041
1042 if (tw_dev->generic_buffer_virt[0])
1043 pci_free_consistent(tw_dev->tw_pci_dev,
1044 TW_SECTOR_SIZE*TW_Q_LENGTH,
1045 tw_dev->generic_buffer_virt[0],
1046 tw_dev->generic_buffer_phys[0]);
1047
Jesper Juhlc9475cb2005-11-07 01:01:26 -08001048 kfree(tw_dev->event_queue[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049} /* End twa_free_device_extension() */
1050
1051/* This function will free a request id */
1052static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
1053{
1054 tw_dev->free_queue[tw_dev->free_tail] = request_id;
1055 tw_dev->state[request_id] = TW_S_FINISHED;
1056 tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
1057} /* End twa_free_request_id() */
1058
Alexey Dobriyan7f927fc2006-03-28 01:56:53 -08001059/* This function will get parameter table entries from the firmware */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
1061{
1062 TW_Command_Full *full_command_packet;
1063 TW_Command *command_packet;
1064 TW_Param_Apache *param;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 void *retval = NULL;
1066
1067 /* Setup the command packet */
1068 full_command_packet = tw_dev->command_packet_virt[request_id];
1069 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1070 command_packet = &full_command_packet->command.oldcommand;
1071
1072 command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
1073 command_packet->size = TW_COMMAND_SIZE;
1074 command_packet->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001075 command_packet->byte6_offset.block_count = cpu_to_le16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 /* Now setup the param */
1078 param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
1079 memset(param, 0, TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001080 param->table_id = cpu_to_le16(table_id | 0x8000);
1081 param->parameter_id = cpu_to_le16(parameter_id);
1082 param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
adam radford3dabec72008-07-22 16:47:40 -07001084 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 -08001085 command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
1087 /* Post the command packet to the board */
1088 twa_post_command_packet(tw_dev, request_id, 1);
1089
1090 /* Poll for completion */
1091 if (twa_poll_response(tw_dev, request_id, 30))
1092 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
1093 else
1094 retval = (void *)&(param->data[0]);
1095
1096 tw_dev->posted_request_count--;
1097 tw_dev->state[request_id] = TW_S_INITIAL;
1098
1099 return retval;
1100} /* End twa_get_param() */
1101
1102/* This function will assign an available request id */
1103static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
1104{
1105 *request_id = tw_dev->free_queue[tw_dev->free_head];
1106 tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
1107 tw_dev->state[*request_id] = TW_S_STARTED;
1108} /* End twa_get_request_id() */
1109
1110/* This function will send an initconnection command to controller */
1111static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
1112 u32 set_features, unsigned short current_fw_srl,
1113 unsigned short current_fw_arch_id,
1114 unsigned short current_fw_branch,
1115 unsigned short current_fw_build,
1116 unsigned short *fw_on_ctlr_srl,
1117 unsigned short *fw_on_ctlr_arch_id,
1118 unsigned short *fw_on_ctlr_branch,
1119 unsigned short *fw_on_ctlr_build,
1120 u32 *init_connect_result)
1121{
1122 TW_Command_Full *full_command_packet;
1123 TW_Initconnect *tw_initconnect;
1124 int request_id = 0, retval = 1;
1125
1126 /* Initialize InitConnection command packet */
1127 full_command_packet = tw_dev->command_packet_virt[request_id];
1128 memset(full_command_packet, 0, sizeof(TW_Command_Full));
1129 full_command_packet->header.header_desc.size_header = 128;
1130
1131 tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
1132 tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
1133 tw_initconnect->request_id = request_id;
adam radford75913d92006-03-15 12:43:19 -08001134 tw_initconnect->message_credits = cpu_to_le16(message_credits);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 tw_initconnect->features = set_features;
1136
1137 /* Turn on 64-bit sgl support if we need to */
1138 tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
1139
adam radford75913d92006-03-15 12:43:19 -08001140 tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
1141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 if (set_features & TW_EXTENDED_INIT_CONNECT) {
1143 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
adam radford75913d92006-03-15 12:43:19 -08001144 tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
1145 tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
1146 tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
1147 tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 } else
1149 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
1150
1151 /* Send command packet to the board */
1152 twa_post_command_packet(tw_dev, request_id, 1);
1153
1154 /* Poll for completion */
1155 if (twa_poll_response(tw_dev, request_id, 30)) {
1156 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
1157 } else {
1158 if (set_features & TW_EXTENDED_INIT_CONNECT) {
adam radford75913d92006-03-15 12:43:19 -08001159 *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
1160 *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
1161 *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
1162 *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
1163 *init_connect_result = le32_to_cpu(tw_initconnect->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
1165 retval = 0;
1166 }
1167
1168 tw_dev->posted_request_count--;
1169 tw_dev->state[request_id] = TW_S_INITIAL;
1170
1171 return retval;
1172} /* End twa_initconnection() */
1173
1174/* This function will initialize the fields of a device extension */
1175static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
1176{
1177 int i, retval = 1;
1178
1179 /* Initialize command packet buffers */
1180 if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
1181 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
1182 goto out;
1183 }
1184
1185 /* Initialize generic buffer */
1186 if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
1187 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
1188 goto out;
1189 }
1190
1191 /* Allocate event info space */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001192 tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 if (!tw_dev->event_queue[0]) {
1194 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
1195 goto out;
1196 }
1197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 for (i = 0; i < TW_Q_LENGTH; i++) {
1200 tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
1201 tw_dev->free_queue[i] = i;
1202 tw_dev->state[i] = TW_S_INITIAL;
1203 }
1204
1205 tw_dev->pending_head = TW_Q_START;
1206 tw_dev->pending_tail = TW_Q_START;
1207 tw_dev->free_head = TW_Q_START;
1208 tw_dev->free_tail = TW_Q_START;
1209 tw_dev->error_sequence_id = 1;
1210 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1211
Jes Sorensena12e25bd2006-01-11 08:39:45 -05001212 mutex_init(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 init_waitqueue_head(&tw_dev->ioctl_wqueue);
1214
1215 retval = 0;
1216out:
1217 return retval;
1218} /* End twa_initialize_device_extension() */
1219
1220/* This function is the interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +01001221static irqreturn_t twa_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
1223 int request_id, error = 0;
1224 u32 status_reg_value;
1225 TW_Response_Queue response_que;
1226 TW_Command_Full *full_command_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
1228 int handled = 0;
1229
1230 /* Get the per adapter lock */
1231 spin_lock(tw_dev->host->host_lock);
1232
1233 /* Read the registers */
1234 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1235
1236 /* Check if this is our interrupt, otherwise bail */
1237 if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
1238 goto twa_interrupt_bail;
1239
1240 handled = 1;
1241
adam radford4039c302006-10-26 18:01:06 -07001242 /* If we are resetting, bail */
1243 if (test_bit(TW_IN_RESET, &tw_dev->flags))
1244 goto twa_interrupt_bail;
1245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 /* Check controller for errors */
1247 if (twa_check_bits(status_reg_value)) {
1248 if (twa_decode_bits(tw_dev, status_reg_value)) {
1249 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1250 goto twa_interrupt_bail;
1251 }
1252 }
1253
1254 /* Handle host interrupt */
1255 if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
1256 TW_CLEAR_HOST_INTERRUPT(tw_dev);
1257
1258 /* Handle attention interrupt */
1259 if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
1260 TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
1261 if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
1262 twa_get_request_id(tw_dev, &request_id);
1263
1264 error = twa_aen_read_queue(tw_dev, request_id);
1265 if (error) {
1266 tw_dev->state[request_id] = TW_S_COMPLETED;
1267 twa_free_request_id(tw_dev, request_id);
1268 clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
1269 }
1270 }
1271 }
1272
1273 /* Handle command interrupt */
1274 if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
1275 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1276 /* Drain as many pending commands as we can */
1277 while (tw_dev->pending_request_count > 0) {
1278 request_id = tw_dev->pending_queue[tw_dev->pending_head];
1279 if (tw_dev->state[request_id] != TW_S_PENDING) {
1280 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
1281 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1282 goto twa_interrupt_bail;
1283 }
1284 if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
1285 tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
1286 tw_dev->pending_request_count--;
1287 } else {
1288 /* If we get here, we will continue re-posting on the next command interrupt */
1289 break;
1290 }
1291 }
1292 }
1293
1294 /* Handle response interrupt */
1295 if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
1296
1297 /* Drain the response queue from the board */
1298 while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
1299 /* Complete the response */
1300 response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1301 request_id = TW_RESID_OUT(response_que.response_id);
1302 full_command_packet = tw_dev->command_packet_virt[request_id];
1303 error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 /* Check for command packet errors */
1305 if (full_command_packet->command.newcommand.status != 0) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001306 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 error = twa_fill_sense(tw_dev, request_id, 1, 1);
1308 } else {
1309 /* Skip ioctl error prints */
1310 if (request_id != tw_dev->chrdev_request_id) {
1311 error = twa_fill_sense(tw_dev, request_id, 0, 1);
1312 }
1313 }
1314 }
1315
1316 /* Check for correct state */
1317 if (tw_dev->state[request_id] != TW_S_POSTED) {
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001318 if (tw_dev->srb[request_id] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
1320 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1321 goto twa_interrupt_bail;
1322 }
1323 }
1324
1325 /* Check for internal command completion */
Harvey Harrison9bcf0912008-05-22 15:45:07 -07001326 if (tw_dev->srb[request_id] == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (request_id != tw_dev->chrdev_request_id) {
1328 if (twa_aen_complete(tw_dev, request_id))
1329 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
1330 } else {
1331 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
1332 wake_up(&tw_dev->ioctl_wqueue);
1333 }
1334 } else {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001335 struct scsi_cmnd *cmd;
1336
1337 cmd = tw_dev->srb[request_id];
1338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 twa_scsiop_execute_scsi_complete(tw_dev, request_id);
1340 /* If no error command was a success */
1341 if (error == 0) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001342 cmd->result = (DID_OK << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 }
1344
1345 /* If error, command failed */
1346 if (error == 1) {
1347 /* Ask for a host reset */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001348 cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
1350
1351 /* Report residual bytes for single sgl */
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001352 if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
1353 if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
1354 scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 }
1356
1357 /* Now complete the io */
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +02001358 if (twa_command_mapped(cmd))
1359 scsi_dma_unmap(cmd);
Christoph Hellwig118c8552015-04-23 09:48:51 +02001360 cmd->scsi_done(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 tw_dev->state[request_id] = TW_S_COMPLETED;
1362 twa_free_request_id(tw_dev, request_id);
1363 tw_dev->posted_request_count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 }
1365
1366 /* Check for valid status after each drain */
1367 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1368 if (twa_check_bits(status_reg_value)) {
1369 if (twa_decode_bits(tw_dev, status_reg_value)) {
1370 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1371 goto twa_interrupt_bail;
1372 }
1373 }
1374 }
1375 }
1376
1377twa_interrupt_bail:
1378 spin_unlock(tw_dev->host->host_lock);
1379 return IRQ_RETVAL(handled);
1380} /* End twa_interrupt() */
1381
1382/* This function will load the request id and various sgls for ioctls */
adam radford0e78d152007-07-20 15:28:28 -07001383static 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 -07001384{
1385 TW_Command *oldcommand;
1386 TW_Command_Apache *newcommand;
1387 TW_SG_Entry *sgl;
adam radford0e78d152007-07-20 15:28:28 -07001388 unsigned int pae = 0;
1389
1390 if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
1391 pae = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1394 newcommand = &full_command_packet->command.newcommand;
adam radford4039c302006-10-26 18:01:06 -07001395 newcommand->request_id__lunl =
1396 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
adam radford53ca3532009-12-10 11:53:31 -08001397 if (length) {
1398 newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1399 newcommand->sg_list[0].length = cpu_to_le32(length);
1400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 newcommand->sgl_entries__lunh =
adam radford53ca3532009-12-10 11:53:31 -08001402 cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 } else {
1404 oldcommand = &full_command_packet->command.oldcommand;
1405 oldcommand->request_id = request_id;
1406
1407 if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
1408 /* Load the sg list */
adam radford0e78d152007-07-20 15:28:28 -07001409 if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
1410 sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
1411 else
1412 sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
adam radford75913d92006-03-15 12:43:19 -08001413 sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
1414 sgl->length = cpu_to_le32(length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
adam radford0e78d152007-07-20 15:28:28 -07001416 oldcommand->size += pae;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 }
1418 }
1419} /* End twa_load_sgl() */
1420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421/* This function will poll for a response interrupt of a request */
1422static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
1423{
1424 int retval = 1, found = 0, response_request_id;
1425 TW_Response_Queue response_queue;
1426 TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
1427
1428 if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
1429 response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
1430 response_request_id = TW_RESID_OUT(response_queue.response_id);
1431 if (request_id != response_request_id) {
1432 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
1433 goto out;
1434 }
1435 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
1436 if (full_command_packet->command.newcommand.status != 0) {
1437 /* bad response */
1438 twa_fill_sense(tw_dev, request_id, 0, 0);
1439 goto out;
1440 }
1441 found = 1;
1442 } else {
1443 if (full_command_packet->command.oldcommand.status != 0) {
1444 /* bad response */
1445 twa_fill_sense(tw_dev, request_id, 0, 0);
1446 goto out;
1447 }
1448 found = 1;
1449 }
1450 }
1451
1452 if (found)
1453 retval = 0;
1454out:
1455 return retval;
1456} /* End twa_poll_response() */
1457
1458/* This function will poll the status register for a flag */
1459static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1460{
1461 u32 status_reg_value;
1462 unsigned long before;
1463 int retval = 1;
1464
1465 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1466 before = jiffies;
1467
1468 if (twa_check_bits(status_reg_value))
1469 twa_decode_bits(tw_dev, status_reg_value);
1470
1471 while ((status_reg_value & flag) != flag) {
1472 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1473
1474 if (twa_check_bits(status_reg_value))
1475 twa_decode_bits(tw_dev, status_reg_value);
1476
1477 if (time_after(jiffies, before + HZ * seconds))
1478 goto out;
1479
1480 msleep(50);
1481 }
1482 retval = 0;
1483out:
1484 return retval;
1485} /* End twa_poll_status() */
1486
1487/* This function will poll the status register for disappearance of a flag */
1488static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
1489{
1490 u32 status_reg_value;
1491 unsigned long before;
1492 int retval = 1;
1493
1494 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1495 before = jiffies;
1496
1497 if (twa_check_bits(status_reg_value))
1498 twa_decode_bits(tw_dev, status_reg_value);
1499
1500 while ((status_reg_value & flag) != 0) {
1501 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1502 if (twa_check_bits(status_reg_value))
1503 twa_decode_bits(tw_dev, status_reg_value);
1504
1505 if (time_after(jiffies, before + HZ * seconds))
1506 goto out;
1507
1508 msleep(50);
1509 }
1510 retval = 0;
1511out:
1512 return retval;
1513} /* End twa_poll_status_gone() */
1514
1515/* This function will attempt to post a command packet to the board */
1516static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
1517{
1518 u32 status_reg_value;
1519 dma_addr_t command_que_value;
1520 int retval = 1;
1521
1522 command_que_value = tw_dev->command_packet_phys[request_id];
adam radford4039c302006-10-26 18:01:06 -07001523
1524 /* For 9650SE write low 4 bytes first */
adam radford0e78d152007-07-20 15:28:28 -07001525 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1526 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001527 command_que_value += TW_COMMAND_OFFSET;
1528 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
1529 }
1530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
1532
1533 if (twa_check_bits(status_reg_value))
1534 twa_decode_bits(tw_dev, status_reg_value);
1535
1536 if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
1537
1538 /* Only pend internal driver commands */
1539 if (!internal) {
1540 retval = SCSI_MLQUEUE_HOST_BUSY;
1541 goto out;
1542 }
1543
1544 /* Couldn't post the command packet, so we do it later */
1545 if (tw_dev->state[request_id] != TW_S_PENDING) {
1546 tw_dev->state[request_id] = TW_S_PENDING;
1547 tw_dev->pending_request_count++;
1548 if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
1549 tw_dev->max_pending_request_count = tw_dev->pending_request_count;
1550 }
1551 tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
1552 tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
1553 }
1554 TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
1555 goto out;
1556 } else {
adam radford0e78d152007-07-20 15:28:28 -07001557 if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
1558 (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
adam radford4039c302006-10-26 18:01:06 -07001559 /* Now write upper 4 bytes */
1560 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 } else {
adam radford4039c302006-10-26 18:01:06 -07001562 if (sizeof(dma_addr_t) > 4) {
1563 command_que_value += TW_COMMAND_OFFSET;
1564 writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1565 writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
1566 } else {
1567 writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 }
1570 tw_dev->state[request_id] = TW_S_POSTED;
1571 tw_dev->posted_request_count++;
1572 if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
1573 tw_dev->max_posted_request_count = tw_dev->posted_request_count;
1574 }
1575 }
1576 retval = 0;
1577out:
1578 return retval;
1579} /* End twa_post_command_packet() */
1580
1581/* This function will reset a device extension */
adam radford0e78d152007-07-20 15:28:28 -07001582static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583{
1584 int i = 0;
1585 int retval = 1;
1586 unsigned long flags = 0;
1587
1588 set_bit(TW_IN_RESET, &tw_dev->flags);
1589 TW_DISABLE_INTERRUPTS(tw_dev);
1590 TW_MASK_COMMAND_INTERRUPT(tw_dev);
1591 spin_lock_irqsave(tw_dev->host->host_lock, flags);
1592
1593 /* Abort all requests that are in progress */
1594 for (i = 0; i < TW_Q_LENGTH; i++) {
1595 if ((tw_dev->state[i] != TW_S_FINISHED) &&
1596 (tw_dev->state[i] != TW_S_INITIAL) &&
1597 (tw_dev->state[i] != TW_S_COMPLETED)) {
1598 if (tw_dev->srb[i]) {
Christoph Hellwig118c8552015-04-23 09:48:51 +02001599 struct scsi_cmnd *cmd = tw_dev->srb[i];
1600
1601 cmd->result = (DID_RESET << 16);
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +02001602 if (twa_command_mapped(cmd))
1603 scsi_dma_unmap(cmd);
Christoph Hellwig118c8552015-04-23 09:48:51 +02001604 cmd->scsi_done(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 }
1606 }
1607 }
1608
1609 /* Reset queues and counts */
1610 for (i = 0; i < TW_Q_LENGTH; i++) {
1611 tw_dev->free_queue[i] = i;
1612 tw_dev->state[i] = TW_S_INITIAL;
1613 }
1614 tw_dev->free_head = TW_Q_START;
1615 tw_dev->free_tail = TW_Q_START;
1616 tw_dev->posted_request_count = 0;
1617 tw_dev->pending_request_count = 0;
1618 tw_dev->pending_head = TW_Q_START;
1619 tw_dev->pending_tail = TW_Q_START;
1620 tw_dev->reset_print = 0;
1621
1622 spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
1623
1624 if (twa_reset_sequence(tw_dev, 1))
1625 goto out;
1626
1627 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
adam radford4039c302006-10-26 18:01:06 -07001628 clear_bit(TW_IN_RESET, &tw_dev->flags);
1629 tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 retval = 0;
1632out:
1633 return retval;
1634} /* End twa_reset_device_extension() */
1635
1636/* This function will reset a controller */
1637static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
1638{
1639 int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
1640
1641 while (tries < TW_MAX_RESET_TRIES) {
adam radford49bfd8d2005-09-21 17:20:14 -07001642 if (do_soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 TW_SOFT_RESET(tw_dev);
adam radford49bfd8d2005-09-21 17:20:14 -07001644 /* Clear pchip/response queue on 9550SX */
1645 if (twa_empty_response_queue_large(tw_dev)) {
1646 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence");
1647 do_soft_reset = 1;
1648 tries++;
1649 continue;
1650 }
1651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
1653 /* Make sure controller is in a good state */
1654 if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
1655 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
1656 do_soft_reset = 1;
1657 tries++;
1658 continue;
1659 }
1660
1661 /* Empty response queue */
1662 if (twa_empty_response_queue(tw_dev)) {
1663 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
1664 do_soft_reset = 1;
1665 tries++;
1666 continue;
1667 }
1668
1669 flashed = 0;
1670
1671 /* Check for compatibility/flash */
1672 if (twa_check_srl(tw_dev, &flashed)) {
1673 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
1674 do_soft_reset = 1;
1675 tries++;
1676 continue;
1677 } else {
1678 if (flashed) {
1679 tries++;
1680 continue;
1681 }
1682 }
1683
1684 /* Drain the AEN queue */
1685 if (twa_aen_drain_queue(tw_dev, soft_reset)) {
1686 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
1687 do_soft_reset = 1;
1688 tries++;
1689 continue;
1690 }
1691
1692 /* If we got here, controller is in a good state */
1693 retval = 0;
1694 goto out;
1695 }
1696out:
1697 return retval;
1698} /* End twa_reset_sequence() */
1699
1700/* This funciton returns unit geometry in cylinders/heads/sectors */
1701static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
1702{
1703 int heads, sectors, cylinders;
1704 TW_Device_Extension *tw_dev;
1705
1706 tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
1707
1708 if (capacity >= 0x200000) {
1709 heads = 255;
1710 sectors = 63;
1711 cylinders = sector_div(capacity, heads * sectors);
1712 } else {
1713 heads = 64;
1714 sectors = 32;
1715 cylinders = sector_div(capacity, heads * sectors);
1716 }
1717
1718 geom[0] = heads;
1719 geom[1] = sectors;
1720 geom[2] = cylinders;
1721
1722 return 0;
1723} /* End twa_scsi_biosparam() */
1724
1725/* This is the new scsi eh reset function */
1726static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
1727{
1728 TW_Device_Extension *tw_dev = NULL;
1729 int retval = FAILED;
1730
1731 tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 tw_dev->num_resets++;
1734
Jeff Garzik017560f2005-10-24 18:04:36 -04001735 sdev_printk(KERN_WARNING, SCpnt->device,
1736 "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
1737 TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
adam radford4039c302006-10-26 18:01:06 -07001739 /* Make sure we are not issuing an ioctl or resetting from ioctl */
1740 mutex_lock(&tw_dev->ioctl_lock);
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 /* Now reset the card and some of the device extension data */
adam radford0e78d152007-07-20 15:28:28 -07001743 if (twa_reset_device_extension(tw_dev)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
1745 goto out;
1746 }
1747
1748 retval = SUCCESS;
1749out:
adam radford4039c302006-10-26 18:01:06 -07001750 mutex_unlock(&tw_dev->ioctl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 return retval;
1752} /* End twa_scsi_eh_reset() */
1753
1754/* This is the main scsi queue function to handle scsi opcodes */
Jeff Garzikf2812332010-11-16 02:10:29 -05001755static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
1757 int request_id, retval;
1758 TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
1759
adam radford4039c302006-10-26 18:01:06 -07001760 /* If we are resetting due to timed out ioctl, report as busy */
1761 if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
1762 retval = SCSI_MLQUEUE_HOST_BUSY;
1763 goto out;
1764 }
1765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 /* Check if this FW supports luns */
adam radford4039c302006-10-26 18:01:06 -07001767 if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 SCpnt->result = (DID_BAD_TARGET << 16);
1769 done(SCpnt);
1770 retval = 0;
1771 goto out;
1772 }
1773
1774 /* Save done function into scsi_cmnd struct */
1775 SCpnt->scsi_done = done;
1776
1777 /* Get a free request id */
1778 twa_get_request_id(tw_dev, &request_id);
1779
1780 /* Save the scsi command for use by the ISR */
1781 tw_dev->srb[request_id] = SCpnt;
1782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
1784 switch (retval) {
1785 case SCSI_MLQUEUE_HOST_BUSY:
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +02001786 if (twa_command_mapped(SCpnt))
1787 scsi_dma_unmap(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 twa_free_request_id(tw_dev, request_id);
1789 break;
1790 case 1:
Christoph Hellwig118c8552015-04-23 09:48:51 +02001791 SCpnt->result = (DID_ERROR << 16);
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +02001792 if (twa_command_mapped(SCpnt))
1793 scsi_dma_unmap(SCpnt);
Christoph Hellwig118c8552015-04-23 09:48:51 +02001794 done(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 tw_dev->state[request_id] = TW_S_COMPLETED;
1796 twa_free_request_id(tw_dev, request_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 retval = 0;
1798 }
1799out:
1800 return retval;
1801} /* End twa_scsi_queue() */
1802
Jeff Garzikf2812332010-11-16 02:10:29 -05001803static DEF_SCSI_QCMD(twa_scsi_queue)
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805/* This function hands scsi cdb's to the firmware */
1806static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
1807{
1808 TW_Command_Full *full_command_packet;
1809 TW_Command_Apache *command_packet;
1810 u32 num_sectors = 0x0;
1811 int i, sg_count;
1812 struct scsi_cmnd *srb = NULL;
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001813 struct scatterlist *sglist = NULL, *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 int retval = 1;
1815
1816 if (tw_dev->srb[request_id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 srb = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001818 if (scsi_sglist(srb))
1819 sglist = scsi_sglist(srb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 }
1821
1822 /* Initialize command packet */
1823 full_command_packet = tw_dev->command_packet_virt[request_id];
1824 full_command_packet->header.header_desc.size_header = 128;
1825 full_command_packet->header.status_block.error = 0;
1826 full_command_packet->header.status_block.severity__reserved = 0;
1827
1828 command_packet = &full_command_packet->command.newcommand;
1829 command_packet->status = 0;
1830 command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
1831
1832 /* We forced 16 byte cdb use earlier */
1833 if (!cdb)
1834 memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
1835 else
1836 memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
1837
1838 if (srb) {
1839 command_packet->unit = srb->device->id;
1840 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001841 cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 } else {
1843 command_packet->request_id__lunl =
adam radford75913d92006-03-15 12:43:19 -08001844 cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 command_packet->unit = 0;
1846 }
1847
1848 command_packet->sgl_offset = 16;
1849
1850 if (!sglistarg) {
1851 /* Map sglist from scsi layer to cmd packet */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001853 if (scsi_sg_count(srb)) {
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +02001854 if (!twa_command_mapped(srb)) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001855 if (srb->sc_data_direction == DMA_TO_DEVICE ||
1856 srb->sc_data_direction == DMA_BIDIRECTIONAL)
1857 scsi_sg_copy_to_buffer(srb,
1858 tw_dev->generic_buffer_virt[request_id],
1859 TW_SECTOR_SIZE);
adam radford75913d92006-03-15 12:43:19 -08001860 command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
1861 command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 } else {
Christoph Hellwig118c8552015-04-23 09:48:51 +02001863 sg_count = scsi_dma_map(srb);
1864 if (sg_count < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 goto out;
1866
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001867 scsi_for_each_sg(srb, sg, sg_count, i) {
1868 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
1869 command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
adam radford75913d92006-03-15 12:43:19 -08001870 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
1872 goto out;
1873 }
1874 }
1875 }
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001876 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 -07001877 }
1878 } else {
1879 /* Internal cdb post */
1880 for (i = 0; i < use_sg; i++) {
adam radford75913d92006-03-15 12:43:19 -08001881 command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
1882 command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length);
1883 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
1885 goto out;
1886 }
1887 }
adam radford75913d92006-03-15 12:43:19 -08001888 command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
1890
1891 if (srb) {
1892 if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
1893 num_sectors = (u32)srb->cmnd[4];
1894
1895 if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
1896 num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
1897 }
1898
1899 /* Update sector statistic */
1900 tw_dev->sector_count = num_sectors;
1901 if (tw_dev->sector_count > tw_dev->max_sector_count)
1902 tw_dev->max_sector_count = tw_dev->sector_count;
1903
1904 /* Update SG statistics */
1905 if (srb) {
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001906 tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
1908 tw_dev->max_sgl_entries = tw_dev->sgl_entries;
1909 }
1910
1911 /* Now post the command to the board */
1912 if (srb) {
1913 retval = twa_post_command_packet(tw_dev, request_id, 0);
1914 } else {
1915 twa_post_command_packet(tw_dev, request_id, 1);
1916 retval = 0;
1917 }
1918out:
1919 return retval;
1920} /* End twa_scsiop_execute_scsi() */
1921
1922/* This function completes an execute scsi operation */
1923static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
1924{
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001925 struct scsi_cmnd *cmd = tw_dev->srb[request_id];
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001926
Christoph Hellwig15e3d5a2015-10-03 19:16:07 +02001927 if (!twa_command_mapped(cmd) &&
FUJITA Tomonori0debe012007-05-26 02:33:31 +09001928 (cmd->sc_data_direction == DMA_FROM_DEVICE ||
1929 cmd->sc_data_direction == DMA_BIDIRECTIONAL)) {
FUJITA Tomonorib1192d52007-05-31 15:24:03 +09001930 if (scsi_sg_count(cmd) == 1) {
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001931 void *buf = tw_dev->generic_buffer_virt[request_id];
1932
FUJITA Tomonori035f5e02008-03-09 13:44:37 +09001933 scsi_sg_copy_from_buffer(cmd, buf, TW_SECTOR_SIZE);
adam radfordd327d082005-09-09 15:55:13 -07001934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 }
1936} /* End twa_scsiop_execute_scsi_complete() */
1937
1938/* This function tells the controller to shut down */
1939static void __twa_shutdown(TW_Device_Extension *tw_dev)
1940{
1941 /* Disable interrupts */
1942 TW_DISABLE_INTERRUPTS(tw_dev);
1943
adam radford4039c302006-10-26 18:01:06 -07001944 /* Free up the IRQ */
1945 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
1946
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
1948
1949 /* Tell the card we are shutting down */
1950 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
1951 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
1952 } else {
1953 printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
1954 }
1955
1956 /* Clear all interrupts just before exit */
1957 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
1958} /* End __twa_shutdown() */
1959
1960/* Wrapper for __twa_shutdown */
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001961static void twa_shutdown(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962{
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001963 struct Scsi_Host *host = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
1965
1966 __twa_shutdown(tw_dev);
1967} /* End twa_shutdown() */
1968
1969/* This function will look up a string */
1970static char *twa_string_lookup(twa_message_type *table, unsigned int code)
1971{
1972 int index;
1973
1974 for (index = 0; ((code != table[index].code) &&
1975 (table[index].text != (char *)0)); index++);
1976 return(table[index].text);
1977} /* End twa_string_lookup() */
1978
adam radford4deedd82010-03-08 12:37:46 -08001979/* This function gets called when a disk is coming on-line */
1980static int twa_slave_configure(struct scsi_device *sdev)
1981{
1982 /* Force 60 second timeout */
1983 blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
1984
1985 return 0;
1986} /* End twa_slave_configure() */
1987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988/* scsi_host_template initializer */
1989static struct scsi_host_template driver_template = {
1990 .module = THIS_MODULE,
1991 .name = "3ware 9000 Storage Controller",
1992 .queuecommand = twa_scsi_queue,
1993 .eh_host_reset_handler = twa_scsi_eh_reset,
1994 .bios_param = twa_scsi_biosparam,
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01001995 .change_queue_depth = scsi_change_queue_depth,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 .can_queue = TW_Q_LENGTH-2,
adam radford4deedd82010-03-08 12:37:46 -08001997 .slave_configure = twa_slave_configure,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 .this_id = -1,
1999 .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH,
2000 .max_sectors = TW_MAX_SECTORS,
2001 .cmd_per_lun = TW_MAX_CMDS_PER_LUN,
2002 .use_clustering = ENABLE_CLUSTERING,
2003 .shost_attrs = twa_host_attrs,
Martin K. Petersen54b2b502013-10-23 06:25:40 -04002004 .emulated = 1,
2005 .no_write_same = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006};
2007
2008/* This function will probe and initialize a card */
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -08002009static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{
2011 struct Scsi_Host *host = NULL;
2012 TW_Device_Extension *tw_dev;
adam radford3dabec72008-07-22 16:47:40 -07002013 unsigned long mem_addr, mem_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 int retval = -ENODEV;
2015
2016 retval = pci_enable_device(pdev);
2017 if (retval) {
2018 TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
2019 goto out_disable_device;
2020 }
2021
2022 pci_set_master(pdev);
Tony Battersby1e6c38c2007-11-09 13:04:35 -05002023 pci_try_set_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Yang Hongyang6a355282009-04-06 19:01:13 -07002025 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2026 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
Yang Hongyang284901a2009-04-06 19:01:15 -07002027 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2028 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford0e78d152007-07-20 15:28:28 -07002029 TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
2030 retval = -ENODEV;
2031 goto out_disable_device;
2032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033
2034 host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
2035 if (!host) {
2036 TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
2037 retval = -ENOMEM;
2038 goto out_disable_device;
2039 }
2040 tw_dev = (TW_Device_Extension *)host->hostdata;
2041
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 /* Save values to device extension */
2043 tw_dev->host = host;
2044 tw_dev->tw_pci_dev = pdev;
2045
2046 if (twa_initialize_device_extension(tw_dev)) {
2047 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
Anton Vasilyev5563a932018-07-27 16:51:57 +03002048 retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 goto out_free_device_extension;
2050 }
2051
2052 /* Request IO regions */
2053 retval = pci_request_regions(pdev, "3w-9xxx");
2054 if (retval) {
2055 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
2056 goto out_free_device_extension;
2057 }
2058
adam radford3dabec72008-07-22 16:47:40 -07002059 if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
adam radford49bfd8d2005-09-21 17:20:14 -07002060 mem_addr = pci_resource_start(pdev, 1);
adam radford3dabec72008-07-22 16:47:40 -07002061 mem_len = pci_resource_len(pdev, 1);
2062 } else {
adam radford49bfd8d2005-09-21 17:20:14 -07002063 mem_addr = pci_resource_start(pdev, 2);
adam radford3dabec72008-07-22 16:47:40 -07002064 mem_len = pci_resource_len(pdev, 2);
2065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
2067 /* Save base address */
adam radford3dabec72008-07-22 16:47:40 -07002068 tw_dev->base_addr = ioremap(mem_addr, mem_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if (!tw_dev->base_addr) {
2070 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
Anton Vasilyev5563a932018-07-27 16:51:57 +03002071 retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 goto out_release_mem_region;
2073 }
2074
2075 /* Disable interrupts on the card */
2076 TW_DISABLE_INTERRUPTS(tw_dev);
2077
2078 /* Initialize the card */
Anton Vasilyev5563a932018-07-27 16:51:57 +03002079 if (twa_reset_sequence(tw_dev, 0)) {
2080 retval = -ENOMEM;
adam radford4039c302006-10-26 18:01:06 -07002081 goto out_iounmap;
Anton Vasilyev5563a932018-07-27 16:51:57 +03002082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 /* Set host specific parameters */
adam radford0e78d152007-07-20 15:28:28 -07002085 if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
2086 (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
adam radford4039c302006-10-26 18:01:06 -07002087 host->max_id = TW_MAX_UNITS_9650SE;
2088 else
2089 host->max_id = TW_MAX_UNITS;
2090
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 host->max_cmd_len = TW_MAX_CDB_LEN;
2092
2093 /* Channels aren't supported by adapter */
adam radford4039c302006-10-26 18:01:06 -07002094 host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 host->max_channel = 0;
2096
2097 /* Register the card with the kernel SCSI layer */
2098 retval = scsi_add_host(host, &pdev->dev);
2099 if (retval) {
2100 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
adam radford4039c302006-10-26 18:01:06 -07002101 goto out_iounmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 }
2103
2104 pci_set_drvdata(pdev, host);
2105
adam radford3dabec72008-07-22 16:47:40 -07002106 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 -07002107 host->host_no, mem_addr, pdev->irq);
2108 printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
2109 host->host_no,
2110 (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
2111 TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
2112 (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
2113 TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
adam radford75913d92006-03-15 12:43:19 -08002114 le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
2115 TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116
adam radford3dabec72008-07-22 16:47:40 -07002117 /* Try to enable MSI */
2118 if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
2119 !pci_enable_msi(pdev))
2120 set_bit(TW_USING_MSI, &tw_dev->flags);
2121
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 /* Now setup the interrupt handler */
Thomas Gleixner1d6f3592006-07-01 19:29:42 -07002123 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 if (retval) {
2125 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
2126 goto out_remove_host;
2127 }
2128
2129 twa_device_extension_list[twa_device_extension_count] = tw_dev;
2130 twa_device_extension_count++;
2131
2132 /* Re-enable interrupts on the card */
2133 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2134
2135 /* Finally, scan the host */
2136 scsi_scan_host(host);
2137
2138 if (twa_major == -1) {
2139 if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
2140 TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
2141 }
2142 return 0;
2143
2144out_remove_host:
adam radford3dabec72008-07-22 16:47:40 -07002145 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2146 pci_disable_msi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 scsi_remove_host(host);
adam radford4039c302006-10-26 18:01:06 -07002148out_iounmap:
2149 iounmap(tw_dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150out_release_mem_region:
2151 pci_release_regions(pdev);
2152out_free_device_extension:
2153 twa_free_device_extension(tw_dev);
2154 scsi_host_put(host);
2155out_disable_device:
2156 pci_disable_device(pdev);
2157
2158 return retval;
2159} /* End twa_probe() */
2160
2161/* This function is called to remove a device */
2162static void twa_remove(struct pci_dev *pdev)
2163{
2164 struct Scsi_Host *host = pci_get_drvdata(pdev);
2165 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2166
2167 scsi_remove_host(tw_dev->host);
2168
2169 /* Unregister character device */
2170 if (twa_major >= 0) {
2171 unregister_chrdev(twa_major, "twa");
2172 twa_major = -1;
2173 }
2174
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 /* Shutdown the card */
2176 __twa_shutdown(tw_dev);
2177
adam radford3dabec72008-07-22 16:47:40 -07002178 /* Disable MSI if enabled */
2179 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2180 pci_disable_msi(pdev);
2181
adam radford4039c302006-10-26 18:01:06 -07002182 /* Free IO remapping */
2183 iounmap(tw_dev->base_addr);
2184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 /* Free up the mem region */
2186 pci_release_regions(pdev);
2187
2188 /* Free up device extension resources */
2189 twa_free_device_extension(tw_dev);
2190
2191 scsi_host_put(tw_dev->host);
2192 pci_disable_device(pdev);
2193 twa_device_extension_count--;
2194} /* End twa_remove() */
2195
adam radford7a252fe2009-03-09 12:15:01 -08002196#ifdef CONFIG_PM
2197/* This function is called on PCI suspend */
2198static int twa_suspend(struct pci_dev *pdev, pm_message_t state)
2199{
2200 struct Scsi_Host *host = pci_get_drvdata(pdev);
2201 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2202
2203 printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no);
2204
2205 TW_DISABLE_INTERRUPTS(tw_dev);
2206 free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
2207
2208 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2209 pci_disable_msi(pdev);
2210
2211 /* Tell the card we are shutting down */
2212 if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
2213 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend");
2214 } else {
2215 printk(KERN_WARNING "3w-9xxx: Suspend complete.\n");
2216 }
2217 TW_CLEAR_ALL_INTERRUPTS(tw_dev);
2218
2219 pci_save_state(pdev);
2220 pci_disable_device(pdev);
2221 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2222
2223 return 0;
2224} /* End twa_suspend() */
2225
2226/* This function is called on PCI resume */
2227static int twa_resume(struct pci_dev *pdev)
2228{
2229 int retval = 0;
2230 struct Scsi_Host *host = pci_get_drvdata(pdev);
2231 TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
2232
2233 printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no);
2234 pci_set_power_state(pdev, PCI_D0);
2235 pci_enable_wake(pdev, PCI_D0, 0);
2236 pci_restore_state(pdev);
2237
2238 retval = pci_enable_device(pdev);
2239 if (retval) {
2240 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume");
2241 return retval;
2242 }
2243
2244 pci_set_master(pdev);
2245 pci_try_set_mwi(pdev);
2246
Yang Hongyange9304382009-04-13 14:40:14 -07002247 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
2248 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
2249 if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
2250 || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
adam radford7a252fe2009-03-09 12:15:01 -08002251 TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume");
2252 retval = -ENODEV;
2253 goto out_disable_device;
2254 }
2255
2256 /* Initialize the card */
2257 if (twa_reset_sequence(tw_dev, 0)) {
2258 retval = -ENODEV;
2259 goto out_disable_device;
2260 }
2261
2262 /* Now setup the interrupt handler */
2263 retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
2264 if (retval) {
2265 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume");
2266 retval = -ENODEV;
2267 goto out_disable_device;
2268 }
2269
2270 /* Now enable MSI if enabled */
2271 if (test_bit(TW_USING_MSI, &tw_dev->flags))
2272 pci_enable_msi(pdev);
2273
2274 /* Re-enable interrupts on the card */
2275 TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
2276
2277 printk(KERN_WARNING "3w-9xxx: Resume complete.\n");
2278 return 0;
2279
2280out_disable_device:
2281 scsi_remove_host(host);
2282 pci_disable_device(pdev);
2283
2284 return retval;
2285} /* End twa_resume() */
2286#endif
2287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288/* PCI Devices supported by this driver */
Greg Kroah-Hartman6f039792012-12-21 13:08:55 -08002289static struct pci_device_id twa_pci_tbl[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
2291 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford49bfd8d2005-09-21 17:20:14 -07002292 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
2293 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford4039c302006-10-26 18:01:06 -07002294 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
2295 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
adam radford0e78d152007-07-20 15:28:28 -07002296 { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
2297 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 { }
2299};
2300MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
2301
2302/* pci_driver initializer */
2303static struct pci_driver twa_driver = {
2304 .name = "3w-9xxx",
2305 .id_table = twa_pci_tbl,
2306 .probe = twa_probe,
2307 .remove = twa_remove,
adam radford7a252fe2009-03-09 12:15:01 -08002308#ifdef CONFIG_PM
2309 .suspend = twa_suspend,
2310 .resume = twa_resume,
2311#endif
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07002312 .shutdown = twa_shutdown
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313};
2314
2315/* This function is called on driver initialization */
2316static int __init twa_init(void)
2317{
2318 printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
2319
Henrik Kretzschmardcbccbde2006-09-25 16:58:58 -07002320 return pci_register_driver(&twa_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321} /* End twa_init() */
2322
2323/* This function is called on driver exit */
2324static void __exit twa_exit(void)
2325{
2326 pci_unregister_driver(&twa_driver);
2327} /* End twa_exit() */
2328
2329module_init(twa_init);
2330module_exit(twa_exit);
2331